HTML跑酷

news2025/3/31 17:25:29

先看效果

 

 

 

再上代码 

<!DOCTYPE html>
<html>
<head>
    <title>火柴人跑酷</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            background: #87CEEB;
        }
        #gameCanvas {
            background: linear-gradient(to bottom, #87CEEB 0%, #87CEEB 50%, #228B22 50%, #228B22 100%);
        }
        #ui {
            position: fixed;
            top: 20px;
            left: 20px;
            font-family: Arial;
            font-size: 24px;
            color: white;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
        }
        #gameOver {
            display: none;
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: rgba(0,0,0,0.8);
            color: white;
            padding: 20px;
            text-align: center;
            border-radius: 10px;
        }
    </style>
</head>
<body>
    <div id="ui">
        得分: <span id="score">0</span>
    </div>
    <div id="gameOver">
        <h2>游戏结束!</h2>
        <p>最终得分: <span id="finalScore">0</span></p>
        <button onclick="restartGame()">重玩</button>
    </div>
    <canvas id="gameCanvas"></canvas>

    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        let canvasWidth = window.innerWidth;
        let canvasHeight = window.innerHeight;
        canvas.width = canvasWidth;
        canvas.height = canvasHeight;

        // 游戏参数
        let gameSpeed = 10;
        let isJumping = false;
        let isGameOver = false;
        let score = 0;
        let gravity = 0.8;
        let jumpForce = -21;
        let groundLevel = canvasHeight * 0.8;

        // 火柴人参数
        let stickman = {
            x: 100,
            y: groundLevel - 60,
            width: 40,
            height: 80,
            velocityY: 0,
            isOnGround: true
        };

        // 障碍物数组
        let obstacles = [];
        let obstacleTypes = [
            { width: 30, height: 50 },
            { width: 50, height: 30 },
            { width: 40, height: 40 }
        ];

        // 游戏循环
        function gameLoop() {
            if (!isGameOver) {
                ctx.clearRect(0, 0, canvasWidth, canvasHeight);
                
                updateStickman();
                updateObstacles();
                checkCollisions();
                drawGround();
                drawStickman();
                drawObstacles();
                updateScore();
                
                requestAnimationFrame(gameLoop);
            }
        }

        function drawStickman() {
            // 绘制火柴人
            ctx.fillStyle = '#000';
            
            // 身体
            ctx.beginPath();
            ctx.moveTo(stickman.x + stickman.width/2, stickman.y);
            ctx.lineTo(stickman.x + stickman.width/2, stickman.y + stickman.height);
            ctx.stroke();
            
            // 头部
            ctx.beginPath();
            ctx.arc(stickman.x + stickman.width/2, stickman.y - 10, 15, 0, Math.PI * 2);
            ctx.stroke();
            
            // 腿
            ctx.beginPath();
            ctx.moveTo(stickman.x + stickman.width/2, stickman.y + stickman.height);
            ctx.lineTo(stickman.x, stickman.y + stickman.height + 30);
            ctx.moveTo(stickman.x + stickman.width/2, stickman.y + stickman.height);
            ctx.lineTo(stickman.x + stickman.width, stickman.y + stickman.height + 30);
            ctx.stroke();
        }

        function updateStickman() {
            // 重力应用
            if (!stickman.isOnGround) {
                stickman.velocityY += gravity;
                stickman.y += stickman.velocityY;
            }

            // 地面检测
            if (stickman.y + stickman.height > groundLevel) {
                stickman.y = groundLevel - stickman.height;
                stickman.velocityY = 0;
                stickman.isOnGround = true;
            }
        }

        function drawGround() {
            ctx.fillStyle = '#228B22';
            ctx.fillRect(0, groundLevel, canvasWidth, canvasHeight - groundLevel);
        }

        function generateObstacle() {
            if (Math.random() < 0.02) {
                let type = obstacleTypes[Math.floor(Math.random() * obstacleTypes.length)];
                obstacles.push({
                    x: canvasWidth,
                    y: groundLevel - type.height,
                    width: type.width,
                    height: type.height,
                    passed: false
                });
            }
        }

        function updateObstacles() {
            generateObstacle();
            
            for (let i = obstacles.length - 1; i >= 0; i--) {
                obstacles[i].x -= gameSpeed;
                
                if (obstacles[i].x + obstacles[i].width < 0) {
                    obstacles.splice(i, 1);
                }
            }
        }

        function drawObstacles() {
            ctx.fillStyle = '#8B4513';
            obstacles.forEach(obstacle => {
                ctx.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height);
            });
        }

        function checkCollisions() {
            obstacles.forEach(obstacle => {
                if (
                    stickman.x < obstacle.x + obstacle.width &&
                    stickman.x + stickman.width > obstacle.x &&
                    stickman.y < obstacle.y + obstacle.height &&
                    stickman.y + stickman.height > obstacle.y
                ) {
                    gameOver();
                }

                if (!obstacle.passed && obstacle.x + obstacle.width < stickman.x) {
                    obstacle.passed = true;
                    score += 10;
                }
            });
        }

        function updateScore() {
            document.getElementById('score').textContent = score;
            gameSpeed += 0.001;
        }

        function gameOver() {
            isGameOver = true;
            document.getElementById('gameOver').style.display = 'block';
            document.getElementById('finalScore').textContent = score;
        }

        function restartGame() {
            isGameOver = false;
            score = 0;
            gameSpeed = 10;
            obstacles = [];
            stickman.y = groundLevel - 60;
            stickman.velocityY = 0;
            document.getElementById('gameOver').style.display = 'none';
            gameLoop();
        }

        // 事件监听
        document.addEventListener('keydown', (e) => {
            if ((e.code === 'Space' || e.code === 'ArrowUp') && stickman.isOnGround) {
                stickman.velocityY = jumpForce;
                stickman.isOnGround = false;
            }
        });

        // 窗口调整
        window.addEventListener('resize', () => {
            canvasWidth = window.innerWidth;
            canvasHeight = window.innerHeight;
            canvas.width = canvasWidth;
            canvas.height = canvasHeight;
            groundLevel = canvasHeight * 0.8;
        });

        // 启动游戏
        gameLoop();
    </script>
</body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2324592.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChemBioServer: 一个在线“药物发现/再利用”的平台

ChemBioServer 是一个提供高级化学化合物过滤、聚类和网络分析的服务器&#xff0c;旨在支持药物发现和药物再利用&#xff08;drug repurposing&#xff09;。它集成了多种工具和网络服务&#xff0c;以便更高效地筛选、分析和可视化化学化合物。 网站地址&#xff1a; https:…

数据结构(4)——带哨兵位循环双向链表

目录 前言 一、带哨兵的循环双向链表是什么 二、链表的实现 2.1规定结构体 2.2创建节点 2.3初始化 2.4打印 2.5检验是否为空 2.6销毁链表 2.7尾插 2.8尾删 2.9头插 2.10头删 2.11寻找特定节点 2.12任意位置插入&#xff08;pos前&#xff09; 2.13删除任意节点 …

【MyBatis】MyBatis 操作数据库(入门)

文章目录 前言一、什么是MyBatis&#xff1f;二、MyBatis入门2.1、准备工作2.1.1 创建工程2.1.2、数据准备 2.2、配置数据库连接字符串2.3、写持久层代码2.4 单元测试 三、MyBatis的基础操作3.1 打印日志3.2、参数传递3.3、增(Insert)3.4、 删(Delete)3.5、改(Update)3.6、查(S…

高速电路中的存储器应用与设计四

5 SRAM介绍及其应用要点 DRAM的性能在很大程度上受到刷新操作的影响&#xff0c;而SRAM则不涉及刷新&#xff0c;因此在相同时钟频率的条件下&#xff0c;SRAM的性能远高于DRAM。 SRAM的缺点是集成度低、容量小、功耗大、价格高。 在应用的场合上&#xff0c;SRAM毫不逊色于…

Vue2 项目将网页内容转换为图片并保存到本地

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

HT81697——30W内置升压单声道D类/AB类音频功放

1 特性 ● 防削顶失真功能(防破音,Anti-Clipping Function,ACF) ● 扩频技术 ● 输出功率 28W (VBAT7.2V, RL4Ω, THDN10%, PVDD 15.5V, fiN 1kHz) 22W (VBAT7.2V,RL4Ω, THDN1%, PVDD 15.5V, fin 1kHz) 16.5W (VBAT3.7V, RL4Ω, THDN10%, PVDD 12V, fiN 1kHz) 12.8W (VBAT…

关于ArcGIS中加载影像数据,符号系统中渲染参数的解析

今天遇到一个很有意思的问题&#xff0c;故记录下来&#xff0c;以作参考和后续的研究。欢迎随时沟通交流。如果表达错误或误导&#xff0c;请各位指正。 正文 当我们拿到一幅成果影像数据的时候&#xff0c;在不同的GIS软件中会有不同效果呈现&#xff0c;但这其实是影像是…

GAMMA数据处理(十)

今天向别人请教了一个问题&#xff0c;刚无意中搜索到了一模一样的问题 不知道这个怎么解决... ok 解决了 有一个GAMMA的命令可转换 但是很奇怪 完全对不上 转换出来的行列号 不知道为啥 再试试 是因为经纬度坐标的小数点位数 de as

基于改进粒子群算法的多目标分布式电源选址定容规划(附带Matlab代码)

通过分析分布式电源对配电网的影响&#xff0c;以有功功率损耗、电压质量及分布式电源总容量为优化目标&#xff0c;基于模糊理论建立了分布式电源在配电网中选址定容的多目标优化模型&#xff0c;并提出了一种改进粒子群算法进行求解。在算例仿真中&#xff0c;基于IEEE-14标准…

SAP 学习笔记 - 系统移行业务 - MALSY(由Excel 移行到SAP 的收费工具)

以前有关移行&#xff0c;也写过一些文章&#xff0c;比如 SAP 学习笔记 - 系统移行业务 - Migration cockpit工具 - 移行Material&#xff08;品目&#xff09;-CSDN博客 SAP 学习笔记 - 系统移行业务 - Migration cockpit工具2 - Lot导入_sap cockpit-CSDN博客 SAP学习笔记…

2025美国网络专线国内服务商推荐

在海外业务竞争加剧的背景下&#xff0c;稳定高效的美国网络专线已成为外贸企业、跨国电商及跨国企业的刚需。面对复杂的国际网络环境和严苛的业务要求&#xff0c;国内服务商Ogcloud凭借其创新的SD-WAN技术架构与全球化网络布局&#xff0c;正成为企业拓展北美市场的优选合作伙…

如何正确地在 Postman 中添加认证 Token?

在 Postman 中设置 token。我们知道 HTTP 是无状态的。token 是保持用户的登录状态或者其他数据的一种机制&#xff0c;从而让用户在不同页面之间保持一致的体验。 在 Postman 中添加认证 token 教程

SpringCould微服务架构之Docker(6)

容器的基本命令&#xff1a; 1. docker exec &#xff1a;进入容器执行命令 2. docker logs: -f 持续查看容器的运行日志 3. docker ps&#xff1a;查看所有运行的容器和状态 案例&#xff1a;创建运行一个容Nginx容器 docker run--name myNginx -p 80:80 -d nginx 命…

Linux|gitlab|二进制快速安装部署gitlab-ce教程

一、 gitlab二进制文件下载地址&#xff1a; 官方网站: gitlab/gitlab-ce - Packages packages.gitlab.com 清华镜像站&#xff1a; Index of /gitlab-ce/yum/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror gitlab分为ce也就是社区版本和ee版本&#xff0c;…

NixVis 开源轻量级 Nginx 日志分析工具

NixVis NixVis 是一款基于 Go 语言开发的、开源轻量级 Nginx 日志分析工具&#xff0c;专为自部署场景设计。它提供直观的数据可视化和全面的统计分析功能&#xff0c;帮助您实时监控网站流量、访问来源和地理分布等关键指标&#xff0c;无需复杂配置即可快速部署使用。 演示…

vscode正则表达式使用

小标题 ^\d.\d.\d\s.*$ ^表示匹配字符串的开头。\d\.\d\.\d表示匹配一到多个数字&#xff0c;接着一个小数点&#xff0c;再接着一到多个数字&#xff0c;然后又一个小数点和一到多个数字&#xff0c;用来匹配类似 “2.1.1” 这样的标题号部分。\s表示匹配一个空格。.*表示匹配…

OpenAI API - Realtime 实时

文章目录 实时 API&#xff08;Beta&#xff09;使用实时API入门示例应用合作伙伴集成 用例通过 WebRTC 连接概述连接详情创建一个临时token发送和接收事件 使用 WebSockets 连接概述连接详情 实时对话Beta实时语音到语音会话会话生命周期事件文本输入和输出音频输入和输出语音…

PE文件(十三)资源表

所谓的资源也就是我们之前学的MFC中的对话框&#xff0c;按钮&#xff0c;编辑框之类的东西。不仅MFC有资源&#xff0c;我们平时熟悉的控制台程序也有资源 当我们平时写一些程序或者木马时&#xff0c;我们通常对其定义一个随机的名称或者路径&#xff0c;然后再向外界进行释…

丝杆升降机行程控制:精准运行的奥秘

丝杆升降机作为机械传动领域的 “得力干将”&#xff0c;在环保设备、工业生产线、建筑施工等众多场景中发挥着关键作用。其能够实现重物的升降、平移等操作&#xff0c;而行程控制对于丝杆升降机而言&#xff0c;就如同给机器设定了行动边界&#xff0c;不仅关乎设备能否精准达…

力扣.旋转矩阵Ⅱ

59. 螺旋矩阵 II - 力扣&#xff08;LeetCode&#xff09; 代码区&#xff1a; class Solution {const int MAX25; public:vector<vector<int>> generateMatrix(int n) {vector<vector<int>> ans;vector<int> hang;int len_nn;int arry[25][25]…