Weblab Day 2

W1: Snake Game

获取资源

回到昨天的仓库,执行以下代码来切换我们需要的内容:

git reset --hard
git fetch
git checkout w1-starter

你应该会看到一个 game.js,一个 index.html,一个 style.css

这节课中不需要修改 CSS。

启动

我们将使用 setInterval() 来制造循环。

setInterval(func, delay) 可以在延时之后调用函数,并不断重复这个过程。

const SNAKE_SPEED = 5;
setInterval(main, 1000 / SNAKE_SPEED);

注意 delay 以毫秒为单位。

为了将 game.js 连接到 index.html,我们需要使用 <script> 标签:

<script src="game.js" defer></script>

生成🐍

切换到 w1-step1 分支,发现我们多了一个 snake.js,用于编写蛇的逻辑。

连接文件

<head> 中添加:

<script src="snake.js" defer></script>

生成身体

通过预制的网格,我们可以用二维坐标表示网页中的一块区域。

那么蛇的身体,就可以用一个坐标队列表示。

初始的蛇:

const snakeBody = [
    {x: 11, y: 11},
    {x: 11, y: 10},
    {x: 11, y: 9},
];

移动

我们可以使用 JS 的 pop()unshift() 来完成队尾弹出和队首插入。

值得注意的是,pop() 的返回值是弹出的元素,unshift() 的返回值是队列长度。

const updateSnake = () => {
  snakeBody.pop();
  const npnt = {...snakeBody[0]};
  npnt.y++;
  snakeBody.unshift(npnt);
};

game.jsUpdate 中调用即可。

响应操作

切换到 w1-step2 分支。多了一个 input.js,用于我们写键盘输入。和前面一样连接到 index.html 中。

创建键盘监听

先来学习一下事件监听:EventTarget: addEventListener() method - Web APIs | MDN (mozilla.org)

然后再学习一下键盘监听:KeyboardEvent: key property - Web APIs | MDN (mozilla.org)

配合 switch 语句,搓一下方向判断,放在 input.js 中:

const snakeDirection = [
  { x: 0, y: 1 },
  { x: 0, y: -1 },
  { x: -1, y: 0 },
  { x: 1, y: 0 },
];

let directionIndex = 0;

window.addEventListener("keydown", (event) => {
  switch (event.key) {
    case "ArrowDown":
      directionIndex = 0;
      break;
    case "ArrowUp":
      directionIndex = 1;
      break;
    case "ArrowLeft":
      directionIndex = 2;
      break;
    case "ArrowRight":
      directionIndex = 3;
      break;
    default:
      break;
  }
});

const getInputDirection = () => {
  return snakeDirection[directionIndex];
};

判断折叠

众所周知,🐍的身体不能折叠,所以我们要写个逻辑判断有没有撞到自己,即键盘输入和上一个时刻相反的情况。

修改一下即可:

window.addEventListener("keydown", (event) => {
  let newIndex = directionIndex;
  switch (event.key) {
    case "ArrowDown":
      newIndex = 0;
      break;
    case "ArrowUp":
      newIndex = 1;
      break;
    case "ArrowLeft":
      newIndex = 2;
      break;
    case "ArrowRight":
      newIndex = 3;
      break;
    default:
      break;
  }
  diff = newIndex ^ directionIndex
  if (diff != 0 && diff != 1) directionIndex = newIndex;
});

生成🍎

切换到 w1-step3。多了 food.jssnakeUtils.js。建议先阅读 snakeUtils.js 了解可用的函数。

可以发现 onSnake() 可以判定一个位置是否和蛇身重合,getNewFoodPosition() 可以获得一个随机位置。

food.js 中添加代码,如果🍎和🐍重合则让🐍变长,同时生成一个新的🍎。

update() 中添加 updateFood() 即可。

判定结束

w1-step4。在 snakeUtils.js 中增加了新的函数,判定蛇有没有出界、有没有和自身相撞。

game.js 中,我们需要判定游戏结束、设定游戏结束的提示、让蛇的位置停止更新。

这里需要用到 alert() 函数,用于发送消息弹窗;以及 clearInterval() 函数,用于取消循环。

额外挑战:重置游戏

先把重置按键绑定为 rinput.js 的其他部分和上文一样。其他文件和 w1-step4 一样。

let isResetGame = true;

window.addEventListener("keydown", (event) => {
    if(event.key == "r") isResetGame = true;
});

然后在 game.js 中重新整理函数。原来的 main() 只负责游戏过程,现在我们需要另一个函数掌控它的开关。

所以我把原来的 main() 更名为 gamerun(),同时用 resetGame() 来完成重启一次的任务。

(这里偷懒,把 snakeBody 定义为变量了,这样直接赋值就能重置🐍)

const SNAKE_SPEED = 5;

const gameBoard = document.getElementById("game-board");

let isGameOver = true;

let gameid = 0;

const main = () => {
  if (isResetGame === true) resetGame();
};

const resetGame = () => {
  if (!isGameOver) clearInterval(gameid);
  isResetGame = false;
  isGameOver = false;
  snakeBody = [
    { x: 11, y: 11 },
    { x: 11, y: 10 },
    { x: 11, y: 9 },
  ];
  directionIndex = 0;
  gameid = setInterval(gamerun, 1000 / SNAKE_SPEED);
};

const gamerun = () => {
  update();
  draw();
  if (isGameOver) {
    alert("Game Over!");
    clearInterval(gameid);
  }
};

const update = () => {
  console.log("Updating");
  updateSnake();
  updateFood();
  // TODO 4.2: Update Game State
  isGameOver = checkGameOver();
};

const draw = () => {
  gameBoard.innerHTML = "";
  drawSnake(gameBoard);
  drawFood(gameBoard);
};

const checkGameOver = () => {
  return snakeOutOfBounds() || snakeIntersectSelf();
};

setInterval(main, 100);

参考答案是 w1-challenge

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇