• “贪吃蛇”


    “贪吃蛇”小游戏

    HTML5贪吃蛇游戏

    页面结构

    以保存对javascript的些许理解

    复制代码
    /****************/
    /*****game.js****/
    /****************/
    Array.prototype.remove = function (obj) {
        for (var i = 0, l = this.length; i < l; i++) {

            if (this[i] == obj) {
                this.splice(i, 1);
                break;
            }
        }
    }

    var Game = {
        //循环ID
        timeId: -1,
        //context2d对象
        gamebg: null,
        //游戏背景信息
        gameinfo: {},
        //开始按钮
        btn: null,
        //初始化
        snake: null,
        food: null,
        init: function () {
            //获取游戏背景dom
            var game_dom = document.getElementById('gamebg'),
            This = this;
            //设置游戏背景信息
            this.gameinfo = {
                 game_dom.clientWidth,
                height: game_dom.clientHeight,
                left: game_dom.offsetLeft,
                top: game_dom.offsetTop
            };
            //获取context2d对象
            this.gamebg = game_dom.getContext('2d');
            //绑定键盘按下事件
            document.onkeydown = function (e) { This.keyDown(e); };
            //创建小球
            this.snake = new Snake(7, this.gameinfo.width, this.gameinfo.height);
            this.food = new Food(100, 100, 4, 'red');
            //this.createFood();
        },

        keyDown: function (e) {
            var d = this.snake.direction;
            switch (e.keyCode) {
                case 37:
                    d = 9;
                    break;
                case 38:
                    d = 12;
                    break;
                case 39:
                    d = 3;
                    break;
                case 40:
                    d = 6;
                    break;
                case 32:
                    this.pause(document.getElementById('Button2'));
                    break;
            }
            if (Math.abs(this.snake.direction - d) != 6) {
                this.snake.oldDirection = this.snake.direction;
                this.snake.direction = d;
            }
            else {
                this.snake.back = 1;
            }
        },

        //btn:开始按钮dom
        start: function (btn) {

            if (this.btn) this.reset();

            this.btn = btn;
            this.btn.disabled = 'disabled';
            var This = this;
            this.init();
            //开始画画
            this.timeId = setInterval(function () {
                This.process();
            }, 80);
        },

        process: function () {
            //清除画面
            this.gamebg.clearRect(0, 0, this.gameinfo.width, this.gameinfo.height);
            this.snake.update(this.food);
            var body = this.snake.Body;
            Canvas.arc(this.gamebg, this.food.X, this.food.Y, this.food.Radius, this.food.Color);
            for (var i = 0; i < body.length; i++) {
                Canvas.arc(this.gamebg, body[i].X, body[i].Y, body[i].Radius, body[i].Color);
            }

            //判断游戏是否结束
            if (this.snake.Body.length == 0) {
                clearInterval(this.timeId);
                var score = document.getElementById("score");
                alert('您的分数是:' + score.innerHTML);
                this.btn.disabled = '';
            }
        },

        //重置游戏数据
        reset: function () {
            this.food = null;
            this.snake = null;
            this.timeId = -1;
            this.gamebg = null;
            this.gameinfo = {};
            var score = document.getElementById("score");
            score.innerHTML = 0;
        },

        pause: function (btn) {
            if (btn.value == 'Pause') {
                clearInterval(this.timeId);
                btn.value = 'Run';
            }
            else if (btn.value == 'Run') {
                btn.value = 'Pause';
                var This = this;
                this.timeId = setInterval(function () {
                    This.process();
                }, 80);
            }
        }
    复制代码

    }

    复制代码
    /****************/
    /*****food.js****/
    /****************/
    var Food = function (x, y, radius, color) {
        this.X = x;
        this.Y = y;
        this.Radius = radius;
        this.Color = color;
        this.fpt = 10000;
        this.lastUpdata = 0;
    }

    Food.prototype =
    {
        update: function () {
            this.X = parseInt(Math.random() * 380 + 8, 10);
            this.Y = parseInt(Math.random() * 380 + 8, 10);
        }
    复制代码

    }

    复制代码
    /****************/
    /*****Canvas.js****/
    /****************/
    var Canvas = {
        //画圆
        //ctx:context2d对象,x:圆心x坐标,y:圆心y坐标,radius:半径,color:颜色
        arc: function (cxt, x, y, radius, color) {
            cxt.fillStyle = color;
            cxt.beginPath();
            cxt.arc(x, y, radius, 0, Math.PI * 2, true);
            cxt.closePath();
            cxt.fill();
        }
    复制代码

    }

    复制代码
    /****************/
    /*****Bone.js****/
    /****************/
    var Bone = function (x, y, radius, color) {
        this.X = x;
        this.Y = y;
        this.Radius = radius;
        this.Color = color;
    复制代码

    }

    复制代码
    /****************/
    /*****Snake.js****/
    /****************/
    var Snake = function (length, width, height) {
        this.fpt = 40;
        this.Body = [];
        this.lastUpdata = 0;
        this.speed = 8;
        this.oldDirection = 6;
        this.direction = 6;
        var centerX = parseInt(width / 2, 10);
        var centerY = parseInt(height / 2, 10);

        var bone = new Bone(centerX, centerY, 4, 'blue');
        this.Body.push(bone);

        for (var i = 0; i < length - 1; i++) {
            var bone = new Bone(centerX, centerY - (8 * (i + 1)), 4, 'blue');
            this.Body.push(bone);
        }

        this.cornerX = centerX;
        this.cornerY = centerY;
        this.back = 0;
    }

    Snake.prototype =
    {
        update: function (food) {
            if (this.lastUpdata % this.fpt == 0) {

                if (this.back == 1) {
                    this.back = 0;
                    var last = this.Body[this.Body.length - 1];
                    var secondLast = this.Body[this.Body.length - 2];

                    if (last.Y - secondLast.Y > 0) {
                        this.direction = 6;
                    }
                    else if (last.Y - secondLast.Y < 0) {
                        this.direction = 12;
                    }
                    else if (last.X - secondLast.X < 0) {
                        this.direction = 9;
                    }
                    else if (last.X - secondLast.X > 0) {
                        this.direction = 3;
                    }
                    this.Body.reverse();
                }


                //记录蛇头的原始坐标
                this.cornerX = this.Body[0].X;
                this.cornerY = this.Body[0].Y;

                //定义蛇头的新位置
                switch (this.direction) {
                    case 12:
                        this.Body[0].Y -= this.speed;
                        break;
                    case 6:
                        this.Body[0].Y += this.speed;
                        break;
                    case 3:
                        this.Body[0].X += this.speed;
                        break;
                    case 9:
                        this.Body[0].X -= this.speed;
                        break;
                    default:
                        break;
                }
                //蛇身的新位置为前一个节点的位置
                for (var i = this.Body.length - 1; i > 1; i--) {
                    this.Body[i].X = this.Body[i - 1].X;
                    this.Body[i].Y = this.Body[i - 1].Y;
                }

                //定义蛇尾的新位置
                this.Body[1].X = this.cornerX;
                this.Body[1].Y = this.cornerY;

                this.eatFood(food);
                var over = false;
                for (var j = 0; j < this.Body.length; j++) {
                    var bone = this.Body[j];
                    if (bone.X < 0 || bone.Y < 0 || bone.X > 400 || bone.Y > 400) {
                        over = true;
                        break;
                    }
                }

                if (over) {
                    this.Body.length = 0;
                }
            }

            //时间累加
            this.lastUpdata += 10;
        },

        eatFood: function (food) {
            var i, l, bone, isTouch = false;
            //遍历蛇身体
            for (i = 0, l = this.Body.length; i < l; i++) {
                var bone = this.Body[i];
                //判断蛇身与食物的圆心距
                if (Math.sqrt(Math.pow(bone.X - food.X, 2) + Math.pow(bone.Y - food.Y, 2)) <= bone.Radius + food.Radius) {
                    isTouch = true;
                    break;
                }
            }

            //给蛇增加一节
            if (isTouch) {
                var head = this.Body[0];
                var x = head.X;
                var y = head.Y;
                switch (this.direction) {
                    case 12:
                        y = y - head.Radius * 2;
                        break;
                    case 3:
                        x = x + head.Radius * 2;
                        break;
                    case 6:
                        y = y + head.Radius * 2;
                        break;
                    case 9:
                        x = x - head.Radius * 2;
                        break;
                }
                var newBone = new Bone(x, y, head.Radius, head.Color);
                this.Body.push(newBone);

                //随机改变食物的位置
                food.X = -100;
                food.Y = -100;
                setTimeout(function () {
                    food.update();
                }, 800);
                var score = document.getElementById("score");
                score.innerHTML = parseInt(score.innerHTML) + 1;
                if (this.fpt > 10) {
                    this.fpt -= 10;
                }
            }
        }
    复制代码

    复制代码
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
        <script src="game.js" type="text/javascript"></script>
        <script src="Bone.js" type="text/javascript"></script>
        <script src="Canvas.js" type="text/javascript"></script>
        <script src="Snake.js" type="text/javascript"></script>
        <script src="food.js" type="text/javascript"></script>
    </head>
    <body>
        <canvas id="gamebg" width="400" height="400" style="background: Black;">您的浏览器不支持html5,请使用chrome或者ff</canvas>
        <input id="Button1" type="button" value="Start" onclick="Game.start(this)" />
        <input id="Button2" type="button" value="Pause" onclick="Game.pause(this)" />
        <br />
    <div id="score">0</div>
    </body>
    复制代码

    </html> 

    简单的21x21的方块,页面结构

    id为container的div包含所21个class名为row的div,每个row代表贪吃蛇的一整行,每个row中又包含21个div,代表这一行的每一个div方格,如果这个方格是空的话,div的类名为blank,如果这一个方格表示“贪吃蛇”的“食物”,div的类名为food,如果这一个方格表示“蛇”,div的类名为snake。

    CSS

    JS

    然后我们思考下一个贪吃蛇游戏需要那些参数,

    首先,界面中可见的元素无非就是空方格,“蛇”还有“食物”,所以需要一个二维数组,用来表示每个方格的状态0表示方格为空,1表示方格为“食物”,2表示方格为“蛇”,然后是一个数组,存放“蛇”在方格中所占位子的坐标,再然后是一个存放“食物坐标”,由于需要确定“蛇”移动的方向,所以需要个存放方向的变量,还需要一个定时器,控制蛇每秒钟的移动,最后是需要统计用户的得分,所以有

    我们需要创建游戏界面,所以在Game中添加函数createDOM,根据我们上文所说的页面结构,我们有

    有了createDOM之后,在Game初始化的时候调用,初始化函数名为init

    所以有

    首先调用上文的createDOM方法生成页面

    然后初始化data,data为一个长度21的二维数组,二维数组的每一个子元素又是一个数组,数组中的每个元素值都为0,

    然后初始化蛇的坐标,这里默认为方格的9,10,11行的第10列,

    然后是遍历snake数组,讲snake数组中每个元素表示的data中的位置的值改为2,即在data中表示蛇的位置,

    接着需要生成食物的坐标,由于之后还要多次生成食物坐标,所以写了一个create_food方法,方便之后调用,

    蛇的初始移动方向默认为“上”,

    如果是用户第二次开始,先清除上一次游戏设置的定时器

    初始化玩家得分为0

    调用key_action方法,设置键盘事件,控制蛇的移动方向

    然后是调用display方法,刷新游戏页面

    create_food方法

    先随机生成一个x,y的坐标,由于“食物”的生成位置只能在空位置,即data中值为0的位置,所以如果data[x][y]的值不为0的话,一直重新生成,直到生成的位置为空,将生成位置对应data中的值改为1,

    key_action方法

    读取键盘事件,并根据情况设置“贪吃蛇”的移动方向,

    display方法

    遍历data二维数组,数组中的值0,1,2对应空,“食物”,“蛇”,讲页面中所对应的标签的类名分别改写为“blank”,“food”,“snake”,

    最为关键的是需要让蛇能动起来,我们写了一个snake_move方法,

    思考一波,比如说snake现在的元素有[{x:9,y:10},{x:10,y:10},{x:11,y:10}],当前的direction的值是“up”向上移动,所以下一个状态的snake的元素应该是[{x:8,y:10},{x:9,y:10},{x:10,y:10}],也就是说,原来的snake将最后一个元素{x:11,y:10}舍弃,然后根据direction的值,计算出一个新的坐标,并snake数组的头部加入

    所以有

    last变量存放原来snake数组的最后一个元素,obj存放下一个时刻的snake头部的元素

    如果direction的值为“up”那么下一个时刻snake头部元素,应该为原来的snake首个元素snake[0]的x值减1,snake[0]的y值不变,

    direction为其他值的时候类推

    但这样还不够,贪吃蛇存在碰到“墙壁”或者碰到“蛇”自己身体的情况,

    还是拿direction的值为“up”类比,当原snake[0]的x值为0的时候,即已经到达了游戏框的顶部,如果继续向上移动,那么下一个x值应该为-1,显然是不合理的,所以有

    还有“蛇”撞到自己身体的情况,上面说到obj存放的是下一个时刻snake头部的坐标,如果在data数组中所对应位置的值为2即“蛇”的身体,表示“蛇”撞到了自己的身体

    所以有

    上面说到obj存放的是下一个时刻snake头部的坐标,但是实际上snake这个数组并没有被重新赋值,所以我们还需要一个add_snake方法,每次数组变化的时候更新snake数组

    并在snake_move中调用,调用后结果改变了snake数组变味了下一个状态,但是这个时候data数组所表示的原来的snake数组的最后一个元素,应该为空(蛇移动之后,尾部重新变为空)所以我们将之前保存下来的原snake的最后一个元素在data中对应的值变为0,

     

    最后重新遍历新生成的snake数组,讲snake数组在data数组所对应的位置的值设为2

    完整的snake_move方法

    最后需要一个start方法,设置一个定时器,不断调用snake_move方法让蛇移动

    在init的末尾调用start方法,大功告成

    最后Game.init();初始化游戏,试玩下

  • 相关阅读:
    java基础>包、访问权限、命名规范 小强斋
    java基础>Static 和 Final 关键字 小强斋
    java基础>对象的创建过程(初始化、析构、清理) 小强斋
    iPhone 上少用三元操作符 ? :
    QQ群人满了
    面向对象C语言(ObjectiveC)编程简介
    java Integer.ValueOf(int)和new Integer(int)性能比较
    关于在iPhone上合并2个应用程序(App)成一个
    java Preferences持久化使用示例
    Memcache VS MySQL Query Cache.
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/6239356.html
Copyright © 2020-2023  润新知