已实现功能
- 键盘可控制蛇移动方向,并且蛇无法反向
- 蛇头触碰边界即游戏结束
- 蛇吃食物会身体增长
- 蛇吃到自己身体即游戏结束
- 根据分数增长会升级蛇的样式,也会加快移动速度,增加游戏难度
Html部分
body部分
<div class="container"></div>
<div class="score">
<h3>Score:<span>0</span></h3>
<h4>等级:<span>1</span></h4>
</div>
CSS样式部分
<style>
*{
margin: 0;
padding: 0;
}
.container {
width: 680px;
height: 680px;
border: 1px solid;
background: lightgrey;
margin: 0 auto;
position: relative;
}
.score{
width: 80px;
background: lightgrey;
position: fixed;
top: 10px;
left: 320px;
text-align: center;
height: 60px;
line-height: 30px;
}
</style>
JavaScript部分
获取元素
let containerEle = document.querySelector('.container');
let scoreSpan = document.querySelector('h3 span');
let gradeSpan = document.querySelector('h4 span');
蛇类
class Snake {
constructor() {
//创建身体数组
this.body = [];
this.createBody();
// 设置蛇移动的初始方向为right
this.dir = "ArrowRight";
this.nowDir = "ArrowRight";
//设置初始分数和等级
this.score = 0;
this.grade = 1;
}
// 创建蛇的头和身体
createBody() {
for (let i = 0; i < 5; i++) {
// 1 -- 0
// 2 -- 20
// 3 -- 40
let rect;
// body的最后一个方块为蛇头,蛇头颜色设置为red,身体为orange
if (i == 4) {
rect = new Rect(20 * i, 0, "red");
} else {
rect = new Rect(20 * i, 0, "orange");
}
// 将每个小方块push进body
this.body.push(rect);
}
}
// 渲染Dom
renderDom(containerEle) {
// 接收container元素
this.containerEle = containerEle;
// 将body中的每个方块添加到Dom中
this.body.forEach(rect => {
rect.addDom(containerEle);
})
}
// 蛇移动的方法
move() {
// 先移动蛇头一个距离,删除最后一个蛇的身体,在之前蛇头的位置添加一个身体
// 把最后一个方块设为蛇头
let head = this.body[this.body.length - 1];
// 取之前蛇头位置的x和y
let numX = parseInt(head.ele.style.left);
let numY = parseInt(head.ele.style.top);
// 创建新方块
let rect = new Rect(numX, numY, "orange");
rect.addDom(this.containerEle);
// 放在之前蛇头的位置上
this.body.splice(this.body.length - 1, 0, rect);
// 若此次键盘输入this.dir与上次输入this.nowDir相反,则继续沿着原方向移动,不反向
if((this.dir == "ArrowRight"&& this.nowDir == "ArrowLeft") || (this.dir == "ArrowLeft" && this.nowDir == "ArrowRight")|| (this.dir == "ArrowUp" && this.nowDir == "ArrowDown")|| (this.dir == "ArrowDown" && this.nowDir == "ArrowUp")){
this.dir = this.nowDir;
}else{
this.dir = this.dir;
}
// 根据this.dir接收的键盘方向进行移动
switch (this.dir) {
case 'ArrowRight':
// 以20px为单位进行移动
head.ele.style.left = numX + 20 + "px";
this.nowDir = "ArrowRight";
break;
case 'ArrowLeft':
head.ele.style.left = numX - 20 + "px";
this.nowDir = "ArrowLeft";
break;
case 'ArrowUp':
head.ele.style.top = numY - 20 + "px";
this.nowDir = "ArrowUp";
break;
case 'ArrowDown':
head.ele.style.top = numY + 20 + "px";
this.nowDir = "ArrowDown";
break;
default:
console.log("请按方向键");
break;
}
// 检测蛇头是否与食物碰撞
// 调用crash函数判断
if (crash(head.ele, food.food.ele)) {
// 若碰撞,删除food元素,创建新food
food.food.ele.remove();
food = new Food();
food.food.addDom(this.containerEle);
// 积分+1 并显示在页面
this.score++;
scoreSpan.innerHTML = this.score;
} else {
// 把蛇尾(数组的第一个元素)删除从页面删除
let obj = this.body[0];
obj.ele.remove();
// 把this.body里的对象删除;
this.body.shift();
}
// 检测蛇头是否碰撞自己身体
let eat = false; // 设置eat代表是否吃到自己身体
// 和除了头之外的每个方块检测
for(let i = 0;i<this.body.length-1;i++){
if(crash(head.ele,this.body[i].ele)){
eat = true;
}
}
// 若碰到自己身体,则游戏结束
if(eat){
// 先清除之前的定时器
clearInterval(t1);
alert('Game Over!');
}
// 根据分数升级和改变蛇样式
if (this.score == 5) {
// 蛇头设成红橘相间条纹状
head.ele.style.background = 'linear-gradient(red 0%, red 20%, orange 20%, orange 40%, red 40%, red 60%, orange 60%, orange 80%, red 80%, red 100%)';
// 等级变为2
gradeSpan.innerHTML = 2;
// 清除之前的定时器,再设置新的定时器加快移动速度
clearInterval(t1);
controlSpeed(100);
}
if (this.score == 10) {
head.ele.style.background = 'linear-gradient(black 0%, black 20%, orange 20%, orange 40%, black 40%, black 60%, orange 60%, orange 80%, black 80%, black 100%)';
gradeSpan.innerHTML = 3;
clearInterval(t1);
controlSpeed(80);
}
// 检测蛇头是否出界
var headX = parseInt(head.ele.style.left) + parseInt(head.ele.clientWidth);
var headY = parseInt(head.ele.style.top) + parseInt(head.ele.clientHeight);
// 获取容器(地图)宽高
var conW = parseInt(this.containerEle.clientWidth);
var conH = parseInt(this.containerEle.clientHeight);
// 若snake出界,则游戏结束
if (headX == 0 || headX > conW || headY == 0 || headY > conH) {
clearInterval(t1);
alert('Game Over!');
}
}
}
食物类
class Food {
constructor() {
// 食物在地图内随机出现
let x = this.randomNum();
let y = this.randomNum();
// 依照x和y值产生红色的食物
this.food = new Rect(x, y, "red");
// 调用自身类内的方法
this.isAppearBody();
}
// 检测食物是否出现在蛇身体上
isAppearBody(){
// 跟身体的每个方块都检测
for (let i = 0; i < snake.body.length; i++) {
// 若碰撞,则再次产生随机数
if (crash(this.food.ele, snake.body[i].ele)) {
x = this.randomNum();
y = this.randomNum();
// 把之前的食物删掉,对象内food属性重新赋予新方块
this.food.ele.remove();
this.food = new Rect(x, y, "red");
}
}
}
randomNum(){
// 以20为单位产生随机数
return Math.max(0, parseInt(Math.random() * 33)) * 20;
}
}
小方块类
class Rect {
constructor(snakeX, snakeY, color) {
// 在dom中创建一个div
this.ele = document.createElement('div');
this.ele.style.width = "20px";
this.ele.style.height = "20px";
// 定位
this.ele.style.position = "absolute";
// 根据接收的color设置方块的颜色
this.ele.style.background = color;
this.ele.style.left = snakeX + 'px';
this.ele.style.top = snakeY + 'px';
}
// 将div添加到地图中
addDom(containerEle) {
containerEle.appendChild(this.ele);
}
}
控制速度函数
let t1;
// 参数为定时器间隔时间,可调用时自行传参设置
function controlSpeed(delay){
t1 = setInterval(function () {
// 每隔delay蛇移动一次
snake.move();
}, delay)
}
检测碰撞函数
function crash(ele1, ele2) {
// 元素1的数据
var AminX = ele1.offsetLeft; // 元素1相对于父级left的偏移量
var AmaxX = ele1.offsetLeft + ele1.offsetWidth; // 偏移量+元素1的宽度(包括边框)
var AminY = ele1.offsetTop;
var AmaxY = ele1.offsetTop + ele1.offsetHeight;
// 元素2的数据
var BminX = ele2.offsetLeft;
var BmaxX = ele2.offsetLeft + ele2.offsetWidth;
var BminY = ele2.offsetTop;
var BmaxY = ele2.offsetTop + ele2.offsetHeight;
if (AmaxX > BminX && AminX < BmaxX && AmaxY > BminY && AminY < BmaxY) {
return true;
} else {
return false;
}
}
根据 蛇类 和 食物类 实例化对象 snake 和 food
let snake = new Snake();
// 将snake渲染到dom中
snake.renderDom(containerEle);
let food = new Food();
// 向地图中添加食物方块
food.food.addDom(containerEle);
// 给蛇设置初始移动速度:每200毫秒移动一个单位
controlSpeed(200);
键盘事件:获取键盘按下的按键
document.onkeydown = function (e) {
let key = e.key;
// 将获取的键盘按键名赋给snake中的dir属性
snake.dir = key;
}
[Gitee源码](Month2/Day05/html/snake(melon).html · Muskmelon/HTML5 - 码云 - 开源中国 (gitee.com))