面向对象编程-贪吃蛇小游戏

页面中的地图map

html结构
    <div id = "map"></div>
样式
    #map{
        width:800px;
        height:600px
        margin:0 auto;
        background-color:#ccc;
        position:relative;
    }

食物的对象

  • Food
    • 属性
      • 宽度width
      • 高度height
      • 背景色bgColor
      • 横向坐标x
      • 纵向坐标y
    • 方法:
      • 出现在地图上
书写贪吃蛇食物小点的构造函数
function Food(options){
    options = options||{};
    this.width = options.width||20;
    this.height = options.height||20;
    this.bgColor = options.bgColor||"blue"
    this.x = options.x||0;
    this.y = options.y||0;
}

等同于构造函数function Food(width,height,bgColor){
};
Food(options){};options是一个置入的对象作为形参,可以多个参数传入,优点

    function Foodoptions){
        ...
    }
var f = new Food({
        width:50,
        height:50,
        ....
    });
在Food的原型对象上创建共同的行为render渲染函数

将食物小块随机放在map地图上

Food.prototype.render = function(target){
    //创建一个div
    var div = document.createElement("div");
    target.appendChild(div);
    //设置div的一些样式 width height 背景色 left top
    div.style.width = this.width+"px";
    div.style.height = this.height+"px";
    div.style.backgroundColor = this.bgColor;
    //设置div的left值与top值
    //this.x是0-800/20之间的随机数
    this.x = parseInt(Math.random()*target.offsetWidth/this.width);
    this.y = parseInt(Math.random()*target.offsetHeight/this.height);
    div.style.left = this.x*this.width+"px";
    div.style.top = this.y*this.height+"px";
    div.style.position = "absolute";
}

蛇的对象

  • Snake由多个小方块格div组成
    • 属性
      • width蛇的小方块格宽度
      • height蛇的小方块格高度
      • headColor蛇头颜色
      • bodyColor身体颜色
    • 方法
      • 渲染render()
      • 移动move()
创建Snake构造函数
function Snake(options){
    options = options||{};
    this.width = options.width ||20;
    this.height = options.height ||20;
    this.headColor = options.headColor ||"blue";
    this.bodyColor = options.bodyColor||"pink";
    //蛇的核心,蛇是由一个个小方块组成,默认蛇是由三个小方块组成
    this.body = [
        {x:2,y:0,bgColor:this.headColor},
        {x:1,y:0,bgColor:this.bodyColor},
        {x:0,y:0,bgColor:this.bodyColor}
    ];
    this.direction = "right";
}
在原型中创建Snake通用渲染方法
Snake.prototype.render = function(target){
    for(var i = 0;i<this.body.length;i++){
        var span = document.createElement("span");
        target.appendChild(span);
        span.style.width = this.width+"px";
        span.style.height = this.height+"px";
        span.style.backgroundColor = this.body[i].bgColor;
        span.style.position = "absolute";
        span.style.left = this.body[i].x*this.width;
        span.style.top = this.body[i].y*this.height;
    }
}
在原型对象中创建Snake通用的移动方法
Snake.prototype.move = function(target,food){
//移动的思路:
    //1. 移动蛇的身体
    //2. 根据方向移动蛇头
    //3. 删除整条蛇
    //4. 重新渲染这条蛇
    for (var i = this.body.length-1;i>0;i--){//控制蛇尾的变化
    //蛇尾开始变为上一个块儿,可以不用记录上一个块儿的位置,更加方便,蛇尾是数组的第一个值
    this.body[i].x = this.body[i-1].x;
    this.body[i].y = this.body[i-1].y;
    }
    switch(this.direction){//控制蛇头的方向和变化
    //记录一个方向条件,判断,方向的的变化控制x的增减或y,改蛇头
        case "right":
        this.body[0].x++;
        break;
        case "left":
        this.body[0].x--;
        break;
        case "top":
        this.body[0].y--;
        break;
        case "bottom":
        this.body[0].y++;
        break;
    }

    //用于蛇的身体加长,吃food,改变蛇的自身
    //1. 判断蛇头的位置与食物的位置是否重合。
    //2. 把移动前的那个蛇尾位置push到body中,添加蛇尾的思想
    //3. 把原先的食物删除
    //4. 重新渲染一个新的食物
     if(head.x === food.x && head.y === food.y){
            this.body.push({
                x:last.x,
                y:last.y,
                bgColor:this.bodyColor
            });
        //删除食物,让食物重新渲染
        var div = target.querySelector("div");
        target.removeChild(div);
        food.render(target);
        }

    //去除所有的span标签
    var spans =target.querySelectorAll("span");
    for(var i = 0;i < spans.length;i++){
    target.removeChild(span[i]);
    }
}

游戏对象的封装

  • 游戏构造函数,管理所有的对象,地图
  • 属性
    • 蛇 食物 地图
  • 方法开始游戏
游戏对象以及初始化
function Game(target){
    this.target = target;
    this.snake = new Snake();
    this.food = new Food();
    //初始化游戏
    this.init();
}
Game.prototype.init = function(){
    //渲染蛇和食物
    this.snake.render(this.target);
    this.food.render(this.target);
    var that = this;
    //由于在下面的函数中要使用当前函数中的this
    //但是下面的函数中有自己的this,如果直接用this,是访问不到我们这个函数中的this的
    //所以我们声明一个新的变量that 将当前函数中的this赋值给这个that
    //that和this的值就是相同的了
    //在下面的函数中我们就可以使用that来访问到当前函数中的this了!
        //onkeyup事件只能给有焦点的东西注册,或者是document
        //document.onkeyup = function (e) {
       // console.log(e.keyCode);可以打印出来按键的code字符
    //}
     document.onkeyup = function(e){
         switch(e.keyCode){
             case 37://控制左键
             if(that.snake.direction != "right"){
                 that.snake.direction = "left"
             }
             break;
             //后面三个控制方向一样
               case 38://控制上键
             if(that.snake.direction != "bottom"){
                 that.snake.direction = "top"
             }
             break;  case 39://控制右键
             if(that.snake.direction != "left"){
                 that.snake.direction = "right"
             }
             break;  case 40://控制下键
             if(that.snake.direction != "top"){
                 that.snake.direction = "bottom"
             }
             break;
         }
     }
}
游戏开始的方法
var timer;
Game.prototype.start = function(){
    var that = this;//that存储外部this;
    timer = setInterval(function(){
    //在定时器中this是指的window对象
        that.snake.move(that.target,that.food);
        //撞墙的逻辑限制,如果蛇头的位置超出了地图,则说明暂停,停止定时器
        var head = that.snake.body[0];//蛇头
        if(head.x<0||head.x>that.target.offsetWidth/that.snake.width-1||head.y<0||head.y>that.target.offsetHeight/that.snake.height-1){
            clearInterval(timer);
            alert("已撞墙,game over");
        }
        //撞身体的判断,判断蛇头和身体位置是否重合,重合即失败
        for(var i = 3;i < that.snake.body.length;i++){
            if(head.x === that.snake.body[i].x&& head.y ===that.snake.body[i].y){
                clearInterval(timer);
                alert("撞自己,game over");
            }
        }
    },150)
}
沙箱模式封装

沙箱模式其实就是一个自调用函数
沙箱的作用,就是对代码起到保护作用,隔离作用

(function(window,undefined){
    var a = 10;
    var b = 100;
    function Food(){
    }
    //将Food暴露到沙箱外面
    window.Food = Food;
})(window)
var food = new Food();

运用了;(function(){})();函数自调用隔离,前后加分号用来防止前后结束,习惯。
+ 传参的必要性:
如果在沙箱中使用的沙箱外部的内容,那么就必须将内容以传参的形式传递到沙箱中进行使用
+ 原因:
+ 可以实现逻辑上的隔离
+ 有利于代码压缩

代码压缩

将所有不必要的空格和换行全部移除,将所有的变量全部重新命名成单个字母的形式,有利于代码压缩

tip:最后将所有的构造函数封装起来

//Food,命名新建food.js,以调用
;(function(window,undefined){
    function Food(options){
    options = options||{};
    this.width = options.width||20;
    this.height = options.height||20;
    this.bgColor = options.bgColor||"blue"
    this.x = options.x||0;
    this.y = options.y||0;
}
    Food.prototype.render = function(target){
    //创建一个div
    var div = document.createElement("div");
    target.appendChild(div);
    //设置div的一些样式 width height 背景色 left top
    div.style.width = this.width+"px";
    div.style.height = this.height+"px";
    div.style.backgroundColor = this.bgColor;
    //设置div的left值与top值
    //this.x是0-800/20之间的随机数
    this.x = parseInt(Math.random()*target.offsetWidth/this.width);
    this.y = parseInt(Math.random()*target.offsetHeight/this.height);
    div.style.left = this.x*this.width+"px";
    div.style.top = this.y*this.height+"px";
    div.style.position = "absolute";
}
window.Food = Food;
})(window);
//蛇部,命名snake.js以调用
    ;(function(window,undefined){
        function Snake(options){
    options = options||{};
    this.width = options.width ||20;
    this.height = options.height ||20;
    this.headColor = options.headColor ||"blue";
    this.bodyColor = options.bodyColor||"pink";
    //蛇的核心,蛇是由一个个小方块组成,默认蛇是由三个小方块组成
    this.body = [
        {x:2,y:0,bgColor:this.headColor},
        {x:1,y:0,bgColor:this.bodyColor},
        {x:0,y:0,bgColor:this.bodyColor}
    ];
    this.direction = "right";
}
//蛇旋渲染
Snake.prototype.render = function(target){
    for(var i = 0;i<this.body.length;i++){
        var span = document.createElement("span");
        target.appendChild(span);
        span.style.width = this.width+"px";
        span.style.height = this.height+"px";
        span.style.backgroundColor = this.body[i].bgColor;
        span.style.position = "absolute";
        span.style.left = this.body[i].x*this.width+"px";
        span.style.top = this.body[i].y*this.height+"px";
    }
}
//蛇部移动
Snake.prototype.move = function(target,food){
//移动的思路:
    //1. 移动蛇的身体
    //2. 根据方向移动蛇头
    //3. 删除整条蛇
    //4. 重新渲染这条蛇
    for (var i = this.body.length-1;i>0;i--){//控制蛇尾的变化
    //蛇尾开始变为上一个块儿,可以不用记录上一个块儿的位置,更加方便,蛇尾是数组的第一个值
    this.body[i].x = this.body[i-1].x;
    this.body[i].y = this.body[i-1].y;
    }
    switch(this.direction){//控制蛇头的方向和变化
    //记录一个方向条件,判断,方向的的变化控制x的增减或y,改蛇头
        case "right":
        this.body[0].x++;
        break;
        case "left":
        this.body[0].x--;
        break;
        case "top":
        this.body[0].y--;
        break;
        case "bottom":
        this.body[0].y++;
        break;
    }
        var head = this.body[0];
        var last =this.body[this.body.length - 1];
    //用于蛇的身体加长,吃food,改变蛇的自身
    //1. 判断蛇头的位置与食物的位置是否重合。
    //2. 把移动前的那个蛇尾位置push到body中,添加蛇尾的思想
    //3. 把原先的食物删除
    //4. 重新渲染一个新的食物
     if(head.x === food.x && head.y === food.y){
            this.body.push({
                x:last.x,
                y:last.y,
                bgColor:this.bodyColor
            });
        //删除食物,让食物重新渲染
        var div = target.querySelector("div");
        target.removeChild(div);
        food.render(target);
        }

    //去除所有的span标签
    var spans =target.querySelectorAll("span");
    for(var i = 0;i < spans.length;i++){
    target.removeChild(spans[i]);
    }
    //删除之后重新显现
    this.render(target);
}
    window.Snake = Snake;
    })(window);
//游戏对象封装,命名Game.js以调用
;(function(window,undefined){
    function Game(target){
    this.target = target;
    this.snake = new Snake();
    this.food = new Food();
    //初始化游戏
    this.init();
}
Game.prototype.init = function(){
    //渲染蛇和食物
    this.snake.render(this.target);
    this.food.render(this.target);
    var that = this;
    //由于在下面的函数中要使用当前函数中的this
    //但是下面的函数中有自己的this,如果直接用this,是访问不到我们这个函数中的this的
    //所以我们声明一个新的变量that 将当前函数中的this赋值给这个that
    //that和this的值就是相同的了
    //在下面的函数中我们就可以使用that来访问到当前函数中的this了!
        //onkeyup事件只能给有焦点的东西注册,或者是document
        //document.onkeyup = function (e) {
        //console.log(e.keyCode);可以打印出来按键的code字符
       //}
     document.onkeyup = function(e){
         switch(e.keyCode){
             case 37://控制左键
             if(that.snake.direction != "right"){
                 that.snake.direction = "left"
             }
             break;
             //后面三个控制方向一样
               case 38://控制上键
             if(that.snake.direction != "bottom"){
                 that.snake.direction = "top"
             }
             break;  case 39://控制右键
             if(that.snake.direction != "left"){
                 that.snake.direction = "right"
             }
             break;  case 40://控制下键
             if(that.snake.direction != "top"){
                 that.snake.direction = "bottom"
             }
             break;
         }
     }
}
var timer;
Game.prototype.start = function(){
    var that = this;//that存储外部this;
    timer = setInterval(function(){
    //在定时器中this是指的window对象
        that.snake.move(that.target,that.food);
        //撞墙的逻辑限制,如果蛇头的位置超出了地图,则说明暂停,停止定时器
        var head = that.snake.body[0];//蛇头
        if(head.x<0||head.x>that.target.offsetWidth/that.snake.width-1||head.y<0||head.y>that.target.offsetHeight/that.snake.height-1){
            clearInterval(timer);
            alert("已撞墙,game over");
        }
        //撞身体的判断,判断蛇头和身体位置是否重合,重合即失败
        for(var i = 3;i < that.snake.body.length;i++){
            if(head.x === that.snake.body[i].x&& head.y ===that.snake.body[i].y){
                clearInterval(timer);
                alert("撞自己,game over");
            }
        }
    },150)
}
window.Game = Game;
})(window);

封装完毕调用
找地图对象作为参数放入封装的代码中

var map = document.getElementById("map");
var g = new Game(map);
g.start();//可以用个按钮装起来,开始。
//好了,开始玩贪吃蛇吧。
  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
利用面向对象的方法,实现贪吃蛇。 1. 利用面向对象的思想实现——一个食物对象、一个蛇对象、一个游戏总控对象。 2. 在使用××.prototype= {}重写原型对象的时候,一定要加上一句constructor:该对象。不然会造成实例化出来的实例的constructor为object。 3. 在underscore中,使用_.random(a,b)即可获得a-b中的一个随机数。 4. 在求食物的随机位置的时候,用到了panel.clientHeight/this.height - 1) * this.height。 原理是使用盒子的高度/小球的高度,可以算得最多放多少个小球。因为要控制小球不能超过边界,所以总数量要减去1,数量×高度即为随机位置的最大值。 5. 在蛇对象中,用body数组存放蛇身体每一个部分对象。蛇的绘制过程就是遍历body,在面板上绘制。 6. 蛇的移动分为两部分。 ① 蛇节移动到前一个蛇节的位置。直到蛇头后一个蛇节移动到蛇头的位置。 ② 根据direction判断蛇头如何移动。 注意:在游戏绘制的过程中,界面的每一次绘制都要**删除**之前的绘制,不然会叠加到一起。 7. 在蛇的闭包中建一个局部数组,存储蛇对象,可以更加方便的删除操作。 8. 只有在原型对象中的方法和属性,外界是可以调用的。 9. 蛇的移动(动画)必然需要定时器协助。定时器的时间,即象征着刷新速度,也就是难度。 10. this所在的函数在哪一个对象中,this就指向谁。单独写一个函数的时候,如果调用之前对象的this,需要备份指针(将对象的this赋值给另一个变量)。 11. JavaScript原生的键盘按下事件(keydown) 中,事件有一个keyCode属性,其值代表按下的键。其中:37—left、38—top、39—right、40—bottom。 12. 边界控制。通过判断蛇头与最大X和Y的关系,判断是否碰到边界。 13. confirm()方法用于显示一个带有指定消息和确认及取消按钮的对话框。 14. window.location.reload(); 重新加载当前文档 15. window.close() 方法用于关闭浏览器窗口。 16. 与食物的碰撞检测:如果蛇头和食物坐标重叠,将蛇尾添加到body中。并重新绘制一个食物点,将之前的食物删掉。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值