由于我笔记本键盘原因,为了方便我操作,将上下左右方向键设置为英文字母 I K J L
可以自己在document.onkeydown中自行修改.这篇内容是纯代码篇
分析的篇章会在后面发.
注:仅简单实现基础游戏功能,存在部分bug.功能并不完善
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script>
//要素: 地图 食物 蛇?
//步骤1:封装一个地图类
//地图的 背景 宽 高 定位:父相子绝
function Map(){
this.width = "1600px";
this.height = "800px";
this.backgroundColor = "#ebf1dd";
this.position = "relative";
//用一个属性来保存div的值,以便于后面被调用
this._map = null;
//步骤1.1:封装一个显示地图类
this.show = function(){
//创建一个div
this._map = document.createElement("div");
this._map.style.width = this.width;
this._map.style.height = this.height;
this._map.style.backgroundColor = this.backgroundColor;
this._map.style.position = this.position;
//将this._map挂载到 body中
document.body.appendChild(this._map);
}
}
//实例化地图类
var map = new Map();
//***********************************************************************************
//步骤2:封装一个食物类
//***********************************************************************************
function Food(){
this.width = "20px";
this.height = "20px";
this.backgroundColor = "#e5b9b7";
this.position = "absolute";
this.borderRadius = "100%";
this.left = 0; //初始化x坐标
this.top = 0; //初始化y坐标
//用一个属性来保存div的值,以便于后面被调用
this._food = null;
//步骤1.1:封装一个显示食物方法
this.show = function(){
//步骤3.1:判断this._food,阻止重复显示食物
if(!this._food){
//创建一个div
this._food = document.createElement("div");
this._food.style.width = this.width;
this._food.style.height = this.height;
this._food.style.backgroundColor = this.backgroundColor;
this._food.style.position = this.position;
this._food.style.borderRadius = this.borderRadius;
//将this._food追加到 map._map中,即:挂载到背景图的div中
map._map.appendChild(this._food);
}
//调用随机数方法,随机获取(x,y)坐标值
this.randPos();
//定义食物出现的坐标(x,y)
this._food.style.left = this.left*20+"px";
this._food.style.top = this.top*20+"px";
}
//步骤2.1封装一个随机数方法
this.randPos = function(){
this.left = Math.floor(Math.random()*80);
this.top = Math.floor(Math.random()*40);
}
}
//实例化食物类
var food = new Food();
//***********************************************************************************
//步骤3:定义蛇类
//***********************************************************************************
function Snake(){
this.width = "20px";
this.height = "20px";
this.position = "absolute";
this.borderRadius = "100%";
//定义蛇身体,是个二维数组
//在设置完移动后,回来添加一个数组值:null,管理自身的部分
this.body = [[25,20,"#ffc000",null],[24,20,"#fbd5b5",null],[23,20,"#fbd5b5",null]];
//封装显示蛇的方法
this.show = function(){
//因为蛇身体是一个二维数组,所以用for...of循环遍历
for(var i of this.body){
//判断是否已创建蛇身,不再重复生成
if(!i[3]){
i[3] = document.createElement("div");
i[3].style.width = this.width;
i[3].style.height = this.height;
i[3].style.position = this.position;
i[3].style.borderRadius = this.borderRadius;
i[3].style.backgroundColor = i[2];
//将创建的蛇身体div 挂载到 map 的div中
map._map.appendChild(i[3]);
}
i[3].style.left = i[0] * 20 + "px";
i[3].style.top = i[1] * 20 + "px";
}
}
//添加运动方向的属性,默认不动
this.direct = null;
//封装蛇运动的方法
this.move = function(){
//处理蛇尾移动
//获取蛇身数组,蛇身移动时,末尾一个的坐标等于前一个的坐标
// 即将尾坐标替换成它的前一个坐标
//判断,当蛇头不动时,即this.direct 为 false,则不执行蛇尾的移动
if(this.direct){
for(var i=this.body.length-1;i>0;i--){
this.body[i][0] = this.body[i-1][0]; //替换x坐标
this.body[i][1] = this.body[i-1][1]; //替换y坐标
}
}
//处理蛇头移动
switch (this.direct) {
case "up":
this.body[0][1] -= 1;
break;
case "down":
this.body[0][1] += 1;
break;
case "left":
this.body[0][0] -= 1;
break;
case "right":
this.body[0][0] += 1;
break;
}
//蛇运动后,要重新显示,所以调用this.show()方法
//判断如果出界,则不再调用这个方法
if(!(this.body[0][0] < 0 || this.body[0][0] > 79 || this.body[0][1] < 0 || this.body[0][1] > 39)){
this.show();
}
}
//封装蛇吃食物的方法
this.eat = function(){
//当食物生成在蛇身体内时,自动吃掉,积分增加
//循环变量蛇身的所有坐标,判断是否等于食物的坐标
if(this.body[0][0] == food.left && this.body[0][1] == food.top){
//坐标相等表示吃到了
//食物刷新
food.show()
//每吃一个食物,加十分.
score += 10;
//蛇身长度加一个单位
//注意:新的蛇身部分的坐标值,只要不出现在地图中,设置为几都无所谓
//原因:因为当蛇移动时,末尾的蛇身的坐标会等于前一个蛇身的坐标,所以马上会更新到贪吃蛇的尾部
this.body.push([-10,-10,"#fbd5b5",null]);
}
}
//封装蛇出界的方法
this.outLine = function(){
if(this.body[0][0] < 0 || this.body[0][0] > 79 || this.body[0][1] < 0 || this.body[0][1] > 39){
//坐标出界,游戏结束
//停止运动,即:停止定时器,使蛇不再动,并提示Game Over
clearInterval(id);
alert("不撞南墙不回头!");
alert("游戏结束,总得分:"+score+"分");
}
}
//封装蛇追尾的方法
this.eatSelf = function(){
for(var i=4;i<this.body.length;i++){
if(this.body[0][0] == this.body[i][0] && this.body[0][1] == this.body[i][1]){
//蛇头坐标等于蛇身的坐标,表示吃到自己,游戏结束
clearInterval(id);
alert("撞到自己了!");
alert("游戏结束."+"总得分:"+score+"分");
}
}
}
}
//实例化蛇类
var snake = new Snake();
//***********************************************************************************
//从这里开始执行
//***********************************************************************************
//定义全局积分变量,并初始化值为0
var score = 0;
window.onload = open;
function open(){
//设置一个h1标签计分
var h1 = document.getElementsByTagName("h1");
//调用地图类的show()方法
map.show();
//调用食物类的show()方法
food.show();
//调用蛇类的show()方法
snake.show();
//小技巧:设置一个函数,将snake.move()放入函数内,此时,move()方法的调用者就是snake了
function run(){
snake.eat();
snake.outLine();
snake.eatSelf();
snake.move();
h1[0].innerHTML = "游戏积分: <font color=red>"+score+"</font> 分" ;
}
//设置定时器调用蛇类的move()方法,让蛇一直动
id = setInterval(run,60);
//绑定键盘事件,控制蛇移动的方向,同时判断,不允许蛇回头
document.onkeydown = function(event){
switch (event.keyCode) {
case 73:
if(snake.direct != "down"){
snake.direct = "up";
}
break;
case 75:
if(snake.direct != "up"){
snake.direct = "down";
}
break;
case 74:
if(snake.direct != "right"){
snake.direct = "left";
}
break;
case 76:
if(snake.direct != "left"){
snake.direct = "right";
}
break;
case 32:
if(confirm("是否提前结束游戏?")){
clearInterval(id);
alert("游戏结束!")
alert("总得分:"+score+"分");
}
break;
}
}
}
</script>
</head>
<body>
<h1></h1>
</body>
</html>