js写个简单的贪吃蛇案例,用于复习一下js的原型链呀还有闭包沙箱知识等.
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>标题</title>
<style>
.map {
width: 800px;
height: 600px;
background-color: #cccccc;
position: relative;
top: 0px;
left: 0px;
}
</style>
</head>
<body>
<div class="map" id="map"></div>
<script src="Food.js"></script>
<script src="Snake.js"></script>
<script src="Game.js"></script>
<script>
var map1 = document.getElementById("map");
var game1 = new Game(map1);
game1.start();
上面代码是贪吃蛇的静态页面,也是我们js入口函数位置.这里主要写了地图的样式.
(function (window) {
var that = null;
function Game(map){
this.snake = new Snake();
this.food = new Food();
this.map = map;
that = this;
}
Game.prototype.start = function () {
this.snake.render(this.map);
this.food.render(this.map);
snakeAutoMove();
bindKey();
}
function snakeAutoMove(){
var timerId = setInterval(function () {
this.snake.move(this.food,this.map);
this.snake.render(this.map);
var snakeHeadX = this.snake.body[0].x * this.snake.width;
var snakeHeadY = this.snake.body[0].y * this.snake.height;
if(snakeHeadX < 0 || snakeHeadY < 0 || snakeHeadX >= this.map.offsetWidth || snakeHeadY >= this.map.offsetHeight ){
alert("Game Over!");
clearInterval(timerId);
}
}.bind(that),400);
}
function bindKey(){
window.onkeydown = function (e) {
e = e || window.event;
switch (e.keyCode){
case 37:
if(this.snake.direction != "right"){
this.snake.direction = "left";
}
break;
case 38:
if(this.snake.direction != "bottom"){
this.snake.direction = "top";
}
break;
case 39:
if(this.snake.direction != "left"){
this.snake.direction = "right";
}
break;
case 40:
if(this.snake.direction != 'top'){
this.snake.direction = "bottom";
}
break;
}
}.bind(that);
}
window.Game = Game;
}(window));
Game.js主要写我们游戏的主逻辑代码,这里我们写了游戏控制器对象的构造函数,同时创建Food,Snake,并传入Map,
因为这三者就是我们游戏的三大要素,游戏逻辑都围绕这三者展开,写好我们的start方法,调用此方法就开始我们的游戏,
还有一些别的方法,都跟另外两个js文件有关系,在这不赘述,仅对一些比较重要的部分做一些说明.
(function (w){
var list = [];
function Food(width,height,bgColor){
this.width = width || 20;
this.height = height || 20;
this.bgColor = bgColor || "green"
}
Food.prototype.render = function (map) {
remove(map);
this.x = Math.floor(Math.random()*map.offsetWidth/this.width)*this.width;
this.y = Math.floor(Math.random()*map.offsetHeight/this.height)*this.height;
var div1 = document.createElement("div");
div1.style.position = "absolute"
div1.style.left = this.x+"px";
div1.style.top = this.y+"px";
div1.style.width = this.width + "px";
div1.style.height = this.height+"px";
div1.style.backgroundColor = this.bgColor;
map.appendChild(div1);
list.push(div1);
}
function remove(map){
for(var i = 0 ; i < list.length; i++){
map.removeChild(list[i]);
}
list.length = 0;
}
w.Food = Food;
}(window));
Food.js主要是对Food对象的创建,还有对应的方法的撰写,主要用到Food的render渲染方法,因为每一次吃掉食物或者是初始化的
时候都要调用这个函数产生新的食物,产生新食物还要调用remove方法删去之前的旧食物.
(function (window) {
function getColorForRandom(){
var arr = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'];
var str = "#";
for(var i = 0 ; i < 6; i++){
var num = Math.floor(Math.random()*16);
str += arr[num];
}
return str;
}
var list = [];
function Snake(width,height,direction){
this.width = width || 20;
this.height = height || 20;
this.direction = direction || "right";
this.body = [
{x:3,y:1,bgColor:'red'},
{x:2,y:1,bgColor:'green'},
{x:1,y:1,bgColor:'purple'},
];
}
Snake.prototype.render = function (map) {
remove(map);
for(var i = 0 ; i < this.body.length; i++){
var snakeUnit = this.body[i];
var div1 = document.createElement("div");
div1.style.position = "absolute";
div1.style.left = snakeUnit.x * this.width + "px";
div1.style.top = snakeUnit.y * this.height+"px";
div1.style.width = this.width + "px";
div1.style.height = this.height + "px";
div1.style.backgroundColor = snakeUnit.bgColor;
map.appendChild(div1);
list.push(div1);
}
}
function remove(map){
for(var i = 0 ; i < list.length; i++){
map.removeChild(list[i]);
}
list.length = 0;
}
Snake.prototype.move = function (food,map) {
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){
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 snakeHeadX = this.body[0].x * this.width;
var snakeHeadY = this.body[0].y *this.height;
var foodX = food.x;
var foodY = food.y;
var lastSnakeUnit = this.body[this.body.length-1];
if(snakeHeadX == foodX && snakeHeadY == foodY){
this.body.push({
x:lastSnakeUnit.x,
y:lastSnakeUnit.y,
bgColor:getColorForRandom()
});
food.render(map);
}
}
window.Snake = Snake;
}(window));
Snake.js创建蛇对象,这里渲染函数还有删除函数就不赘述了,move函数是游戏逻辑的重要部分,我们控制我们的蛇移动,
除了蛇头部分,可以把蛇的身体分成一节一节的,那么观察很容易得知,蛇每移动一步,后一节的部分,总会等于上一节的位置,
所以我们用一个循环就可以解决了,剩下蛇头的部分,我们可以通过switch方法来控制,这里面还有一个重要的逻辑就是,
贪吃蛇玩法的特点之一,就是蛇吃了食物之后会变成蛇身体的一部分(也就是蛇身变长),所以,move方法需要做一个检测,
也就是当蛇头的坐标等于食物的坐标时,即判定为吃到食物,此时,蛇身就会变长,观察得知,吃了食物后,蛇多出来的那一节,
就是蛇最后一节身体的部分.