效果预览
项目结构
共有Food,GameControl,ScorePanel,Snake四个类
食物类
//食物类
class Food {
//食物所对应的元素
element: HTMLElement;
constructor() {
this.element = document.getElementById('food');
}
//获取食物位置的方法
get X() {
return this.element.offsetLeft;
}
get Y() {
return this.element.offsetTop;
}
//食物位置的修改
change() {
//生成随机位置
//0~290的随机数,一格是10px
//Math.round(Math.random() * 29) * 10
let Left = Math.round(Math.random() * 29) * 10;
let Top = Math.round(Math.random() * 29) * 10;
this.element.style.left = Left + 'px';
this.element.style.top = Top + 'px';
}
}
export default Food;
记分牌类
记分牌只需要控制自己的分数增长和等级提高
/**
* 记分牌
*/
class ScorePanel {
//分数和等级
score = 0;
level = 1;
scoreEle: HTMLElement;
leveEle: HTMLElement;
//等级限制
maxLevel: number;
//多少分升级
upLevel: number;
constructor(maxLevel: number = 10, upLevel: number = 10) {
this.scoreEle = document.getElementById('score');
this.leveEle = document.getElementById('level');
this.maxLevel = maxLevel;
this.upLevel = upLevel;
}
//分数增加方法
addScore() {
this.scoreEle.innerHTML = ++this.score + '';
//每10分升1级
if(this.score % this.upLevel == 0) {
this.addLevel();
}
}
//等级提升
addLevel() {
if(this.level < 10) {
this.leveEle.innerHTML = ++this.level + '';
}
}
}
export default ScorePanel;
蛇类
蛇类最主要的是身体如何根据蛇头来改变位置
这里是对蛇身体除了蛇头进行遍历,将前一个div的位置赋值给后一个div的位置
/**
* snake
*/
class Snake {
//蛇头
head: HTMLElement;
//蛇身体
bodies: HTMLCollection;
//蛇的容器
element: HTMLElement;
constructor() {
this.element = document.getElementById("snake");
this.head = document.querySelector("#snake > div") as HTMLElement;
this.bodies = document.getElementById("snake").getElementsByTagName("div");
}
//获取蛇头的坐标
get X() {
return this.head.offsetLeft;
}
get Y() {
return this.head.offsetTop;
}
//给蛇头坐标赋值
set X(value: number) {
if (this.X === value) {
return;
}
if (value < 0 || value > 290) {
throw new Error("游戏结束");
}
if (
this.bodies[1] &&
value === (this.bodies[1] as HTMLElement).offsetLeft
) {
if (value > this.X) {
value = this.X - 10;
} else {
value = this.X + 10;
}
}
this.bodyMove();
this.head.style.left = `${value}px`;
this.checkHead();
}
set Y(value: number) {
if (this.Y === value) {
return;
}
if (value < 0 || value > 290) {
throw new Error("游戏结束");
}
if (this.bodies[1] && value === (this.bodies[1] as HTMLElement).offsetTop) {
if (value > this.Y) {
value = this.Y - 10;
} else {
value = this.Y + 10;
}
}
this.bodyMove();
this.head.style.top = `${value}px`;
this.checkHead();
}
//蛇的身体增加
addBody() {
this.element.insertAdjacentHTML("beforeend", "<div></div>");
}
bodyMove() {
//遍历到除了蛇头意外的div
for (let i = this.bodies.length - 1; i > 0; i--) {
//获取前一个div的位置
let preX = (this.bodies[i - 1] as HTMLElement).offsetLeft;
let preY = (this.bodies[i - 1] as HTMLElement).offsetTop;
//将前一个的位置赋值给当前div的位置
(this.bodies[i] as HTMLElement).style.left = `${preX}px`;
(this.bodies[i] as HTMLElement).style.top = `${preY}px`;
}
}
//检查蛇头有没有撞到自己
checkHead() {
for(let i = 1; i < this.bodies.length; i++) {
let bd = (this.bodies[i] as HTMLElement);
if(this.X === bd.offsetLeft && this.Y === bd.offsetTop) {
throw new Error("蛇撞到自己的身体了");
}
}
}
}
export default Snake;
整个游戏控制类
import Food from "./Food";
import ScorePanel from "./ScorePanel";
import Snake from "./Snake";
//游戏控制器
class GameControl {
//蛇
snake: Snake;
food: Food;
scorePanel: ScorePanel;
//存储蛇的移动方向
direction: string;
//记录游戏是否结束
isLive: boolean = true;
constructor() {
this.snake = new Snake();
this.food = new Food();
this.scorePanel = new ScorePanel(10, 2);
this.init();
}
//初始化
init() {
document.addEventListener("keydown", this.keyDownHandler.bind(this));
this.run();
}
keyDownHandler(event: KeyboardEvent) {
//判断按键是否合法
this.direction = event.key;
}
//让蛇移动的方法
run() {
let X = this.snake.X;
let Y = this.snake.Y;
switch (this.direction) {
case "ArrowUp":
Y -= 10;
break;
case "ArrowDown":
Y += 10;
break;
case "ArrowLeft":
X -= 10;
break;
case "ArrowRight":
X += 10;
break;
}
//检查蛇是否吃到食物
this.checkEat(X, Y);
try {
this.snake.X = X;
this.snake.Y = Y;
} catch (err) {
alert(err);
this.isLive = false;
}
this.isLive &&
setTimeout(this.run.bind(this), 300 - (this.scorePanel.level - 1) * 50);
}
checkEat(x: number, y: number) {
if (x === this.food.X && y === this.food.Y) {
this.food.change();
this.scorePanel.addScore();
this.snake.addBody();
}
}
}
export default GameControl;