使用canvas实现贪吃蛇

使用canvas实现贪吃蛇



前言

本文章讲述如何使用vue+canvas实现经典游戏贪吃蛇。体验游戏贪吃蛇 - AO源码仅供学习参考。你需要知道vue框架element ui帮助你快速快速开发。


一、组件版本&项目结构

查看详细


二、代码讲解

以下讲解自己写的代码,不会讲解canvas具体怎么实现的。也许可以参考以前的文章使用canvas 的资料

1. 移动snake

1.1 代码

//监听键盘事件
document.onkeydown = this.keyDown;
/**
 * 方向键控制元素移动函数
 * @param event 事件
 */
keyDown(event) {
  if (!this.checkActionStartStatus()) return;
  let keyCodes = [37, 39, 38, 40];
  if (keyCodes.indexOf(event.keyCode) < 0) return;
  this.keyCode = event.keyCode;
}
/**
 * 移动
 */
moveSnake() {
  //清除末尾
  let tail = this.snakeBodyArr[this.snakeBodyArr.length - 1];
  this.ctx.clearRect(tail.x, tail.y, tail.w, tail.h);
  //获取图片
  this.snakeBodyArr[0].keyCode = this.keyCode;
  //每一个方块都赋值前一个,实现移动一步
  for (let index = this.snakeBodyArr.length - 1; index > 0; index--) {
    this.snakeBodyArr[index].x = this.snakeBodyArr[index - 1].x;
    this.snakeBodyArr[index].y = this.snakeBodyArr[index - 1].y;
    this.snakeBodyArr[index].keyCode = this.snakeBodyArr[index - 1].keyCode;
  }
  switch (this.keyCode) {  // 获取当前按下键盘键的编码
    case 37 :  // 按下左箭头键,向左移动
      this.left();
      break;
    case 39 :  // 按下右箭头键,向右移动
      this.right();
      break;
    case 38 :  // 按下上箭头键,向上移动
      this.up();
      break;
    case 40 :  // 按下下箭头键,向下移动
      this.down();
      break;
    default:
      return;
  }
  this.drawSnake();
}
/**
 * 往右
 */
right() {
  //是否超出右边界限
  if (this.snakeBodyArr[0].x + this.snakeBodyArr[0].w >= this.canvas.width) {
    if (!this.touchSnakeWall) this.gameOver();
    this.snakeBodyArr[0].x = 0;
  } else {
    this.snakeBodyArr[0].x += this.snakeBodyArr[0].w;
  }
},
/**
 * 往左
 */
left() {
  //超出左边界限
  if (this.snakeBodyArr[0].x <= 0) {
    if (!this.touchSnakeWall) this.gameOver();
    this.snakeBodyArr[0].x = this.canvas.width - this.snakeBodyArr[0].w;
  } else {
    this.snakeBodyArr[0].x -= this.snakeBodyArr[0].w;
  }
},
/**
 * 往上
 */
up() {
  //超出上边界限
  if (this.snakeBodyArr[0].y <= 0) {
    if (!this.touchSnakeWall) this.gameOver();
    this.snakeBodyArr[0].y = this.canvas.height - this.snakeBodyArr[0].h;
  } else {
    this.snakeBodyArr[0].y -= this.snakeBodyArr[0].h;
  }
},
/**
 * 往下
 */
down() {
  //超出下边界限
  if (this.snakeBodyArr[0].y + this.snakeBodyArr[0].h >= this.canvas.height) {
    if (!this.touchSnakeWall) this.gameOver();
    this.snakeBodyArr[0].y = 0;
  } else {
    this.snakeBodyArr[0].y += this.snakeBodyArr[0].h;
  }
}

1.2 知识点

  • snake每一块身体组合在一起就需要使用数组。
  • 移动snake的规则1:移动头部(改变数组下标0,xy的数据)使用到right(),left(),up(),down()方法
  • 规则2:body向前移动一个(从下标1开始赋值前一位)这样就能实现每一块身体能向前动一步
  • 规则3:清除末尾。也就是清除上一次在的位置

2. 生成被吃者AO

2.1 代码

/**
 * 画出AO
 */
ao() {
  //随机生成坐标
  let randomX = (Math.round(Math.random() * (this.canvas.width - this.aoWidth)));
  let randomY = (Math.round(Math.random() * (this.canvas.height - this.aoHeight)));
  let aoImg = this.getAOImg();
  this.ctx.drawImage(aoImg, randomX, randomY, this.aoWidth, this.aoHeight);
  this.aoArr.push({
    aoImg: aoImg,
    x: randomX,
    y: randomY,
    w: this.aoWidth,
    h: this.aoHeight,
    //1代表未被吃掉
    status: 1
  })
}

2.2 知识点

  • 获取canvas宽高,在canvas的范围内随机生成一个AO
  • 保存生成过的AO对象设置一个status为正常状态

3. 吃掉AO&蛇身加长

3.1 代码

//查找啊哦的位置
let aoObj = this.aoArr.find(o =>
    //把区间放大 小于AO+本身宽度 && 大于AO起点 && 有效的AO
    o.x + this.aoWidth >= snakeBodyHead.x && o.x - snakeBodyHead.w <= snakeBodyHead.x
    && o.y + this.aoHeight >= snakeBodyHead.y && o.y - snakeBodyHead.h <= snakeBodyHead.y
    && o.status === 1
);
//找到了AO位置把它吃掉
if (aoObj && aoObj.status === 1) {
  this.ctx.clearRect(aoObj.x, aoObj.y, this.aoWidth, this.aoHeight);
  //状态设置已被吃掉
  aoObj.status = 2;
  //蛇身+1
  let tail = this.snakeBodyArr[this.snakeBodyArr.length - 1];
  this.snakeBodyArr.push({
    fillStyle: "#" + Math.round(Math.random() * 10000),//每块身体颜色
    x: tail.x,
    y: tail.y,
    w: this.snakeHead.w,
    h: this.snakeHead.h
  });
  //记录已被吃掉的AO
  this.aoDieNum++;
  //500ms出现下一个AO
  setTimeout(() => {
    this.ao();
  }, 500);
}

3.2 知识点

  • 判断蛇头是否触碰到屏幕上的AOthis.aoArr.find
  • 查到AO后清除被吃掉的AO,status设置为2。下次就不会在被find到
  • this.snakeBodyArr[this.snakeBodyArr.length - 1]找到最后一个蛇体,添加到身体末尾
  • setTimeout停顿一些时间再重新生成一个新的AO

总结

以上就是实现贪吃蛇主要代码片段,无聊且有趣。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,下面是一个简单的实现步骤: 1. 创建一个画布 (canvas) 并设置其大小和样式。 ```html <canvas id="snake" width="400" height="400"></canvas> ``` 2. 在 JavaScript 中获取这个画布并创建一个绘图上下文 (context)。 ```javascript const canvas = document.getElementById('snake'); const ctx = canvas.getContext('2d'); ``` 3. 创建蛇的初始状态,包括长度、起始位置和方向。 ```javascript let snake = [{ x: 10, y: 10 }, { x: 9, y: 10 }, { x: 8, y: 10 }]; let direction = 'right'; ``` 4. 创建食物的初始位置。 ```javascript let food = { x: Math.floor(Math.random() * 40), y: Math.floor(Math.random() * 40) }; ``` 5. 创建一个函数来绘制蛇和食物。 ```javascript function draw() { // 绘制蛇 snake.forEach(body => { ctx.fillRect(body.x * 10, body.y * 10, 10, 10); }) // 绘制食物 ctx.fillRect(food.x * 10, food.y * 10, 10, 10); } ``` 6. 创建一个函数来移动蛇。 ```javascript function move() { // 创建新头部 let newHead = { x: snake[0].x, y: snake[0].y }; switch (direction) { case 'up': newHead.y--; break; case 'down': newHead.y++; break; case 'left': newHead.x--; break; case 'right': newHead.x++; break; } // 添加新头部 snake.unshift(newHead); // 判断是否吃到食物 if (snake[0].x === food.x && snake[0].y === food.y) { // 创建新食物 food = { x: Math.floor(Math.random() * 40), y: Math.floor(Math.random() * 40) }; } else { // 移除尾部 snake.pop(); } } ``` 7. 创建一个函数来更新游戏状态并重新绘制画布。 ```javascript function update() { move(); draw(); } ``` 8. 使用 setInterval 函数来不断更新游戏状态。 ```javascript setInterval(update, 100); ``` 到这里,一个简单的贪吃蛇游戏就完成了。当然,这只是一个基础的实现,你可以根据自己的需求进行扩展和优化。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值