使用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 知识点
- 判断蛇头是否触碰到屏幕上的AO
this.aoArr.find
- 查到AO后清除被吃掉的AO,status设置为2。下次就不会在被find到
this.snakeBodyArr[this.snakeBodyArr.length - 1]
找到最后一个蛇体,添加到身体末尾setTimeout
停顿一些时间再重新生成一个新的AO
总结
以上就是实现贪吃蛇主要代码片段,无聊且有趣。