贪吃蛇游戏-javascript
介绍
使用javascript的面向对象实现简单的贪吃蛇小游戏
分析
1. 蛇和食物都在一个容器中
2. 蛇碰到容器时游戏结束
3. 食物随机生成
4. 蛇吃食物后, 食物消失, 重新生成食物, 自身长度+1
5. 其中包含对象: 蛇, 食物, 游戏
对象分析
食物
- 属性
宽, 高, 位置, 颜色 - 方法
- 渲染食物(随即生成)
- 被吃掉时删除该食物
蛇
- 属性
高, 宽, 位置, 颜色, 运动方向, 身体 - 方法
- 渲染蛇
- 移动方法 - 蛇在移动时,包含吃的方法(当蛇头碰到食物, 删除食物, 蛇身长度+1, 重新生成食物)
游戏
- 属性
食物, 蛇, 容器 - 方法
- 蛇运动 (当蛇头碰到边界时, 游戏结束)
- 通过键盘控制移动
代码实现
- index.html页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>贪吃蛇游戏</title>
<link rel="stylesheet" type="text/css" href="css/index.css"/>
</head>
<body>
<div id="map"></div>
</body>
</html>
<script type="text/javascript" src="js/index.js" ></script>
- index.css页面样式
* {
margin: 0;
padding: 0;
}
#map {
width: 800px;
height: 600px;
background-color: darkgrey;
position: relative;
color: goldenrod
}
- index.js.
3.1 工具
3.1 食物对象// 生成固定范围内的随机整数 (function() { function getRandom(min, max) { return Math.round(min + Math.random() * (max - min)); } window.tools = { getRandom } })();
3.2 蛇对象// 使用自调用函数形式解决命名冲突问题 (function(){ // 容器 const position = 'absolute'; // 记录创建食物, 删除时使用 const foods = []; // 食物对象 function Food(options) { // 属性 x, y, width, height, color options = options || {}; this.x = options.x || 0; this.y = options.y || 0; this.width = options.width || 20; this.height = options.height || 20; this.color = options.color || 'green'; } // 渲染 删除原食物,创建新食物 Food.prototype.render = function (map) { removeFood(); // 动态创建div, 为一个食物 const div = document.createElement('div'); // 添加食物到容器中 map.appendChild(div); // 添加到食物的缓存数组中 foods.push(div); // 设置食物样式 div.style.position = position; // 随即生成食物x坐标 this.x = tools.getRandom(0, map.offsetWidth / this.width - 1) * this.width; div.style.left = this.x + 'px'; // 随即生成食物Y坐标 this.y = tools.getRandom(0, map.offsetHeight / this.width - 1) * this.height; div.style.top = this.y + 'px'; div.style.width = this.width + 'px'; div.style.height = this.height + 'px'; div.style.backgroundColor = this.color; } // 删除食物 function removeFood() { // 删除div (食物) foods.forEach(item => item.parentNode.removeChild(item)); // 清空数组 foods.splice(0, foods.length); } // 把food对象绑定到window对象中使用 window.Food = Food; })();
3.3 游戏对象//使用局部作用域防止命名冲突 (function() { const position = 'absolute'; // 记录当前创建的蛇节 const snakes = []; /** * 蛇对象 * @param {Object} options 蛇属性设置 */ function Snake(options) { options = options || {}; this.width = options.width || 20; this.height = options.height || 20; //蛇移动的方向 this.direction = options.direction || 'right'; // 蛇的身体(蛇节) 第一个元素存储蛇头 this.body = [ {x: 3, y:2, color: 'red'}, {x: 2, y:2, color: 'goldenrod'}, {x: 1, y:2, color: 'goldenrod'} ]; } /** * 渲染蛇 * @param {Object} map 渲染容器 */ Snake.prototype.render = function(map) { // 删除之前创建的蛇 removeSnake(); // 把每一个蛇节渲染到页面上 this.body.forEach(item => { const div = document.createElement('div'); map.appendChild(div); // 记录创建的蛇节 方便删除 snakes.push(div); div.style.position = position; div.style.height = this.height + 'px'; div.style.width = this.width + 'px'; div.style.left = item.x * this.width + 'px'; div.style.top = item.y * this.height + 'px'; div.style.backgroundColor = item.color; }); } /** * 蛇移动的方法 * @param {Object} food 根据食物判断是否是吃的状态 * @param {Object} map 使用该部分重新渲染食物 * @param {Object} timerId 定时器用于游戏结束 */ Snake.prototype.move = function(food, map, timerId) { // 蛇身 - 蛇节移动到上一节位置 for(let 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; } // 蛇头 - 蛇头根据方向控制移动 const snakeHand = this.body[0]; switch(this.direction) { case 'right': // 向右走 snakeHand.x += 1; break; case 'left': snakeHand.x -= 1; break; case 'up': snakeHand.y -= 1; break; case 'down': snakeHand.y += 1; break; } // 蛇头的坐标 const handX = snakeHand.x * this.width; const handY= snakeHand.y * this.height; if (handX < 0 || handX > map.offsetWidth || handY < 0 || handY > map.offsetHeight) { console.log(111) alert('GAME OVER!!!'); timerId.clearInterval(); return } if (handX === food.x && handY === food.y) { // 蛇身长度+1 const last = this.body[this.body.length - 1]; this.body.push({ x: last.x, y: last.y, color: last.color }) // 重新生成食物 food.render(map); } } /** * 删除之前创建的蛇 */ function removeSnake() { snakes.forEach(item => item.parentNode.removeChild(item)); snakes.splice(0, snakes.length); } // 绑定蛇对象到window中 window.Snake = Snake; })();
3.4 主函入口(function() { let that; // 记录当前游戏对象 方便使用 function Game(map) { this.food = new Food(); this.snake = new Snake(); this.map = map; that = this; } /** * 开始游戏 */ Game.prototype.start = function() { // 1. 渲染食物和蛇到容器中 this.food.render(this.map); // 2. 游戏逻辑 // 2-1. 蛇运动 (当蛇头碰到边界时, 游戏结束) snakeRun(); // 2-2. 通过键盘控制移动 bindKey(); } /** * 蛇移动 */ function snakeRun() { const timerId = setInterval(function() { // 蛇运动一格(该处this指向window对象, 因此使用that) this.snake.move(that.food, that.map, timerId); // 重新渲染蛇 this.snake.render(that.map); }.bind(that), 150); } /** * 注册键盘控制方向 */ function bindKey() { document.addEventListener('keydown', function(e) { switch(e.keyCode) { case 38: this.snake.direction = 'up'; break; case 40: this.snake.direction = 'down'; break; case 37: this.snake.direction = 'left'; break; case 39: this.snake.direction = 'right'; break; } }.bind(that), false);// false事件冒泡 } // 绑定game对象到windows对象中 window.Game = Game; })();
(function() { const map = document.getElementById('map'); const game = new Game(map); game.start(); })();
总结
到此为止贪食蛇简单demo就告以段落, 本代码使用javascript面向对象的思想实现, 其中不足之处众多, 欢迎大家指点