Js游戏02-贪吃蛇

学习资料来源:
贪吃蛇(HTML+JS/英文字幕)
源码
01

页面布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<head>
<title>Snake Game</title>
<style>
canvas{
display: block;
margin: 0 auto; // 水平居中
}
</style>
</head>

// 规定大小
<canvas id="snake" width="608" height="608"></canvas>

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

逻辑处理

获取canvas

1
2
const cvs = document.getElementById("snake");
const ctx = cvs.getContext("2d");

定义盒子大小

const box = 32;

加载图片资源

1
2
3
4
5
const ground = new Image();
ground.src = "img/ground.png";

const foodImg = new Image();
foodImg.src = "img/food.png";

加载音频资源

1
2
3
4
5
6
7
8
9
10
11
12
13
let dead = new Audio();
let eat = new Audio();
let up = new Audio();
let right = new Audio();
let left = new Audio();
let down = new Audio();

dead.src = "audio/dead.mp3";
eat.src = "audio/eat.mp3";
up.src = "audio/up.mp3";
right.src = "audio/right.mp3";
left.src = "audio/left.mp3";
down.src = "audio/down.mp3";

定义蛇的位置

1
2
3
4
5
6
let snake = []; // 一个数组

snake[0] = { // 起始位置
x : 9 * box,
y : 10 * box
};

定义食物的位置

1
2
3
4
let food = {
x : Math.floor(Math.random()*17+1) * box,
y : Math.floor(Math.random()*15+3) * box
}

定义得分

let score = 0;

获取键盘按键信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let d;
document.addEventListener("keydown",direction);

function direction(event){
let key = event.keyCode;
if( key == 37 && d != "RIGHT"){
left.play();
d = "LEFT";
}else if(key == 38 && d != "DOWN"){
d = "UP";
up.play();
}else if(key == 39 && d != "LEFT"){
d = "RIGHT";
right.play();
}else if(key == 40 && d != "UP"){
d = "DOWN";
down.play();
}
}

碰撞检测

  • 循环 - 头 比较每一个地方。
    1
    2
    3
    4
    5
    6
    7
    8
    function collision(head,array){
    for(let i = 0; i < array.length; i++){
    if(head.x == array[i].x && head.y == array[i].y){
    return true;
    }
    }
    return false;
    }

绘制内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
function draw(){

ctx.drawImage(ground,0,0); // 绘制地面

// 绘制蛇
for( let i = 0; i < snake.length ; i++){
// 头是绿色,身体白色。
ctx.fillStyle = ( i == 0 )? "green" : "white";
// 绘制
ctx.fillRect(snake[i].x,snake[i].y,box,box);
// 增加边框
ctx.strokeStyle = "red";
ctx.strokeRect(snake[i].x,snake[i].y,box,box);
}

// 绘制食物
ctx.drawImage(foodImg, food.x, food.y);

// old head position - 当前头部位置
let snakeX = snake[0].x;
let snakeY = snake[0].y;

// which direction - 改变后头部位置 - 依据x y 轴
if( d == "LEFT") snakeX -= box;
if( d == "UP") snakeY -= box;
if( d == "RIGHT") snakeX += box;
if( d == "DOWN") snakeY += box;

// if the snake eats the food - 碰到食物
if(snakeX == food.x && snakeY == food.y){
score++; // 得分 ++
eat.play(); // 加载音频
food = { // 持续生成食物位置
x : Math.floor(Math.random()*17+1) * box,
y : Math.floor(Math.random()*15+3) * box
}
// we don't remove the tail
}else{
// remove the tail 移出尾部 - 移动。
snake.pop();
}

// add new Head

let newHead = {
x : snakeX,
y : snakeY
}

// game over
// 超出边界
if(snakeX < box || snakeX > 17 * box || snakeY < 3*box || snakeY > 17*box || collision(newHead,snake)){
clearInterval(game); // 停止计时器
dead.play(); // 播放dead声音

// 这里可以设置重新开始的开关!
}

// 添加头部。
snake.unshift(newHead);

// 写入得分
ctx.fillStyle = "white";
ctx.font = "45px Changa one";
ctx.fillText(score,2*box,1.6*box);
}

开始游戏

  • 计时器
    let game = setInterval(draw,100);

总结

伪代码:

  1. 获取canvas
  2. 设置盒子大小
  3. 定义加载图片/音频资源
  4. 定义蛇 / 食物 / 得分
  5. 获取键盘信息
  6. 碰撞检测 - 碰到自己 - 循环判断x , y和头部是否相等。
  7. 循环渲染
    • 绘制地面
    • 绘制蛇
    • 绘制食物
    • 判断方向 - 修改头部位置
    • 如果是食物 - 不去除尾部,不是的话,去除尾部
    • 把改变方向后的盒子放入头部
    • 判断是否超过边界 和 碰撞到自己 - 是就结束定时器,否则继续执行
    • 用canvas写入得分信息
  8. 开启定时器 - 启动游戏

主要内容:
如果增加长度 - 写入canvas - 循环蛇的信息,判断是否是食物
如果判断相交 - x,y + 循环 + 边界条件
游戏开始 - 开启定时器!