Administrator
发布于 2024-11-14 / 4 阅读
0
0

模仿恐龙快跑


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>恐龙快跑</title>
    <link rel="stylesheet" href="index.css">
</head>
<body>
    <h1>恐龙快跑</h1>
    <div id="instruction">按空格键开始游戏和跳跃</div>
    <div id="controls">
        <button id="startBtn">开始游戏</button>
        <button id="pauseBtn" disabled>暂停</button>
    </div>
    <div id="score">得分: <span id="scoreValue">0</span></div>
    <div id="highScore">最高分: <span id="highScoreValue">0</span></div>
    <div id="time">时间: <span id="timeValue">0</span>秒</div>
    <div id="game">
        <div id="dino"></div>
    </div>
    <script src="index.js"></script>
</body>
</html>
   /* 页面整体布局样式 */
   /*
   CSS 属性 font-family 允许你通过给定一个有先后顺序的
   由字体名或者字体族名组成的列表来为选定的元素设置字体。
   */
   body {
    display: flex;
    flex-direction: column;
    align-items: center;
    background:  #023b5098 0%;
    font-family: system-ui;
    color: #fff;
    min-height: 100vh;
    margin: 0;
    padding: 20px;
}

/* 标题样式 */
h1 {
    font-size: 48px;
    margin-bottom: 30px;
    /* 文字渐变效果 */
    /*inear-gradient() CSS 函数
    创建一个由两种或多种颜色沿一条直线进行线性过渡的图像,
    其结果是 <gradient> 数据类型的对象,
    此对象是一种特殊的 <image> 数据类型
    */
    background: -webkit-linear-gradient(#fff, #694343af);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
}

/* 游戏主容器样式 */
#game {
    width: 800px;
    height: 300px;
    border-radius: 15px;
    position: relative;
    overflow: hidden;
    /*加个阴影有边界*/
    box-shadow: 0 8px 32px rgba(0,0,0,0.3);
}

/* 恐龙角色样式 */
#dino {
    width: 50px;
    height: 50px;
    /* 绿色渐变背景 */
    background-image: url("dino.png");
    background-size: cover;
    position: absolute;
    bottom: 0;
    left: 50px;
    border-radius: 8px;
    /* 平滑跳跃动画 */
    transition: bottom 0.5s cubic-bezier(0.4, 0, 0.2, 1);
    box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}

/* 地面障碍物样式 */
.ground-obstacle {
    width: 30px;
    height: 50px;
    /* 红色渐变背景 */
    background-image:url("tree.png");
    background-size:cover;
    position: absolute;
    bottom: 0;
    right: 0;
    border-radius: 8px;
    box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}

/* 空中障碍物样式 */
.air-obstacle {
    width: 40px;
    height: 40px;
    background-image:url("brid.png");
    background-size:cover ;
    position: absolute;
    bottom: 180px;
    right: 0;
    border-radius: 50%;
    box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}

/* 控制按钮容器 */
#controls {
    margin: 30px 0;
}

/* 按钮样式 */
#controls button {
    padding: 12px 30px;
    font-size: 18px;
    border: none;
    border-radius: 25px;
    margin: 0 15px;
    cursor: pointer;
    /* 渐变背景 */
    background: linear-gradient(45deg, #000000, #ffffff);
    color: white;
    transition: all 0.3s ease;
    box-shadow: 0 4px 15px rgba(0,0,0,0.2);
    font-weight: bold;
    text-transform: uppercase;
    letter-spacing: 1px;
}

/* 禁用按钮样式 */
#controls button:disabled {
    background: linear-gradient(45deg, #9e9e9e, #bdbdbd);
    cursor: not-allowed;
    box-shadow: none;
}

/* 按钮悬停效果 */
#controls button:hover:not(:disabled) {
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(0,0,0,0.3);
}

/* 分数和时间显示样式 */
#score, #time, #highScore {
    margin: 20px 0;
    font-size: 32px;
    font-weight: bold;
    color: #fff;
    background: rgba(255,255,255,0.1);
    padding: 15px 40px;
    border-radius: 25px;
    backdrop-filter: blur(5px);
}

/* 游戏说明文字样式 */
#instruction {
    font-size: 20px;
    color: rgba(255,255,255,0.9);
    margin-bottom: 25px;
    /* 呼吸动画效果 */
    animation: pulse 2s infinite;
    background: rgba(255,255,255,0.1);
    padding: 12px 30px;
    border-radius: 20px;
    backdrop-filter: blur(5px);
}

/* 呼吸动画关键帧 */
/* animation6
*/
@keyframes pulse {
    0% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.7; transform: scale(0.98); }
    100% { opacity: 1; transform: scale(1); }
}
 // 获取DOM元素,全写成const
 const dino = document.getElementById('dino');
 const game = document.getElementById('game');
 const startBtn = document.getElementById('startBtn');
 const pauseBtn = document.getElementById('pauseBtn');
 const scoreValue = document.getElementById('scoreValue');
 const highScoreValue = document.getElementById('highScoreValue');
 const timeValue = document.getElementById('timeValue');
 const instruction = document.getElementById('instruction');
 const images = [
    'url(run_left.png)',
    'url(run_right.png)',
  ];
 const righrPostion=800;   //游戏区域最右侧
 // 初始化游戏状态变量
 let isJumping = false;    // 是否正在跳跃
 let gameOver = false;     // 游戏是否结束
 let gamePaused = true;    // 游戏是否暂停
 let obstacleInterval;     // 生成障碍物的定时器
 let timeInterval;         // 计时器
 let score = 0;            // 当前游戏得分
 let highScore = 0;        // 最高分,初始为0
 let gameTime = 0;         // 游戏时长(秒)
 let startTime = 0;        // 游戏开始时间
 let pauseStartTime = 0;   // 暂停开始时间
 let totalPausedTime = 0;  // 总暂停时间
 let activeObstacles = []; // 存储当前活动的障碍物及其移动定时器
 let currentImageid=0;     // 当前显示的小恐龙图片id

 // 初始化显示最高分为0
 highScoreValue.textContent = '0';

/**
 *  小恐龙跑步的图片切换
 */
function changeBackground() {
    document.getElementById('dino').style.backgroundImage=images[currentImageid];
    currentImageid== (currentImageid+1) % images.length;
  }
 /**
  * 跳跃功能实现
  * 通过CSS transition实现平滑的跳跃动画
  * 跳跃高度为180px,持续时间0.5秒
  * setInterval(): 间隔指定的毫秒数不停地执行指定的代码,定时器
    clearInterval(): 用于停止 setInterval() 方法执行的函数代码
    定时器可以当作unity的update来使用,定时的控制游戏场景
  */
 function jump() {
     // 检查是否可以跳跃(未在跳跃(在地面)中且游戏进行中)
     if (!isJumping && !gameOver && !gamePaused) {
         isJumping = true;
         // 设置恐龙跳跃高度
         dino.style.bottom = '180px';  // 上升阶段
         
         // 跳跃后落地
         setTimeout(() => {
             dino.style.bottom = '0px';  // 下落阶段
             // 落地后重置跳跃状态
             setTimeout(() => {
                 isJumping = false;  // 重置跳跃状态,允许下次跳跃
             }, 500);
         }, 500);
     }
 }

 /**
  * 创建并移动障碍物
  * 随机生成三种不同类型的障碍物
  */
 function createObstacle() {
     // 检查游戏状态
     if (!gameOver && !gamePaused) {
         // 创建障碍物DOM元素
         const obstacle = document.createElement('div');
         
         // 随机选择障碍物类型
         const obstacleType = Math.floor(Math.random() * 2);
         switch(obstacleType) {
             case 0: // 地面障碍物
                 obstacle.classList.add('ground-obstacle');
                 break;
             case 1: // 空中障碍物
                 obstacle.classList.add('air-obstacle');
                 break;
         }
         
         game.appendChild(obstacle);

         // 初始化障碍物位置和状态
         let position =righrPostion;        // 初始位置(游戏区域最右侧)
         let scored = false;        // 是否已计分标记
         let lastTime = Date.now(); // 上次更新时间
         
         // 设置障碍物移动定时器
         let moveInterval = setInterval(() => {
             // 暂停检查
             if (gamePaused) {
                 lastTime = Date.now(); // 更新上次时间
                 //这里同文档里一样不能够直接+1,而是用上次的时间差来计算
                 return;
             }
             
             const currentTime = Date.now();
             const deltaTime = currentTime - lastTime;
             lastTime = currentTime;
             
             // 移出屏幕检查
             if (position < -30) {
                 clearInterval(moveInterval);
                 if (game.contains(obstacle)) {
                     game.removeChild(obstacle);
                 }
                 // 从活动障碍物数组中移除
                 const index = activeObstacles.findIndex(item => item.obstacle === obstacle);
                 if (index !== -1) {
                     activeObstacles.splice(index, 1);
                 }
             } else {
                 // 碰撞检测
                 const dinoRect = dino.getBoundingClientRect();
                 const obstacleRect = obstacle.getBoundingClientRect();
                 
                 // 检查矩形是否重叠
                 if (dinoRect.right > obstacleRect.left && 
                     dinoRect.left < obstacleRect.right && 
                     dinoRect.bottom > obstacleRect.top && 
                     dinoRect.top < obstacleRect.bottom) {
                     // 发生碰撞,游戏结束
                     clearInterval(moveInterval);
                     gameOver = true;
                     // 游戏结束时更新最高分
                     if (score > highScore) {
                         highScore = score;
                         highScoreValue.textContent = highScore;
                     }
                     alert(`游戏结束!\n最终得分: ${score}\n最高分: ${highScore}\n坚持时间: ${gameTime}秒`);
                     resetGame();
                 } else if (position < 50 && !scored) {
                     // 通过障碍物,得分加1
                     scored = true;
                     score++;
                     scoreValue.textContent = score;
                 }
             }
             // 更新障碍物位置
             position -= (4 * deltaTime / 20);  // 根据时间差调整移动距离
             obstacle.style.right = (800 - position) + 'px';
         }, 20);

         // 将障碍物和其移动定时器添加到活动障碍物数组
         activeObstacles.push({
             obstacle: obstacle,
             interval: moveInterval
         });
     }
 }

 /**
  * 开始游戏
  * 初始化游戏状态,开始生成障碍物和计时
  */
 function startGame() {
     if (gamePaused) {
         if (pauseStartTime) {
             totalPausedTime += Date.now() - pauseStartTime;
         } else {
             startTime = Date.now();
             totalPausedTime = 0;
             score = 0;
             gameTime = 0;
             scoreValue.textContent = '0';
             timeValue.textContent = '0';
         }
     }
     
     gamePaused = false;
     gameOver = false;
     startBtn.disabled = true;
     pauseBtn.disabled = false;
     instruction.style.display = 'none';
     
     // 开始生成障碍物
     obstacleInterval = setInterval(createObstacle, 2500);
     
     // 开始计时
     timeInterval = setInterval(() => {
         if (!gamePaused) {
             gameTime = Math.floor((Date.now() - startTime - totalPausedTime) / 1000);
             timeValue.textContent = gameTime;
         }
     }, 100);
 }

 /**
  * 暂停游戏
  * 暂停所有游戏进程
  */
 function pauseGame() {
     gamePaused = true;
     pauseStartTime = Date.now();
     startBtn.disabled = false;
     pauseBtn.disabled = true;
     clearInterval(obstacleInterval);
     instruction.style.display = 'block';
 }

 /**
  * 重置游戏
  * 清除所有游戏状态和元素
  */
 function resetGame() {
     gamePaused = true;
     startBtn.disabled = false;
     pauseBtn.disabled = true;
     clearInterval(obstacleInterval);
     clearInterval(timeInterval);
     
     // 清除所有活动障碍物及其定时器
     activeObstacles.forEach(item => {
         clearInterval(item.interval);
         if (game.contains(item.obstacle)) {
             game.removeChild(item.obstacle);
         }
     });
     activeObstacles = [];
     
     score = 0;
     gameTime = 0;
     startTime = 0;
     pauseStartTime = 0;
     totalPausedTime = 0;
     scoreValue.textContent = '0';
     timeValue.textContent = '0';
     instruction.style.display = 'block';
 }

 // 添加按钮点击事件监听
 startBtn.addEventListener('click', startGame);
 pauseBtn.addEventListener('click', pauseGame);
 
 //切换恐龙跑步图片
 setInterval(changeBackground, 100);
 // 添加键盘事件监听
 document.addEventListener('keydown', (event) => {
     // 空格键跳跃和开始游戏
     if (event.code === 'Space') {
         event.preventDefault(); // 防止页面滚动
         if (gamePaused) {
             startGame();
         }
         jump();
     }
     // ESC键暂停
     if (event.code === 'Escape') {
         if (!gamePaused) {
             pauseGame();
         }
     }
 });
  /*
        游戏核心逻辑说明:

        1. 游戏状态管理:
           - 使用多个状态变量控制游戏流程
           - gamePaused: 暂停状态
           - gameOver: 结束状态
           - isJumping: 跳跃状态
           - score: 当前游戏得分
           - highScore: 最高分(初始为0,仅在游戏结束时更新)
           - gameTime: 游戏时长

        2. 跳跃实现:
           - 使用CSS transition实现平滑动画
           - 跳跃高度180px,总持续时间1秒
           - 上升和下落各0.5秒
           - 防止重复跳跃的状态控制

        3. 障碍物系统:
           - 随机生成三种不同类型的障碍物
           - 地面障碍物(红色)
           - 空中障碍物(蓝色)
           - 定时生成(每2.5秒)
           - 匀速移动(4px/20ms)
           - 超出屏幕自动清除
           - 碰撞检测和计分
        4. 计分规则:
           - 成功避开障碍物得1分
           - 使用scored标记防止重复计分
           - 记录游戏持续时间
           - 最高分仅在游戏结束时更新,不会实时更新
           - 最高分初始显示为0,不从localStorage读取

        5. 用户交互:
           - 空格键: 开始/跳跃
           - ESC键: 暂停
           - 按钮控制
           - 游戏状态提示
        */
 游戏核心逻辑说明:

        1. 游戏状态管理:
           - 使用多个状态变量控制游戏流程
           - gamePaused: 暂停状态
           - gameOver: 结束状态
           - isJumping: 跳跃状态
           - score: 当前游戏得分
           - highScore: 最高分(初始为0,仅在游戏结束时更新)
           - gameTime: 游戏时长

        2. 跳跃实现:
           - 使用CSS transition实现平滑动画
           - 跳跃高度180px,总持续时间1秒
           - 上升和下落各0.5秒
           - 防止重复跳跃的状态控制

        3. 障碍物系统:
           - 随机生成三种不同类型的障碍物
           - 地面障碍物(红色)
           - 空中障碍物(蓝色)
           - 定时生成(每2.5秒)
           - 匀速移动(4px/20ms)
           - 超出屏幕自动清除
           - 碰撞检测和计分
        4. 计分规则:
           - 成功避开障碍物得1分
           - 使用scored标记防止重复计分
           - 记录游戏持续时间
           - 最高分仅在游戏结束时更新,不会实时更新
           - 最高分初始显示为0,不从localStorage读取

        5. 用户交互:
           - 空格键: 开始/跳跃
           - ESC键: 暂停
           - 按钮控制
           - 游戏状态提示


评论