ts编写贪吃蛇内部逻辑
这个小游戏主要包括积分面板,食物,蛇,还有我们的游戏控制器这四个部分,分为四个类来写。
创建一个食物的类(详解在代码注释):
// 定义一个食物的类
class Food{
// 属性
element:HTMLElement;
constructor(){
this.element=document.getElementById("food")!;
}
// 定义获取食物的x轴坐标
get X(){
return this.element.offsetLeft;
}
// 定义获取食物的y轴坐标
get Y(){
return this.element.offsetTop;
}
// 定义food位置的方法
change(){
// 定义food出现位置随机的数
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;
// 等级限制的变量
levelLimit:number;
// 多少分时升级的变量
upSocre:number;
// score元素标签
scoreSpan:HTMLElement;
// level元素标签
levelSpan:HTMLElement;
constructor(levelLimit:number,upSocre:number){
this.scoreSpan = document.getElementById("score")!;
this.levelSpan = document.getElementById("level")!;
this.levelLimit = levelLimit;
this.upSocre = upSocre;
}
// 增加分数方法
addScore(){
this.scoreSpan.innerHTML = ++this.score + "";
if(this.score % this.upSocre === 0){
this.addLevel();
}
}
// 增加等级的方法
addLevel(){
if(this.level < this.levelLimit){
this.levelSpan.innerHTML = ++this.level + "";
}
}
}
// 向外暴露我们的积分面板类
export default ScorePanel;
创建一个我们的主角蛇类:
class Snake{
// 表示蛇头的元素
head:HTMLElement;
// 表示蛇的身体(包括蛇头)
bodies:HTMLCollection;
// 获取蛇的容器
element:HTMLElement;
constructor(){
this.element = document.getElementById("snake")!;
this.head = document.querySelector("#snake > div") as HTMLElement;
this.bodies = this.element.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("蛇撞墙了");
}
// 判断是否发生掉头,设置x坐标,说明是在水平方向掉头,左走不能向右走,反而亦之
if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === value){
// 如果发生掉头,则不能让蛇反方向移动
if(value > this.X){
value = this.X - 10;
}else{
value = this.X + 10;
}
}
this.removeBody();
this.head.style.left = value + "px";
}
set Y(value:number){
// 判断蛇是否在移动的范围内
if(this.Y === value){
return
}
if(value < 0 || value > 290){
throw new Error("蛇撞墙了");
}
// 判断是否发生掉头,设置Y坐标,说明是在垂直方向掉头,上走不能向下走,反而亦之
if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === value){
// 如果发生掉头,则不能让蛇反方向移动
if(value > this.Y){
value = this.Y - 10;
}else{
value = this.Y + 10;
}
}
// 调用身体移动的方法
this.removeBody();
this.head.style.top = value + "px";
this.checkHeadBody();
}
// 蛇增加身体的方法
addBody(){
// 向element中添加div
this.element.insertAdjacentHTML("beforeend","<div></div>");
}
// 蛇身体移动的方法
removeBody(){
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';
}
}
// 检查蛇和身子发生碰撞的方法
checkHeadBody(){
// 获取所有身体,是否发生重叠
for(let i = 1; i <= this.bodies.length-1; i++){
let bd = this.bodies[i] as HTMLElement;
if(this.X === bd.offsetLeft && this.Y === bd.offsetTop){
throw new Error("蛇吃到自己的身体了");
}
}
}
}
// 向外暴露我们的蛇类
export default Snake;
创建我们的游戏控制器类,这个类控制我们的游戏开始或者结束:
import Snake from "./Snake";
import Food from "./Food";
import ScorePanel from "./ScorePanel";
// 游戏的控制器,控制其他的所有类
class GameControl {
// 定义三个属性
snake: Snake;
food: Food;
scorePanel: ScorePanel;
// 定义获取键盘按键的字符串
direction: String = '';
// 判斷蛇是否去世
isField:boolean = true;
constructor() {
this.snake = new Snake();
this.food = new Food();
this.scorePanel = new ScorePanel(10, 2);
this.init();
}
// 游戏开始的初始化方法
init() {
// 绑定键盘事件
// .bind() 创建一个新函数,使this指向我们的GameControl这个对象
document.addEventListener("keydown", this.keydownHandler.bind(this));
this.run();
}
// 创建一个键盘按下的响应函数
keydownHandler(event: KeyboardEvent) {
// 修改direction属性
this.direction = event.key
}
// 创建蛇动的方法
// ArrowUp Up ArrowRight Right ArrowLeft Left ArrowDown Down
run() {
let X = this.snake.X;
let Y = this.snake.Y;
switch (this.direction) {
case 'ArrowUp':
case 'Up':
Y -= 10;
break;
case 'ArrowRight':
case 'Right':
X += 10;
break;
case 'ArrowLeft':
case 'Left':
X -= 10;
break;
case 'ArrowDown':
case 'Down':
Y += 10;
break
}
try{
this.snake.X = X;
this.snake.Y = Y;
}catch(e){
// 提示蛇已经撞墙
alert("Game Over!");
// 停止移动
this.isField = false;
}
// 调用蛇吃到食物的方法
this.checkEat(X,Y);
// 蛇等级的提升移动速度的改变
this.isField && setTimeout(this.run.bind(this),300-(this.scorePanel.level-1)*30);
}
//当吃到食物,发生的系列游戏行为
checkEat(X:number,Y:number){
if(this.food.X === X && this.food.Y === Y){
// 食物位置的改变
this.food.change();
// 积分等级的改变
this.scorePanel.addScore();
// 蛇长度的改变
this.snake.addBody();
}
}
}
// 向外暴露我们的GameControl类
export default GameControl;
这样我们的蛇的基本逻辑就已经实现了,我们只需要启动我们的GameControl这个类,整个游戏就可以运行起来了。
创建一个主index.ts文件,引入我们的GameControl类,创建GameControl的实例对象:
import './style/style.less';
import GameControl from "./model/GameControl"
// 创建实例对象启动游戏
const ga = new GameControl();
效果:
这里打开我们的网页,按方向键就能开始游戏了,吃到食物后左上角有个小问题,也不是太清楚,这里为什么会闪一下,还是有待完善的地方,但是总体上还是能运行下去。