Snake game front-end development from design to run smoothly

The first thing a js Snake game Our first step is to use object-oriented approach to thinking

Object-Oriented

Here Insert Picture Description
Snake game we all know, we have to look at abstract objects Snake.
First, snake itself can be seen as a single object food randomly appear on the screen, whether it is the most primitive appears only a food or a more expanded version of food appears must be in accordance with certain rules. So the food here is also an object.

First, the food item is not associated with other objects, we first determine js food objects.

Establish food.js

/* 食物对象需要的属性,位置x,y,大小,颜色 */
function Food(options){
	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';
}
var position="absolute";
/* Food的原型对象
	render方法
	动态创建div */
Food.prototype.render =function(map){
	/* 创建div */
	var div = document.createElement('div');
	map.appendChild(div);
	/* 设置div的样式 */
	div.style.position=position;
	div.style.left=this.x+'px';
	div.style.top=this.y+'px';
	
	div.style.width=this.width+'px';
	div.style.height=this.height+'px';
	div.style.backgroundColor=this.color;
}

/* test */
var map=document.getElementById('map');
var food=new Food();
food.render(map);

About perfect index.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<link rel="stylesheet" href="css/style.css">
	</head>
	<body>
		<div id="map"></div>
		
		<script src="js/food.js"></script>
		
		
	</body>
</html>

Here we note that, after the introduction of food.js to div stated otherwise, the following may occur or limited to the following question.

报错:Uncaught TypeError: Cannot read property ‘appendChild’ of undefined

The reason for this problem is not to find the map div id module js before loading. So to remember all the js loaded on the back div declaration.

Establish a css

#map {
	width: 800px;
	height: 600px;
	background-color: red;
	position: relative;/* 相对 */
}

ok, it has been shown to be red with green on the Google browser if no problem
Here Insert Picture Description
is so hot the eye. food not yet been solved completely, how to make food appear randomly?

Random set food location

Generating a random number to the maximum value between the minimum

var Tools = {
  getRandom: function (min, max) {
    return Math.floor(Math.random() * (max - min + 1)) +  min;
  }
}

ok just our x and y position is the default, so set about x and y in div but to the (random).

Consider the boundary problem of random numbers : We are essentially random coordinates, 0:00 random coordinates can be placed food on a map, this is easier to think. Max on the border of it, first of all have their own map width and height of the first to come to us to get the width x (height and empathy y) defines food in food.js 20px width in
the width 800px map defined in the css by how much can the former is the block map discerning food placed horizontally seen, may put 40
but may be equal to max 40 it? The answer is no, because equal to 40, because we are seeking the coordinates, to expand the food, in fact, does not belong to the scope of the map.
Therefore max = 40-1 = 39

Thus we get a new representation of the x and y coordinates:

this.x=Tools.getRandom(0,map.offsetWidth/this.width-1)*this.width;
this.y=Tools.getRandom(0,map.offsetHeight/this.height-1)*this.height;

Here Insert Picture Description
Has been randomly shows, there is an important game rules: eat the food.
So after eating to randomly display, before the step by step deletion of food there

Delete food

var elements=[];//存储食物的元素

Random generation method:

var div = document.createElement('div');
	map.appendChild(div);
	/* 记录到数组中 */
	elements.push(div);
function remove(){
	for(var i=elements.length-1;i>=0;i--){
		/* 删除div  调用父元素的removeChild方法删除*/
		elements[i].parentsNode.removeChild(elements[i]);
		/* 删除数组中的数据 
		第一个参数从哪个元素开始删除
		第二个参数删除几个*/
		elements.splice(i,1);
	}
}

Since the calling function improved

First, since the purpose is to call the function to create a local scope, making follow-up calls, etc. the same name does not appear

(function(){
})()

Before writing the code into the function can be
noted here that a small problem
Food method in function of the local scope, so less external calls

/* window下的函数全局可访问,创建自调用函数之后,局部作用域使得外部的测试代码无法调用food方法 */
	window.Food=Food;

Object-Oriented Object on food is almost complete

Construction of objects snake

Rendering ideas and snake food objects objects Similarly, the orientation of the object to be prescribed snake and the body, the body with the default storage array, each element represents the body of a snake a snake section.

(function(){
	var position ='absolute';
function Snake(options){
	options=options||{};
	/* 蛇节大小和行进方向 */
	this.width =options.width||20;
	this.height=options.height||20;
	this.derection=options.derection||'right';
	/* 蛇身体 */
	this.body=[
		{x:3,y:2,color:'red'},
		{x:2,y:2,color:'blue'},
		{x:1,y:2,color:'blue'}
	];
}	


Snake.prototype.render=function(){
	for(var i=0,len =this.body.length;i<len;i++){
		var object =this.body[i];
		var div=document.createElement('div');
		map.appendChild(div);
		/* 设置postion的目的是脱离文档流 在上面新建一个var postion*/
		div.style.position=position;
		/* 设置大小 */
		div.style.width=this.width+'px';
		div.style.height=this.height+'px';
		/* 设置坐标,颜色 */
		div.style.left=object.x*this.width+'px';
		div.style.top=object.y*this.height+'px';
		div.style.backgroundColor=object.color;
	}
}

window.Snake=Snake;
})()

Here Insert Picture Description

Start js

Before the tests were added after a period of test code js, to start a js instead create a separate test code

(function(){
	function Game(map){
		/* 依赖于food和snake */
		this.food=new Food();
		this.snake=new Snake();
		this.map=map;
		
	}
	
	Game.prototype.start=function(){
		/* 把蛇和食物对象渲染到地图
		开始游戏的逻辑 */
		this.food.render(this.map);
		this.snake.render(this.map);
		
		
	}
	
	window.Game=Game;
	
})();

var map=document.getElementById('map');
var game =new Game(map);
game.start();

Game.js role is to replace the previous test code, so first of all it depends on the first two js food and snakes, can then be rendered in accordance with its render method. As before the effect of, not the drawings.

Movement control snake

Snake.prototype.move =function(){
	/* 控制蛇的身体移动 */
	/* 蛇节 */
	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;
		
	}
	/* 蛇头 */
	var head =this.body[0];
	switch(this.direction){
		case'right':
		head.x+=1;
		break;
		
		case'left':
		head.x-=1;
		break;
		
		case'top':
		head.y-=1;
		break;
		
		case'bottom':
		head.y+=1;
		break;
	}
}

Snake during the move, need to remove the snake section before moving snake.
Similarly food:

/* 私有成员函数 删除参照food*/
function remove(){
	/* 从后往前删除 */
	for(var i=elements.length-1;i>=0;i--){
		/* 删除div */
		elements[i].parentNode.removeChild(elements[i]);
		elements.splice(i,1);
	}
}

Let the snake continues to move

 // 私有的函数  让蛇移动
   function runSnake() {
     var timerId = setInterval(function () {
       // 让蛇走一格
       // 在定时器的function中this是指向window对象的
       // this.snake
       // 要获取游戏对象中的蛇属性
       that.snake.move();
       that.snake.render(that.map);

        // 2.2  当蛇遇到边界游戏结束
        // 获取蛇头的坐标
        var maxX = that.map.offsetWidth / that.snake.width;
        var maxY = that.map.offsetHeight / that.snake.height;
        var headX = that.snake.body[0].x;
        var headY = that.snake.body[0].y;
        if (headX < 0 || headX >= maxX) {
          alert('Game Over');
          clearInterval(timerId);
        }

        if (headY < 0 || headY >= maxY) {
          alert('Game Over');
          clearInterval(timerId);
        }
     }, 150);
   }

Here used that, in the var that; that = this;// 记录游戏对象already defined above, for obtaining this.

By controlling the direction of movement of the keyboard snake

   // 通过键盘控制蛇移动的方向
  function bindKey() {
    // document.onkeydown = function () {};
    document.addEventListener('keydown', function (e) {
      // console.log(e.keyCode);
      // 37 - left
      // 38 - top
      // 39 - right
      // 40 - bottom
      switch (e.keyCode) {
        case 37: 
          that.snake.direction = 'left';
          break;
        case 38:
          that.snake.direction = 'top';
          break;
        case 39:
          that.snake.direction = 'right';
          break;
        case 40:
          that.snake.direction = 'bottom';
          break;
      }
    }, false);
  }

Eat food

/* 判断蛇头是否和食物坐标重合 需要food 和map 在move方法中添加两个参数,同时game也需要添加两个参数*/
	var headX=head.x*this.width;
	var headY=head.y*this.height;
	if(headX === food.x &&headY === food.y){
		var last =this.body[this.body.length - 1];
		this.body.push({
			x:last.x,
			y:last.y,
			color:last.color
		})

Here Insert Picture Description
Here Insert Picture Description

github Portal: https://github.com/qdjiangwenhao/snake

Published 158 original articles · won praise 44 · views 30000 +

Guess you like

Origin blog.csdn.net/qq_43277404/article/details/104151069
Recommended