我们先来看一个最简单的例子
利用canvas动画编写贪吃蛇:https://clacier.github.io/tcs/
canvas是HTML5中新增加的一个元素,专门用于图形的绘制,通过脚本 (通常是JavaScript)来完成;
首先创建一个画布(Canvas)
一个画布在网页中是一个矩形框,通过
简单实例如下:
注意: 默认情况下
使用 JavaScript 来绘制图像
let c=document.getElementById("myCanvas");
let ctx=c.getContext("2d");
首先,找到
let c=document.getElementById("myCanvas");
然后,创建 context 对象:
let ctx=c.getContext("2d");
getContext("2d") 对象是内建的 HTML5 对象,拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。
Canvas 坐标
canvas是一个二维网格,我们可以把整个浏览器屏幕看做成直角坐标系的第四象限,不过向下为Y轴正方向
我们会用到以下几种方法
ctx.beginPath() //起始一条路径,或重置当前路径。
ctx.rect() //创建矩形。
ctx.fill() //填充当前绘图(路径)。
ctx.stroke() //绘制已定义的路径。
我们从图片中可以看到,贪吃蛇的原型其实是由一个个方块连接而成的,所以我们先要构造方块
1.创建方块对象
function Square(x, y, w, h, c) {
this.x = x;
this.y = y;
this.w = w;//宽
this.h = h;//高
this.c = c;//颜色
}
2.画方块
由于有多个方块,所以我们需要在原型里添加画方块的方法
Square.prototype.draw = function() {
ctx.beginPath();
ctx.rect(this.x, this.y, this.w, this.h);
ctx.fillStyle = this.c;
ctx.fill();
ctx.stroke();//画出方块的轮廓,不显示轮廓可以不写
}
3.方块移动
Square.prototype.move = function() {
//根据蛇头的方向决定移动方向
switch(snake.direction) {
case 37:
this.x -= this.w;
break;
case 38:
this.y -= this.h;
break;
case 39:
this.x += this.w;
break;
case 40:
this.y += this.h;
break;
}
}
4.创建蛇对象
蛇是如何组成的?我们从图片中看到的蛇很容易想到一种数据结构那就是数组。
我们把方块一个一个push到一个空数组里,这样就组成了一条蛇,数组的第一个元素则是蛇头
function Snake() {
//定义初始方向
this.direction = 38;
//按键锁,防止一次性按多个键
this.Lock = false;
//判断蛇头是否撞墙或者身体
this.isOnBody = false;
//用数组存储蛇身
this.Body = [];
//初始化身体
//根据循环次数来改变蛇身的长度
for(var i = 0; i < 5; i++) {
this.Body.push(new Square(500 + i * size, 200, size, size, "#00e600"));
}
//设置蛇头颜色
this.Body[0].c = "#f92506";
}
5.蛇的移动
最关键的来了,蛇是怎么移动的?
先看代码:
Snake.prototype.move = function() {
this.Lock = false;
//在蛇头移动后插入一个方块
this.Body.splice(1, 0, new Square(this.Body[0].x, this.Body[0].y, size, size, "#00e600"));
//判断是否吃到食物,如果吃到,则再创建食物,并且不移除尾部方块
if( food.x == this.Body[0].x && food.y == this.Body[0].y) {
Fraction++ //分数+1
food=createFood();
}
else{
this.Body.pop();
}
//只让蛇头移动
this.Body[0].move();
}
蛇每次都会移动一个单位,我们只让蛇头移动,随即在蛇头移动前的位置插入一个方块,然后再末尾删除一个方块,这样就实现了蛇的一次移动,所以我们为什么要把蛇看成一个数组,插入和末尾删除,因为我们刚好可以用到数组的splice()和pop()方法
6.控制蛇的移动
这个很简单,我们就用一般的方向键来控制
document.onkeydown = function(e) {
let et = e || window.event;
if(!snake.Lock) {
switch(et.keyCode) {
case 37:
if(snake.direction != 39) {
snake.direction = 37;
snake.Lock = true;
}
break;
case 38:
if(snake.direction != 40) {
snake.direction = 38;
snake.update = true;
}
break;
case 39:
if(snake.direction != 37) {
snake.direction = 39;
snake.Lock = true;
}
break;
case 40:
if(snake.direction != 38) {
snake.direction = 40;
snake.Lock = true;
}
break;
}
}
}
首先,食物肯定是随机出现的,所以我们先要写一个随机函数:
function Random(min, max) {
return parseInt(Math.random() * (max - min) + min) * size;
}
有人肯定会问为什么要乘一个size?,我们先把食物创建完我再解释
function createFood() {
//判断食物是否在蛇身上
let isOnSnake = true;
while(isOnSnake) {
var x = Random(0, 800 / size);//水平长度
var y = Random(0, 600 / size);//竖直长度
for(let i = 0; i < snake.Body.length; i++) {
//如果食物在身体上,就继续创建食物
if(snake.Body[i].x == x && snake.Body[i].y == y) {
isOnSnake = true;
break;
} else {
isOnSnake = false;
}
}
}
return new Square(x, y, size, size, "#00FF00"); //输出食物
}
因为我们需要把画布区域分解成由组成蛇的方块一个一个拼接而成,这样才能确保食物出现的位置能与蛇头对齐。
所以我们需要把size定义为一个全局变量,很多方法都会调用这个变量
这里我们需要使用window.requestAnimationFrame()
方法:方法具体介绍
let snake = new Snake();
let food = createFood();
let jspeed= 0;
let Fraction=0 //记录分数
let v=15; //速度
//动画
function A() {
if(Fraction>5){ //分数大于5就加速
v=10;
}
if(Fraction>10){ //继续加速,当然还可设置
v=5;
}
jspeed++;
//改变速度
if(jspeed % v== 0) {
ctx.fillStyle='rgba(0,0,0,0.75)';
ctx.fillRect(0, 0, canvas.width, canvas.height);//清除轨迹
food.draw();
snake.move();
for(var i = 0; i < snake.Body.length; i++) {
snake.Body[i].draw();
}
}
//判断蛇头是否撞到身体
for(let i = 1; i < snake.Body.length; i++) {
if((snake.Body[0].x == snake.Body[i].x) && (snake.Body[0].y == snake.Body[i].y)) {
snake.isOnBody = true;
break;
} else {
snake.isOnBody = false
}
}
var stop = 0;
//当撞墙或者撞到身体就结束游戏
if(snake.Body[0].x < 0 || snake.Body[0].x > c.width - size || snake.Body[0].y < 0 || snake.Body[0].y > c.height - size || snake.isOnBody) {
alert('game over');
document.location.reload();
} else {
stop= window.requestAnimationFrame(A);
}
}
A();
好了,我们最基本的贪吃蛇就完成了。
我们可以做一点更高级的,比如引入分数功能,随着分数增加,蛇的移动速度会更快
https://clacier.github.io/tcs/tcsjj.html