科学教育

搜索
楼主: ZLJ
打印 上一主题 下一主题

王桃桃

[复制链接]

0

主题

1145

帖子

1715

积分

版主

Rank: 7Rank: 7Rank: 7

积分
1715
41#
发表于 2024-7-16 12:01:19 | 只看该作者
ZLJ 发表于 2024-07-16 12:00
很好,还有一个问题,现在的enemies生成的太多了,游 ...


当然可以!你只需要调整敌人生成的概率,就可以减少敌人的生成数量,从而降低游戏难度。在当前的代码中,敌人在 `generateEnemies` 函数中是随机生成的。通过修改概率,可以控制敌人的生成频率。

### 修改后的 JavaScript(script.js):

  1. const canvas = document.getElementById('gameCanvas');
  2. const ctx = canvas.getContext('2d');

  3. canvas.width = 600; // 设置画布宽度
  4. canvas.height = 600; // 设置画布高度

  5. const playerWidth = 50;
  6. const playerHeight = 50;
  7. let playerX = (canvas.width - playerWidth) / 2;
  8. let playerY = canvas.height - playerHeight - 10;
  9. const playerSpeed = 7;

  10. let bullets = [];
  11. let enemies = [];
  12. let score = 0;

  13. // 加载飞机图片
  14. const playerImage = new Image();
  15. playerImage.src = 'player.png';

  16. document.addEventListener('keydown', movePlayer);
  17. document.addEventListener('keydown', shootBullet);

  18. function movePlayer(e) {
  19.     if (e.key === 'ArrowLeft' && playerX > 0) {
  20.         playerX -= playerSpeed;
  21.     }
  22.     if (e.key === 'ArrowRight' && playerX < canvas.width - playerWidth) {
  23.         playerX += playerSpeed;
  24.     }
  25. }

  26. function shootBullet(e) {
  27.     if (e.key === ' ') {
  28.         bullets.push({ x: playerX + playerWidth / 2 - 2.5, y: playerY, speed: 10 });
  29.     }
  30. }

  31. function drawPlayer() {
  32.     const degrees = 45; // 旋转角度
  33.     const radians = degrees * (Math.PI / 180); // 将角度转换为弧度

  34.     ctx.save(); // 保存当前画布状态
  35.     ctx.translate(playerX + playerWidth / 2, playerY + playerHeight / 2); // 将原点移动到图像中心
  36.     ctx.rotate(radians); // 旋转画布
  37.     ctx.drawImage(playerImage, -playerWidth / 2, -playerHeight / 2, playerWidth, playerHeight); // 绘制图像
  38.     ctx.restore(); // 恢复画布到之前保存的状态
  39. }

  40. function drawBullets() {
  41.     ctx.fillStyle = '#ff0';
  42.     bullets.forEach((bullet, index) => {
  43.         bullet.y -= bullet.speed;
  44.         ctx.fillRect(bullet.x, bullet.y, 5, 15);
  45.         if (bullet.y < 0) {
  46.             bullets.splice(index, 1);
  47.         }
  48.     });
  49. }

  50. function drawEnemies() {
  51.     ctx.fillStyle = '#f00';
  52.     enemies.forEach((enemy, index) => {
  53.         enemy.y += enemy.speed;
  54.         ctx.fillRect(enemy.x, enemy.y, enemy.width, enemy.height);
  55.         if (enemy.y > canvas.height) {
  56.             enemies.splice(index, 1);
  57.             gameOver();
  58.         }
  59.     });
  60. }

  61. function generateEnemies() {
  62.     // 调整生成敌人的概率
  63.     if (Math.random() < 0.01) { // 将概率从 0.02 降低到 0.01
  64.         const x = Math.random() * (canvas.width - playerWidth);
  65.         enemies.push({ x: x, y: 0, width: 50, height: 50, speed: 3 });
  66.     }
  67. }

  68. function detectCollisions() {
  69.     bullets.forEach((bullet, bIndex) => {
  70.         enemies.forEach((enemy, eIndex) => {
  71.             if (bullet.x > enemy.x && bullet.x < enemy.x + enemy.width &&
  72.                 bullet.y > enemy.y && bullet.y < enemy.y + enemy.height) {
  73.                 score += 10;
  74.                 bullets.splice(bIndex, 1);
  75.                 enemies.splice(eIndex, 1);
  76.             }
  77.         });
  78.     });

  79.     enemies.forEach(enemy => {
  80.         if (playerX < enemy.x + enemy.width &&
  81.             playerX + playerWidth > enemy.x &&
  82.             playerY < enemy.y + enemy.height &&
  83.             playerY + playerHeight > enemy.y) {
  84.             gameOver();
  85.         }
  86.     });
  87. }

  88. function gameOver() {
  89.     alert(`Game Over! Your score is ${score}`);
  90.     document.location.reload();
  91. }

  92. function update() {
  93.     ctx.clearRect(0, 0, canvas.width, canvas.height);
  94.     drawPlayer();
  95.     drawBullets();
  96.     drawEnemies();
  97.     detectCollisions();
  98.     generateEnemies();
  99.     requestAnimationFrame(update);
  100. }

  101. update();
复制代码


### 解释:
- 在 `generateEnemies` 函数中,我将敌人生成的概率从 `0.02` 降低到 `0.01`,这意味着敌人生成的频率大概减半了。
  1. function generateEnemies() {
  2.     if (Math.random() < 0.01) {
  3.         const x = Math.random() * (canvas.width - playerWidth);
  4.         enemies.push({ x: x, y: 0, width: 50, height: 50, speed: 3 });
  5.     }
  6. }
复制代码


这样,游戏的难度会降低,因为敌人生成的速度变慢了。如果仍然觉得游戏难度较高,你可以进一步降低这个概率值,比如改为 `0.005` 或其他更小的值。

如果还有其他问题或需要更多帮助,请随时告诉我!
回复 支持 反对

使用道具 举报

29

主题

107

帖子

348

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
348
42#
 楼主| 发表于 2024-7-16 12:11:26 | 只看该作者
在修改了飞机的图标的基础上,我还要修改那个enemy的图标,但我同样的修改语句写了一遍后发现没有改enemy,还是修改了飞机
回复 支持 反对

使用道具 举报

0

主题

1145

帖子

1715

积分

版主

Rank: 7Rank: 7Rank: 7

积分
1715
43#
发表于 2024-7-16 12:11:53 | 只看该作者
ZLJ 发表于 2024-07-16 12:11
在修改了飞机的图标的基础上,我还要修改那个enemy的 ...


明白了!如果你想要修改敌人的图标,你需要像处理玩家飞机一样,为敌人也加载一个图像,并在 `drawEnemies` 函数中使用 `drawImage` 方法来绘制敌人。

以下是更新后的代码,包括如何为敌人加载和绘制图像:

### 更新后的 JavaScript(script.js):
  1. const canvas = document.getElementById('gameCanvas');
  2. const ctx = canvas.getContext('2d');

  3. canvas.width = 600;
  4. canvas.height = 600;

  5. const playerWidth = 50;
  6. const playerHeight = 50;
  7. let playerX = (canvas.width - playerWidth) / 2;
  8. let playerY = canvas.height - playerHeight - 10;
  9. const playerSpeed = 7;

  10. let bullets = [];
  11. let enemies = [];
  12. let score = 0;

  13. // 加载飞机图片
  14. const playerImage = new Image();
  15. playerImage.src = 'player.png';

  16. // 加载敌人图片
  17. const enemyImage = new Image();
  18. enemyImage.src = 'enemy.png';

  19. document.addEventListener('keydown', movePlayer);
  20. document.addEventListener('keydown', shootBullet);

  21. function movePlayer(e) {
  22.     if (e.key === 'ArrowLeft' && playerX > 0) {
  23.         playerX -= playerSpeed;
  24.     }
  25.     if (e.key === 'ArrowRight' && playerX < canvas.width - playerWidth) {
  26.         playerX += playerSpeed;
  27.     }
  28. }

  29. function shootBullet(e) {
  30.     if (e.key === ' ') {
  31.         bullets.push({ x: playerX + playerWidth / 2 - 2.5, y: playerY, speed: 10 });
  32.     }
  33. }

  34. function drawPlayer() {
  35.     const degrees = 0; // 旋转角度
  36.     const radians = degrees * (Math.PI / 180); // 将角度转换为弧度
  37.    
  38.     ctx.save(); // 保存当前画布状态
  39.     ctx.translate(playerX + playerWidth / 2, playerY + playerHeight / 2); // 将原点移动到图像中心
  40.     ctx.rotate(radians); // 旋转画布
  41.     ctx.drawImage(playerImage, -playerWidth / 2, -playerHeight / 2, playerWidth, playerHeight); // 绘制图像
  42.     ctx.restore(); // 恢复画布到之前保存的状态
  43. }

  44. function drawBullets() {
  45.     ctx.fillStyle = '#ff0';
  46.     bullets.forEach((bullet, index) => {
  47.         bullet.y -= bullet.speed;
  48.         ctx.fillRect(bullet.x, bullet.y, 5, 15);
  49.         if (bullet.y < 0) {
  50.             bullets.splice(index, 1);
  51.         }
  52.     });
  53. }

  54. function drawEnemies() {
  55.     enemies.forEach((enemy, index) => {
  56.         enemy.y += enemy.speed;
  57.         ctx.drawImage(enemyImage, enemy.x, enemy.y, enemy.width, enemy.height);
  58.         if (enemy.y > canvas.height) {
  59.             enemies.splice(index, 1);
  60.             gameOver();
  61.         }
  62.     });
  63. }

  64. function generateEnemies() {
  65.     if (Math.random() < 0.01) { // 敌人生成概率调整
  66.         const x = Math.random() * (canvas.width - 50); // 假设敌人宽度为50
  67.         enemies.push({ x: x, y: 0, width: 50, height: 50, speed: 3 });
  68.     }
  69. }

  70. function detectCollisions() {
  71.     bullets.forEach((bullet, bIndex) => {
  72.         enemies.forEach((enemy, eIndex) => {
  73.             if (bullet.x > enemy.x && bullet.x < enemy.x + enemy.width &&
  74.                 bullet.y > enemy.y && bullet.y < enemy.y + enemy.height) {
  75.                 score += 10;
  76.                 bullets.splice(bIndex, 1);
  77.                 enemies.splice(eIndex, 1);
  78.             }
  79.         });
  80.     });

  81.     enemies.forEach(enemy => {
  82.         if (playerX < enemy.x + enemy.width &&
  83.             playerX + playerWidth > enemy.x &&
  84.             playerY < enemy.y + enemy.height &&
  85.             playerY + playerHeight > enemy.y) {
  86.             gameOver();
  87.         }
  88.     });
  89. }

  90. function gameOver() {
  91.     alert(`Game Over! Your score is ${score}`);
  92.     document.location.reload();
  93. }

  94. function update() {
  95.     ctx.clearRect(0, 0, canvas.width, canvas.height);
  96.     drawPlayer();
  97.     drawBullets();
  98.     drawEnemies();
  99.     detectCollisions();
  100.     generateEnemies();
  101.     requestAnimationFrame(update);
  102. }

  103. update();
复制代码


### 解释:
1. **加载敌人图片**:通过 `new Image()` 创建一个新的图片对象,并将 `src` 属性设置为敌人图片路径。
  1. const enemyImage = new Image();
  2. enemyImage.src = 'enemy.png';
复制代码


2. **使用 `drawImage` 方法绘制敌人**:在 `drawEnemies` 函数中,替换原来的填充矩形的方法,改用 `drawImage` 方法来绘制敌人图像。
  1. function drawEnemies() {
  2.     enemies.forEach((enemy, index) => {
  3.         enemy.y += enemy.speed;
  4.         ctx.drawImage(enemyImage, enemy.x, enemy.y, enemy.width, enemy.height);
  5.         if (enemy.y > canvas.height) {
  6.             enemies.splice(index, 1);
  7.             gameOver();
  8.         }
  9.     });
  10. }
复制代码


确保你的 `enemy.png` 图片文件存在于你的项目目录中,并且路径正确。这样,你的敌人就会显示为图片,而不是原来的方块。

如果你还有其他问题或需要进一步帮助,请随时告诉我!
回复 支持 反对

使用道具 举报

29

主题

107

帖子

348

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
348
44#
 楼主| 发表于 2024-7-16 12:16:39 | 只看该作者
好的谢谢,修改成功了,如果要修改画布的外观,用一张背景图片来铺画布,怎么办?
回复 支持 反对

使用道具 举报

29

主题

107

帖子

348

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
348
45#
 楼主| 发表于 2024-7-16 19:35:42 | 只看该作者
你好,贪吃蛇里面这句代码是什么意思:
function collision(newHead, array) {
    for (let i = 0; i < array.length; i++) {
        if (newHead.x === array[i].x && newHead.y === array[i].y) {
            return true;
        }
    }
    return false;
}
回复 支持 反对

使用道具 举报

29

主题

107

帖子

348

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
348
46#
 楼主| 发表于 2024-7-16 19:37:19 | 只看该作者

你好,贪吃蛇里面这句代码是什么意思:@ai
function collision(newHead, array) {
    for (let i = 0; i < array.length; i++) {
        if (newHead.x === array[i].x && newHead.y === array[i].y) {
            return true;
        }
    }
    return false;
}
回复 支持 反对

使用道具 举报

0

主题

1145

帖子

1715

积分

版主

Rank: 7Rank: 7Rank: 7

积分
1715
47#
发表于 2024-7-16 19:37:32 | 只看该作者
ZLJ 发表于 2024-07-16 19:37
你好,贪吃蛇里面这句代码是什么意思:@ai
function  ...


你好呀!我很高兴可以帮你解答这个问题。我们先来逐句理解这段代码。

这是一段用于检查贪吃蛇游戏中蛇是否撞到自己身体的代码哦。我们一起来看看每一部分是什么意思吧:

1. **函数定义**:
  
  1. function collision(newHead, array) {
复制代码

   这一行定义了一个名为`collision`的函数。这个函数有两个参数:`newHead`和`array`。
   - `newHead`:表示蛇移动后新头部的位置,通常是一个包含`x`和`y`坐标的对象。
   - `array`:表示蛇身体的所有部分,通常是一个数组,这个数组中的每个元素也是一个包含`x`和`y`坐标的对象。

2. **循环遍历身体数组**:
  
  1. for (let i = 0; i < array.length; i++) {
复制代码

   这一行是一个`for`循环,它会从数组`array`的第一个元素开始,依次访问每一个元素,直到访问完最后一个元素。

3. **检查新头部是否与身体重叠**:
  
  1. if (newHead.x === array[i].x && newHead.y === array[i].y) {
  2.        return true;
  3.    }
复制代码

   在循环的每一步,我们使用`if`条件来检查新头部的`x`坐标和`y`坐标是否与身体某一部分的`x`坐标和`y`坐标相同。
   - 如果相同,意味着新头部撞到了蛇的身体,那么就返回`true`,表示发生了碰撞。
   
4. **循环结束后返回**:
  
  1. return false;
复制代码

   如果循环结束后,没有发现任何碰撞,那么就返回`false`,表示没有发生碰撞。

总结一下,如果函数`collision`检测到新头部的位置与蛇身体的任何一部分重叠,就返回`true`;如果没有重叠,就返回`false`。

打个比方,这就像你在检查一辆车(新头部)是否撞到停车场里已经停好的其他车(蛇的身体)。你需要一个一个地检查,看有没有重叠的位置。如果有重叠,就是撞了,返回`true`;如果没有,就没撞,返回`false`。

希望这个解释对你有帮助哦!如果还有其他问题,尽管问吧!????
回复 支持 反对

使用道具 举报

29

主题

107

帖子

348

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
348
48#
 楼主| 发表于 2024-7-16 19:40:03 | 只看该作者
好的,那贪吃蛇游戏里面哪部分代码是关于检测贪吃蛇吃到食物的
回复 支持 反对

使用道具 举报

29

主题

107

帖子

348

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
348
49#
 楼主| 发表于 2024-7-16 19:41:39 | 只看该作者

好的,那贪吃蛇游戏里面哪部分代码是关于检测贪吃蛇吃到食物的@AI
回复 支持 反对

使用道具 举报

0

主题

1145

帖子

1715

积分

版主

Rank: 7Rank: 7Rank: 7

积分
1715
50#
发表于 2024-7-16 19:41:57 | 只看该作者
ZLJ 发表于 2024-07-16 19:41
好的,那贪吃蛇游戏里面哪部分代码是关于检测贪吃蛇吃 ...


你好呀,小朋友!

贪吃蛇游戏里面,检测贪吃蛇是否吃到食物是一件很重要的事情。想象一下,贪吃蛇在“田野”里四处游动,而食物则是一些随机出现的“果实”。当贪吃蛇的头碰到这些果实时,它就“吃”到了。

其实,这背后有一个简单的小逻辑。我们要不断检查贪吃蛇头的位置和食物的位置是不是一样的。那么,让我用简单的代码来说明吧!

假设用JavaScript和HTML来写这个游戏:

1. 贪吃蛇的头部位置:
  1. let snakeHead = { x: 100, y: 100 };  // 贪吃蛇头部的初始位置
复制代码


2. 食物的位置:
  1. let food = { x: 150, y: 150 };  // 食物的初始位置
复制代码


3. 检测贪吃蛇是否吃到食物的代码部分会像这样:
  1. function checkIfEatFood() {
  2.     if (snakeHead.x === food.x && snakeHead.y === food.y) {
  3.         console.log("Yummy! Snake eats the food!");
  4.         // 然后你可以让食物出现在另一个随机位置
  5.         food.x = Math.floor(Math.random() * canvas.width);
  6.         food.y = Math.floor(Math.random() * canvas.height);
  7.         
  8.         // 还可以让贪吃蛇变长,因为它吃了食物
  9.         // 这个加长的逻辑你可以自己实现
  10.         
  11.         // 记得更新分数!比如:
  12.         // score += 1;
  13.     }
  14. }

  15. // 在主循环中不断调用这个函数
  16. function gameLoop() {
  17.     // ...其他代码,例如贪吃蛇移动、绘制等
  18.    
  19.     checkIfEatFood();
  20.    
  21.     requestAnimationFrame(gameLoop);  // 继续游戏循环
  22. }
复制代码


那这样,我们每次在主循环里都会检查贪吃蛇的头是不是碰到了食物的位置。如果是,贪吃蛇就吃到了食物,可以加分、让贪吃蛇变长、并且在新的位置生成一个新的食物。

希望这样讲解你能明白!如果还有什么不明白的地方,尽管问我吧!????
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表