ts主要注重类思想,这里贪吃蛇分为四大类:蛇、食物、分数水平、总体控制类:
其中蛇需要在吃到食物后自增一节,可以使用insertAdjacentElement()在最后插入一个节点。还需要向上下左右移动,所以需要监听键盘按键keydown事件,食物被吃到需要随机出现在另一个地方,同时蛇吃到一个食物分数加1,当吃到10个食物后,水平加1同时蛇移动的速度加快
1.食物类
//食物类Food 对象里只有:属性、值
class Food {
//定义一个属性表示食物所多对应的元素
element: HTMLElement;
constructor() {
//获取页面中的food元素并将其赋值给element
this.element = document.getElementById('food')!
}
//获取食物的xy坐标
getDistance() {
let distance = {
X: this.element.offsetLeft,
Y: this.element.offsetTop
}
return distance
}
/*
蛇移动一次就是一格,一格的大小就是10
*/
//食物改变位置(随机)
change() {
let top = Math.round(Math.random() * 29) * 10//四舍五入取整
this.element.style.left = top + 'px';
this.element.style.top = top + 'px';
}
}
export default Food
2.蛇类
class Snake {
//获取蛇的元素
head: HTMLElement;
bodies: HTMLCollection;
element: HTMLElement
constructor() {
this.element = document.querySelector('#snake')!,
this.head = document.querySelector('#snake>div')!,
this.bodies = document.getElementById('snake')!.getElementsByTagName('div')
}
//获取蛇头head坐标
getHeadDistane() {
let distance = {
X: this.head.offsetLeft,
Y: this.head.offsetTop
}
return distance
}
//设置蛇头坐标
setHeadDistance(left: number, top: number) {
this.moveBodies()
//如果蛇的走向互斥
//x的合法值 0-290
if (this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === top) {
if (left > this.getHeadDistane().X) {
console.log('往右');
left = this.getHeadDistane().X + 10
} else {
console.log('往左');
}
}
if (left < 0 || left > 290) throw new Error('蛇撞墙了')
this.head.style.left = left + 'px'
if (top < 0 || top > 290) throw new Error('蛇撞墙了')
this.head.style.top = top + 'px'
}
addSnake() {
//向element中添加一个div
let tempDiv = document.createElement('div');
this.element.insertAdjacentElement("beforeend", tempDiv)
}
//蛇身体移动
moveBodies() {
/*
将后边的身体设置为起那边身体的位置:后一节的位置等于前一节的位置
从后往前取
*/
for (let i = this.bodies.length - 1; i > 0; i--) {
//获取前边身体的位置
let X = (this.bodies[i - 1] as HTMLElement).offsetLeft;
let Y = (this.bodies[i - 1] as HTMLElement).offsetTop;
// 拿到前一个的位置后将其赋值到自己身上也就是将自己移到前一节的位置
(this.bodies[i] as HTMLElement).style.left = X + 'px';
(this.bodies[i] as HTMLElement).style.top = Y + 'px';
}
}
}
export default Snake
3.水平分数类
//计时器
class Score {
private score = 0;
level = 1;
scoreEle: HTMLElement;
levelEle: HTMLElement;
maxLevel: number;
upScore: number;
constructor(maxLevel: number = 10, upScore: number = 10) {
this.scoreEle = document.getElementById('score')!,
this.levelEle = document.getElementById('level')!,
this.maxLevel = maxLevel,
this.upScore = upScore
}
//改变分数
changeScore() {
this.scoreEle.innerHTML = ++this.score + ''
if (this.score % this.upScore === 0) {
this.changeLevel()
}
}
//改变水平
changeLevel() {
if (this.level < this.maxLevel) {
this.levelEle.innerHTML = ++this.level + ''
}
}
}
export default Score
4.总控制类
//游戏控制器 控制其他类
import Snake from './Snake'
import Food from './Food'
import Score from './Score'
class GameControl {
snake: Snake;//蛇
food: Food;//食物
score: Score;//记分
direction: string = '';//方向
isLive: boolean = true;//是否活着
constructor() {
this.snake = new Snake(),
this.food = new Food(),
this.score = new Score(),
this.init()
}
//初始化 -开始
init() {
//绑定键盘事件
document.addEventListener('keydown', this.keyDownHandle.bind(this))
this.run()
}
//键盘按下的响应事件
keyDownHandle(event: KeyboardEvent) {
console.log(event.key);
this.direction = event.key
}
//蛇移动
run() {
/* 根据方向direction让蛇移动 */
let distance = this.snake.getHeadDistane()
switch (this.direction) {
case 'ArrowUp':
case 'Up':
distance.Y -= 10
break;
case 'ArrowRight':
case 'Right':
distance.X += 10
break;
case 'ArrowLeft':
case 'Left':
distance.X -= 10
break;
case 'ArrowDown':
case 'Down':
distance.Y += 10
break;
case 'default':
this.isLive = false
}
this.checkEat(distance.X, distance.Y)
try {
this.snake.setHeadDistance(distance.X, distance.Y)
} catch (e) {
//说明出现异常
alert(e.message + 'GAME OVER')
this.isLive = false
}
//开始定时调用
this.isLive && setTimeout(this.run.bind(this), 200 - (this.score.level - 1) * 30)
}
//检查蛇是否吃到食物
checkEat(X: number, Y: number) {
if (X === this.food.getDistance().X && Y === this.food.getDistance().Y) {
//吃到食物,食物位置发生改变 分数增加 蛇增加一节
this.food.change()
this.score.changeScore()
this.snake.addSnake()
}
}
}
export default GameControl