游戏设计
对象:
1.地图
高度
宽度
原子--类似小的div
x--多少个原子
y--多少个原子
显示画布功能
2.食物
宽度--原子的大小
高度--原子的大小
功能,在地图上显示食物
3.蛇
body---头 体 尾 ---三个div(原子)
高度---原子的大小
宽度---原子的大小
功能:
1.运动
2.控制方向
3.遇到边界,游戏结束,重新开始
4.遇到食物
5.自己碰到自己,游戏结束,重新开始
4.升级规则
1.每升一级,有一个级别号
2.每升一级,速度加快
3.每升一级,挑战难度增大
业务流程实现
创建每个对象,相关使用
代码实现
html代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>贪吃蛇</title>
<script src="js/index.js"></script>
<style>
body {
margin: 0;
padding: 0;
}
#main {
margin: 100px;
}
.bnt {
width: 100px;
height: 40px;
}
.gtitle {
font-size: 25px;
font-weight: bold;
}
#gnum {
color: red;
}
</style>
</head>
<body>
<div id="main">
<h1>贪吃蛇</h1>
<input class="btn" type="button" value="开始游戏" id="begin">
<input class="btn" type="button" value="暂停游戏" id="pause">
<span class="gtitle">第<span id="gnum">1</span>关</span>
</div>
</body>
</html>
js代码:
/* !!!注意这里用的是load,不能用onload
onload可能会有元素没有加载完成,
load是等所有的元素加载完后才执行 */
window.addEventListener('load',function(){
var main = document.getElementById('main');
var showcanvas =false; //是否开启画布上的格子
/* 地图对象的构造方法
atom:原子大小 宽高一样 10
x:横向原子数量
y:纵向原子数量 */
function Map(atom, xnum, ynum) {
this.atom = atom; //20*20
this.xnum = xnum;
this.ynum = ynum;
// 声明一个画布
this.canvas = null;
// 创建画布的方法
this.create = function () {
this.canvas = document.createElement("div");
// canvas的基础样式
this.canvas.style.cssText = "position:relative;top:40px;border:1px solid darkred;background:#fafafa";
this.canvas.style.width = this.atom * this.xnum + 'px'; //画布的宽
this.canvas.style.height = this.atom * this.ynum + 'px'; //画布的高
// 给main追加子元素,就相当于把main当做父亲,然后通过main来显示this.canvas
// appendChild里面要添加的是有效节点,而不是字符串,所以不能加引号!!!
main.appendChild(this.canvas);
if (showcanvas) {
// 画出整个画布
for (var y = 0; y < ynum; y++) {
// 画一行
for (var x = 0; x < xnum; x++) {
var a = document.createElement('div');
a.style.cssText = "border:1px solid #fafafa";
a.style.width = this.atom + 'px';
a.style.height = this.atom + 'px';
a.style.backgroundColor = 'green';
// 在画布里追加a
this.canvas.appendChild(a);
a.style.position = 'absolute';
a.style.left = x * this.atom + 'px';
a.style.top = y * this.atom + 'px';
}
}
}
}
}
// 创建食物对象的构造方法,将地图对象作为参数
function Food(map) {
this.width = map.atom;
this.height = map.atom;
// 生成随机颜色的食物 floor--向下取整
this.bgcolor = 'rgb(' + Math.floor(Math.random() * 200) + ',' + Math.floor(Math.random() * 200) + ',' + Math.floor(Math.random() * 200) + ')';
// 保证食物不超出地图的范围
this.x = Math.floor(Math.random() * map.xnum);
this.y = Math.floor(Math.random() * map.ynum);
this.flag = document.createElement('div');
this.flag.style.width = this.width + 'px';
this.flag.style.height = this.height + 'px';
this.flag.style.backgroundColor = this.bgcolor;
this.flag.style.borderRadius = '50%'; //圆形的食物
this.flag.style.position = 'absolute';
this.flag.style.left = this.x * this.width + 'px';
this.flag.style.top = this.y * this.height + 'px';
// 将食物追加到地图里面
map.canvas.appendChild(this.flag);
}
// 创建蛇
function Snake(map) {
//设置宽、高
this.width = map.atom;
this.height = map.atom;
//默认走的方向
this.direction = 'right';
this.body = [
{ x: 2, y: 0 }, //蛇头
{ x: 1, y: 0 }, //蛇身
{ x: 0, y: 0 } //蛇尾
];
//显示蛇
this.display = function () {
for (var i = 0; i < this.body.length; i++) {
//当吃到食物时,x===null,不能新建食物,不然会在0,0处新建一个;当x!=null时,才创建新的食物
if (this.body[i].x != null) {
var s = document.createElement('div');
// 将蛇的节点保存到一个状态变量中,以便以后删除使用
this.body[i].flag = s;
// 设置蛇的样式
s.style.width = this.width + 'px';
s.style.height = this.height + 'px';
s.style.backgroundColor = 'rgb(' + Math.floor(Math.random() * 200) + ',' + Math.floor(Math.random() * 200) + ',' + Math.floor(Math.random() * 200) + ')';
s.style.borderRadius = '50%';
// 设置位置
s.style.position = 'absolute';
s.style.left = this.body[i].x * this.width + 'px';
s.style.top = this.body[i].y * this.height + 'px';
map.canvas.appendChild(s);
}
}
}
//让蛇运动起来
this.run = function () {
/*
0{x:2,y:0}, //蛇头
1{x:1,y:0}, //蛇身
2{x:0,y:0} //蛇尾
0 {x:2,y:0}, //蛇头
1{x:2,y:0}, //蛇身
2{x:1,y:0} //蛇尾
*/
// 将蛇前一格身体的X赋给后一格,这样蛇身整体向前挪动一格,目前蛇头位置还没变
// for循环遍历
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;
}
// 默认是向右走(right) 讨论left、up、down
// 根据方向处理蛇头
switch (this.direction) {
case 'left': this.body[0].x -= 1; //如果向左走 则蛇头为x-1(根据网页坐标系可知)
break;
case 'right': this.body[0].x += 1; //如果向右走 则蛇头为x+1(根据网页坐标系可知)
break;
case 'up': this.body[0].y -= 1; //如果向上走 则蛇头为y-1
break;
case 'down': this.body[0].y += 1; //如果向下走 则蛇头为y+1
break;
}
// 判断蛇头吃到食物,判断条件蛇头的xy和食物的xy重合
if (this.body[0].x == food.x && this.body[0].y == food.y) {
//蛇吃到食物后,加一节,在尾部加
//加入空的元素,执行run方法时,之前蛇的尾部会赋值给这个空元素
this.body.push({ x: null, y: null, flag: null });
// 判断设置级别
if(this.body.length > l.slength){
l.set();
}
map.canvas.removeChild(food.flag); //蛇吃掉食物,删除食物
food = new Food(map); //食物被吃掉后,新建一个食物
}
// 判断是否出界,蛇头来判断
if (this.body[0].x < 0 || this.body[0].x > map.xnum - 1 || this.body[0].y < 0 || this.body[0].y > map.ynum - 1) {
clearInterval(timer); //清除定时器暂停游戏
alert('game over');
// 重新开始游戏
restart(map, this);
return false; //var showcanvas = true; //是否开启画布上的格子 等于false就是不开启
}
// 判断是否和自己重合
// 为什么i是4,因为考虑到内存和效率的问题,能少循环几次就少循环几次,蛇的长度最短是3,围不成一个环
for (var i = 4; i < this.body.length; i++) {
if (this.body[0].x == this.body[i].x && this.body[0].y == this.body[i].y) {
clearInterval(timer); //清除定时器暂停游戏
alert('game over');
// 重新开始游戏
restart(map, this);
return false;
}
}
// 将原来所有的都删掉
for (var i = 0; i < this.body.length; i++) {
if (this.body[i].flag != null) { //当吃到食物,flag是等于null,且不能删除
// flag 是标记div
map.canvas.removeChild(this.body[i].flag);
}
}
this.display();
}
}
//设置级别对象
function Level() {
this.num = 1; //第几级别
this.speed = 300; //毫秒 ,每升一关,数量减少20, 速度逐渐加快
this.slength = 10; //通过判断蛇的长度,来判断关卡级别
this.set = function () {
this.num++;
if (this.speed <= 50) {
this.speed = 50;
} else {
this.speed -= 50;
}
this.slength += 3; //蛇的长度每加3个就升一关
this.display();
start(); //重新开始,速度加快
}
this.display = function () {
document.getElementById('gnum').innerHTML = this.num;
}
}
var l = new Level();
l.display();
// 重新开始游戏
function restart(map, snake) {
// 清除之前的蛇和食物
for (var i = 0; i < snake.body.length; i++) {
map.canvas.removeChild(snake.body[i].flag);
}
// 重建初始页面
snake.direction = 'right';
snake.body = [
{ x: 2, y: 0 }, //蛇头
{ x: 1, y: 0 }, //蛇身
{ x: 0, y: 0 } //蛇尾
];
snake.display();
map.canvas.removeChild(food.flag);
food = new Food(map);
}
// 给body加键盘事件,上下左右
window.onkeydown = function (e) {
var event = e || window.event; //兼容
// console.log(event.keyCode);
/* 键盘按键值:
38(up)
40(down)
39(right)
37(left)*/
switch (event.keyCode) {
case 38:
if (snake.direction != 'down') { //防止蛇直接反方向掉头
snake.direction = 'up';
}
break;
case 40:
if (snake.direction != 'up') {
snake.direction = 'down';
}
break;
case 37:
if (snake.direction != 'right') {
snake.direction = 'left';
}
break;
case 39:
if (snake.direction != 'left') {
snake.direction = 'right';
}
break;
}
}
//创建地图对象
var map = new Map(20, 40, 20);
map.create();
var food = new Food(map); //构造食物对象
var snake = new Snake(map); //构造蛇对象
snake.display();
var timer; //变量可以提升
function start() {
// 在使用之前清除定时器,保证不重复启动定时器
clearInterval(timer);
timer = setInterval(function () {
snake.run();
}, l.speed);
}
// 按下开始按钮,游戏就动起来,就是计时器启动
document.getElementById('begin').onclick = function () {
start();
}
// 按下暂停按钮,游戏就停止起来,就是计时器停止
document.getElementById('pause').onclick = function () {
// 在使用之前清除定时器,保证不重复启动定时器
clearInterval(timer);
// timer = setInterval(function () {
// }, 300);
}
})