zoukankan      html  css  js  c++  java
  • 苏福的作品:贪吃蛇

    本文是苏福的原创文章,转载请注明出处:苏福CNblog:http://www.cnblogs.com/susufufu/p/5875523.html

    该程序是本人的个人作品,写的不好,未经本人允许,请不要用于其它用途!

    贪吃蛇的游戏相信80后的朋友小时候都玩过,记得我小时候还攒了二十多块钱买了个游戏机(一个礼拜2块的零花钱!),可以玩飞机、俄罗斯方块、贪吃蛇等,刚开始玩的真过瘾,无奈太费电池,玩不起,放一段时间居然屏幕不行了!哎!
    点击查看演示:

    贪吃蛇没什么游戏规则,就是转转转、吃吃吃!我就定义了一个类Snake,想用面向对象来写,不知道写的像不像!请前辈多多指点

    //====Snake类
                var Snake = function () {
                    this.score = 0;
                    this.speed = 10;
                    this.levle = 0;
                    this.snakeHead = this.createBlock('snake-head',block);
                    this.snake = [this.snakeHead]; //将蛇头作为蛇体的第一个元素
                    this.food = this.createBlock('food',block);
                };
    

    这个游戏的设计难点有这几个:

    1. 蛇的移动方向随方向键的改变
    2. 蛇身各个部分的移动
    3. 蛇身移动过程中不断的判断是否撞墙、是否吃到食物。

    蛇的移动方向的改变我定义了一个静态属性Snake.headDirection = {x:1,y:0};,用来保存当前状态,x、y的取值范围为1、0、-1,x和y不会同时为零,x为零时表示当前垂直移动,可以往左(y:1)或往右(y:-1),y为零时表示水平移动,可以往上(x:1)或往下(x:-1)。为此我把方向键的事件回调函数设计成类似状态机的函数:

    document.onkeydown = function (event){
                    var e = event||window.event;
                    var key = e.keyCode;
                    switch (key){
                        case 38:
                            if(Snake.headDirection.x === 0){return;} //判断是否是垂直移动
                            Snake.headDirection.y = 1;
                            Snake.headDirection.x = 0;
                            break;
                        case 40:
                            if(Snake.headDirection.x === 0){return;}
                            Snake.headDirection.y = -1;
                            Snake.headDirection.x = 0;
                            break;
                        case 37:
                            if(Snake.headDirection.y === 0){return;} //判断是否是水平移动
                            Snake.headDirection.x = 1;
                            Snake.headDirection.y = 0;
                            break;
                        case 39:
                            if(Snake.headDirection.y === 0){return;}
                            Snake.headDirection.x = -1;
                            Snake.headDirection.y = 0;
                            break;
                    }
                };
    

    下面是创建蛇头或蛇身的共有函数,因为蛇头、蛇身都是由一样的方块组成,这里我预先在HTML文件里就创建了一个方块<span class="block"></span>,通过css把它藏在标题栏的下面,然后以后碰到要创建蛇头、蛇身的时候就克隆一个并在给定随机位置后添加到游戏窗口,省的每次都运行创建元素的代码:具体看代码注释

    Snake.prototype.createBlock = function (id,block) {
                    var bk = block.cloneNode(false),x = getRandom(600),y = getRandom(400);
                    bk.id = id;
                    setElemXY(bk,x,y); //该方法用来设置元素的lef、top
                    gameWindow.appendChild(bk);
                    return bk;
                };
    

    接下来是蛇的移动、吃食物、撞墙:当蛇头的位置等于食物的位置时,启动吃食物函数;当蛇头的下次移动的坐标在游戏窗口之外时,就判定撞墙,游戏结束;

    //移动蛇身,并判断是否吃到食物,或吃到自己,或撞墙
                Snake.prototype.moving  = function () {
                    //吃到食物
                    var head = getElemXY(this.snakeHead), food = getElemXY(this.food);
                    if(head.x === food.x && head.y === food.y){
                        this.eat(this.food);
                        this.food = this.createBlock('food',block);
                    }
                    //移动、撞墙
                    var x = Snake.headDirection.x, y = Snake.headDirection.y;
                    //x等于0说明当前垂直移动,如果y等于1,说明在向左移动,所以head.y即元素的left-10px;y等于零时同理
                    if(x === 0){ 
                        y === 1 ? head.y-=10 : head.y+=10;
                        if(head.y<0||head.y>400){this.gameOver();return;}
                    }
                    if(y === 0){
                        x === 1 ? head.x-=10 : head.x+=10;
                        if(head.x<0||head.x>600){this.gameOver();return;}
                    }
    
                    var len = this.snake.length;
                    for(var i = len-1 ; i>0 ; i--){
                        var nowXY = getElemXY(this.snake[i]);
                        if(head.x === nowXY.x && head.y === nowXY.y){this.gameOver();return;} //吃到自己
                        var preXY = getElemXY(this.snake[i-1]);
                        setElemXY(this.snake[i],preXY.x,preXY.y); //将每个蛇节都移到它的前一个的位置
                    }
                    setElemXY(this.snakeHead,head.x,head.y); //舌头移动到新位置
    
                    timeId = setTimeout(function () {
                        this.moving();
                    //这里用bind绑定this,不然无法调用this.moving(),不支持bind的话只能外层加个匿名函数来传参了
                    }.bind(this),1000/this.speed);  
                };
    

    下面是吃食物函数,这个函数比较简单,主要看后面几行代码,将食物的位置改为蛇身的最后一个节点的位置,并把它添加进蛇的数组,便于整体移动

    //吃食物,并更新游戏成绩
                Snake.prototype.eat = function (food) {
                    this.levle++;
                    this.speed+=0.4;
                    this.score+=5*this.speed;
                    levelInfo.innerHTML = '等级: '+this.levle;
                    speedInfo.innerHTML = '速度: '+this.speed.toFixed(2);
                    scoreInfo.innerHTML = '成绩: '+this.score;
                    maxScore = Math.max(maxScore,this.score);
                    maxScoreInfo.innerHTML = '最高成绩: '+maxScore;
                    var oldLast = getElemXY(this.snake[this.snake.length-1]);
                    setElemXY(food,oldLast.x,oldLast.y);
                    this.snake.push(food);
                };
    

    基本上就是以上这些代码了,其它还有几个简单的公共函数,就不说了,自己查看源码。

    这里我要说的一点心得:给函数、变量命名的时候一定要语义化,一看就能大概知道这个函数、变量是干什么的,这样才不会自乱阵脚,更别提和别人合作了!(不要用拼音,你不觉得low的话也行,我是不懂就查翻译,多多少少也能提高点英语水平吧,呵呵,我英语水平也是很菜,惭愧!)

  • 相关阅读:
    详解Codis安装与部署
    停车场地图开发
    dlib换脸
    海康相机官网硬触发设置
    python操作数据库
    心率和血氧测量
    音乐模块
    flask网页显示图片
    树莓派识别二维码
    树莓派python获取自身IP
  • 原文地址:https://www.cnblogs.com/susufufu/p/5875523.html
Copyright © 2011-2022 走看看