利用HTML5 canvas元素+原生JS编写贪吃蛇

我们先来看一个最简单的例子 

利用canvas动画编写贪吃蛇:https://clacier.github.io/tcs/

一.什么是canvas?

canvas是HTML5中新增加的一个元素,专门用于图形的绘制,通过脚本 (通常是JavaScript)来完成;

标签只是图形容器,我们必须通过JS代码来绘制图形

首先创建一个画布(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()	//绘制已定义的路径。

二.贪吃蛇的组成

利用HTML5 canvas元素+原生JS编写贪吃蛇_第1张图片

我们从图片中可以看到,贪吃蛇的原型其实是由一个个方块连接而成的,所以我们先要构造方块

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

你可能感兴趣的:(JavaScript)