zoukankan      html  css  js  c++  java
  • “贪吃蛇”

    “贪吃蛇”小游戏

    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();初始化游戏,试玩下

  • 相关阅读:
    WCF 第八章 安全 确定替代身份(中)使用AzMan认证
    WCF 第八章 安全 总结
    WCF 第八章 安全 因特网上的安全服务(下) 其他认证模式
    WCF Membership Provider
    WCF 第八章 安全 确定替代身份(下)模仿用户
    WCF 第八章 安全 因特网上的安全服务(上)
    WCF 第九章 诊断
    HTTPS的七个误解(转载)
    WCF 第八章 安全 日志和审计
    基于比较的排序算法集
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/6239356.html
Copyright © 2011-2022 走看看