js面向对象简易贪吃蛇

js面向对象简易贪吃蛇

1.贪吃蛇.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        
        .container {
            width: 600px;
            height: 600px;
            border: 1px solid #ccc;
            margin: 0 auto;
        }
    </style>
</head>

<body>
//创建一个贪吃蛇活动的范围
    <div class="container"></div>
    //引入各个js文件
    <script src="js/Game.js"></script>
    <script src="js/Map.js"></script>
    <script src="js/Snake.js"></script>
    <script src="js/Food.js"></script>
    <script>
    //获得贪吃蛇活动的范围
        var container = document.querySelector('.container');
        //创建map实例对象 传入地图的宽高  行列数
        var map = new Map(container.clientWidth, container.clientHeight, 20, 20);
        //创建蛇实例对象
        var snake = new Snake();
        //创建食物实例对象
        var food = new Food(7, 5);
        //创建游戏实例对象 传入贪吃蛇活动的范围 以及地图 蛇 食物三个实例对象
        var g = new Game(container, map, snake, food);
    </script>
</body>

</html>

2.map.js

function Map(width, height, row, col) {
//获取容器的宽高 行数 列数
    this.width = width;
    this.height = height;
    this.row = row;
    this.col = col;
    //创建地图
    this.div = document.createElement('div');
    //二维数组接收行和列
    this.arr = [];
    //行数组接收行
    this.rowArr = [];
    //初始化行数
    this.init();
}
Map.prototype.init = function() {
    this.fill();
    this.addStyle();
}
//构建架构的函数
Map.prototype.fill = function() {
//循环行数创建行
    for (var i = 0; i < this.row; i++) {
        var rowElement = document.createElement("div");
        rowElement.className = "row";
        //将创建出来的行添加到存放行的数组中
        this.rowArr.push(rowElement);
        //创建一个空数组存放列
        var colArr = [];
        //循环列数  创建列
        for (var j = 0; j < this.col; j++) {
            var colElement = document.createElement("div");
            colElement.className = "col";
            //将创建出来的列添加到数组中
            colArr.push(colElement)
            //将列添加到行中
            rowElement.appendChild(colElement);
        }
        //将存放列的数组添加到数组中  最终生成一个二维数组
        this.arr.push(colArr);
        //地图添加每一行
        this.div.appendChild(rowElement);
    }
    // console.log(this.arr);
    // console.log(this.rowArr);
}
//渲染样式
Map.prototype.addStyle = function() {
//地图占据容器百分之百
    var divStyle = {
        width: '100%',
        height: '100%'
    }
    for (var i in divStyle) {
        this.div.style[i] = divStyle[i];
    }
    //每一行的样式
    var rowStyle = {
        width: '100%',
        height: 100 / this.row + '%',
        borderBottom: '1px solid #ccc',
        boxSizing: 'border-box'
    }
    for (var i in rowStyle) {
        this.rowArr.forEach(item => {
            item.style[i] = rowStyle[i];
        })
    }
    //最后一行不需要下边框
    var rowArrLength = this.rowArr.length - 1;
    this.rowArr[rowArrLength].style.borderBottom = 'none';
	//每一列的样式
    var colStyle = {
        width: 100 / this.col + '%',
        height: '100%',
        borderRight: '1px solid #ccc',
        boxSizing: 'border-box',
        float: 'left'
    }
    //遍历二维数组
    this.arr.forEach(item => {
        item.forEach(value => {
            for (var i in colStyle) {
                value.style[i] = colStyle[i]
            }
        })
        //最后一列不需要右边框
        var colLength = item.length - 1;
        item[colLength].style.borderRight = 'none'
    })

}
//清除整个地图中蛇占据的位置
Map.prototype.clear = function() {
    this.arr.forEach(item => {
        item.forEach(value => {
            value.style.backgroundColor = 'white'
        })
    })
}

3.game.js

function Game(container, map, snake, food) {
    //获取存放地图的容器 已经地图对象 蛇对象 食物对象
    this.container = container;
    this.map = map;
    this.snake = snake;
    this.food = food;
    //初始化函数
    this.init();
    //游戏开始与结束的标志位
    this.flag = true;
}
Game.prototype = {
    constructor: Game,
    init() {
        this.renderMap();
        this.renderSnake();
        this.startMove();
        this.changeDirection();
    },
    //渲染地图
    renderMap() {
        //将map实例创建出来的地图渲染到存放地图的容器中
        this.container.appendChild(this.map.div);
    },
    //渲染食物
    renderFood() {
        let { x, y } = this.food;
        this.map.arr[x][y].style.backgroundColor = "pink";
    },
    //渲染蛇
    renderSnake() {
        this.snake.arr.forEach(({ x, y }) => {
            this.map.arr[x][y].style.backgroundColor = "red"
        })
    },
    //蛇运动的函数
    startMove() {
        //定义定时器让蛇一直运动
        this.timer = setInterval(() => {
            //改变蛇的位置的数组
            this.snake.move();
            //当蛇运动的时候  也不断地检测是否触发事件
            this.check();
            //当游戏是否开启的标志位为false时  游戏结束
            if (!this.flag) {
                return;
            }
            //清除地图上蛇的样式 再重新渲染蛇
            this.map.clear();
            //渲染蛇
            this.renderSnake();
            //渲染食物
            this.renderFood();
        }, 500)
    },
    //按键事件
    changeDirection() {
        //将相应的按键码传递给snake中改变蛇方向的函数
        document.addEventListener('keypress', (e) => {
            // console.log(e.key);
            switch (e.key) {
                case "w":
                case "a":
                case 's':
                case "d":
                    this.snake.switchDirection(e.key);
                    break;
            }
        });
    },
    //检测事件
    check() {
        //当蛇撞到墙的时候
        this.touchWall();
        //当蛇吃到食物的时候
        this.eat();
        //当蛇自己吃自己的时候
        this.eatSelf();
    },
    //撞墙事件
    touchWall() {
        //得到当前蛇头的位置
        let { x, y } = this.snake.arr.slice(-1)[0];
        //当蛇头的位置小于或大于当前行数列数的时候  就游戏结束时
        if (x < 0 || y < 0 || x >= this.map.row || y >= this.map.col) {
            this.gameOver();
        }
    },
    //游戏结束事件
    gameOver() {
        //将游戏是否开启的标志位置为false
        this.flag = false;
    },
    //吃到食物的事件
    eat() {
        //得到当前蛇头的位置
        let snakeHeadX = this.snake.arr.slice(-1)[0].x;
        let snakeHeadY = this.snake.arr.slice(-1)[0].y;
        //得到当前食物的位置
        let { x, y } = this.food;
        //当蛇头的位置和食物的位置相同时 代表着吃到了食物
        if (x === snakeHeadX && y === snakeHeadY) {
            //让蛇长大
            this.snake.growUp();
            //重新渲染食物
            this.resetFood();
        }

    },
    //重新渲染食物
    resetFood() {
        //重新给一个食物的位置
        let x = parseInt(Math.random() * this.map.row);
        let y = parseInt(Math.random() * this.map.col);
        //判断重新生成的食物的位置是不是与当前蛇的位置重合
        let isExist = this.snake.arr.some(value => {
            return value.x === x && value.y === y;
        });
        //重合的话  再重新渲染食物
        if (isExist) {
            this.resetFood();
            return;
        }
        //将重新得到的位置给到食物
        this.food.x = x;
        this.food.y = y;
    },
    //吃自己的事件
    eatSelf() {
        //得到当前蛇的头部的位置
        let { x, y } = this.snake.arr.slice(-1)[0];
        //得到当前除了蛇头蛇其他部位的位置
        let otherArr = this.snake.arr.slice(0, -1);
        //判断蛇头的位置是否与蛇身的位置重合
        let isExist = otherArr.some((item) => {
            return x === item.x && y === item.y
        });
        //重合的话  游戏结束
        if (isExist) {
            this.gameOver();
        }
    }

}

4.food.js

function Food(x, y) {
    //x y是食物的位置
    this.x = x;
    this.y = y;
}

5.snake.js

function Snake() {
    //arr是蛇的位置
    this.arr = [{ x: 3, y: 3 }, { x: 3, y: 4 }, { x: 3, y: 5 }, { x: 3, y: 6 }];
    //蛇的方向
    this.direction = "R";
    //蛇是否转向完成的标志位
    this.flag = true;
}
//move的本质是重新给this.arr数组赋值
Snake.prototype.move = function() {
    //删除数组的第一位
    this.arr.shift();
    let newHead = {
            ...this.arr[this.arr.length - 1],
        }
        //根据当前方向  决定添加头部的位置
    if (this.direction === "R") {
        newHead.y++;

    } else if (this.direction === "L") {
        // 如果方向是向左 y - 1
        newHead.y--;

    } else if (this.direction === "U") {
        // 如果方向是向上 x - 1;
        newHead.x--;

    } else if (this.direction === "D") {
        // 如果方向是向下 x + 1
        newHead.x++
    }
    //添加数组的第一位
    this.arr.push(newHead);
    //将可以转向变为true
    this.flag = true;
}
Snake.prototype.switchDirection = function(keyChar) {
    //当转向还没有完成的时候
    if (!this.flag) {
        return;
    }
    //当键盘按下对应的按键且当前的方向不为反方向的话  若为反方向就会自己吃自己
    if (keyChar == 'w' && this.direction != 'D') {
        this.direction = 'U';
    } else if (keyChar == 'a' && this.direction != 'R') {
        this.direction = "L";
    } else if (keyChar == 's' && this.direction != 'U') {
        this.direction = "D";
    } else if (keyChar == 'd' && this.direction != 'L') {
        this.direction = "R"
    }
    //将可否转向的标志位置为false
    this.flag = false;
};
//蛇长大的事件
Snake.prototype.growUp = function() {
    //得到蛇尾部的位置
    let newTail = {
        ...this.arr[0]
    }
    console.log(newTail);
    //将蛇尾部的位置  添加到数组中
    this.arr.unshift(newTail);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
利用面向对象的方法,实现贪吃蛇。 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中。并重新绘制一个食物点,将之前的食物删掉。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值