本项目使用webpack+ts所编写
下边是项目的文件目录
/src下边的index.html页面是入口文件
index.ts是引入所有的ts文件
/modules文件夹是用来存放所有类的
index.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>贪吃蛇</title>
</head>
<body><div id="main"><!-- 游戏的舞台 --><div id="stage"><!-- 设置蛇 --><div id="snake"><div></div></div><div id="food"><div></div><div></div><div></div><div></div></div></div><!-- 游戏的计分牌 --><div id="score-panel"><div>SCORE:<span id="score">0</span></div><div>level:<span id="level">1</span></div></div></div>
</body>
</html>
index.ts
import "./style/index.less"import GameControl from "./modules/GameControl"
new GameControl()
/style/less
@bg-color: #b7d4a8;// 清楚默认样式
*{padding: 0;margin: 0;box-sizing: border-box;
}
body{font: bold 20px "Courier";
}
// 设置主体样式
#main{width: 360px;height: 420px;background-color: @bg-color;margin: 100px auto ;border: 10px solid black;border-radius: 40px;display: flex;flex-flow: column;justify-content: space-around;align-items: center;#stage{width: 304px;height: 304px;border: 2px solid black;position: relative;// 设置蛇的样式#snake{&>div{width: 10px;height: 10px;background-color: #000;border: 1px solid @bg-color;// 开启绝对定位position: absolute;}}// 设置食物#food{width: 10px;height: 10px;position: absolute;left: 40px;top: 100px;display: flex;flex-flow: row wrap;justify-content: space-between;align-content: space-between;&>div{width: 4px;height: 4px;background-color: #000;transform: rotate(45deg);}}}#score-panel{width: 300px;display: flex;justify-content: space-between;}
}
/modules/Food.ts
// 定义一个食物 food类
class Food{// 定义一个属性表示食物所对应的元素element:HTMLElement;constructor () {// 获取页面中的food元素饼将其赋给element !表示一定有元素存在this.element = document.getElementById('food')!;}// 定义获取食物的x轴坐标的方法get X(){return this.element.offsetLeft}// 获取食物的y轴坐标的方法get Y(){return this.element.offsetTop}// 修改食物的一个位置change(){// 生产一个随机的位置// 食物最小的位置是0 最大是300-10=290 // 蛇移动一次就是一格(10),所以食物的坐标必须是整10let top = Math.round(Math.random()*29)*10 //0-29之间的数,然后是每10倍let left = Math.round(Math.random()*29)*10 //0-29之间的数,然后是每10倍this.element.style.top = top +'px'this.element.style.left = left +'px'}
}
export default Food
/modules/GameControl.ts
// 引入其他的类
import Food from "./Food";
import Snake from "./snake";
import ScorePanel from "./ScorePanel";// 游戏控制器,控制所有的类
class GameControl{// 定义三个属性 food:Food;snake:Snake;scorePanel: ScorePanel;// 创建一个属性用来存储蛇的移动方向(也就是按键的方向)direction:string = "";// 创建一个属性用来记录游戏是否结束isLIve = trueconstructor(){this.food = new Food()this.snake = new Snake()this.scorePanel = new ScorePanel()this.init()}// 游戏的初始化方法,调用后游戏即开始init(){document.addEventListener('keydown',this.keydownHandler.bind(this ))// 调用run方法,让蛇移动this.run()}// 创建一个键盘按下的响应函数/*ArrowUp Up ArrowDown DownArrowLeft LeftArrowRight Right*/keydownHandler(event:KeyboardEvent){// 修改direction的属性this.direction = event.key}// 创建一个控制蛇移动的方法run(){// 获取蛇现在的坐标let X = this.snake.Xlet Y = this.snake.Yswitch(this.direction){case "ArrowUp":case "Up":// 向上移动 top减少Y -= 10break;case "ArrowDown":case "Down":// 向下移动 top增加Y += 10break;case "ArrowLeft":case "Left":// 向左移动 left减少X -= 10break;case "ArrowRight":case "Right":// 向左移动 left减少X += 10 break;}// 检查蛇是否吃到了食物this.checkEat(X,Y)// 修改蛇的值try{this.snake.X = Xthis.snake.Y = Y }catch (e) {console.log(e,'1212')// 进入catch,捕获异常,弹出信息alert(e + 'GOME OVER')// 将isLIve设置为falsethis.isLIve = false}// 开启一个定时this.isLIve && setTimeout(this.run.bind(this),300 - (this.scorePanel.level - 1) * 30)}// 定义一个方法,用来检查蛇是否吃到食物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
/modules/ScorePanel.ts
// 定义计分牌
class ScorePanel{// score和level用来记录分数和等级score = 0;level = 1;// 分数和等级所在的元素,再构造函数中进行初始化scoreEle:HTMLElement;levelEle:HTMLElement;// 设置一个等级变量maxLevel:number;// 设置一个变量表示 多少分升级upScore:numberconstructor(maxLevel: number = 10,upScore:number = 10){this.scoreEle = document.getElementById("score")!;this.levelEle = document.getElementById("level")!;this.maxLevel = maxLevelthis.upScore = upScore}// 设置一个加分的方法addScore(){this.scoreEle.innerHTML = ++ this.score +'';// 判断分数是多少if(this.score % this.upScore ===0){this.levelUp()}}// 提升等级的方法levelUp(){if(this.level < this.maxLevel ){this.levelEle.innerHTML = ++ this.level +'';}}}export default ScorePanel
/modules/Snake.ts
class Snake{// 表示蛇头的元素head: HTMLElement;// 表示蛇的身体bodies:HTMLCollection;// 蛇的容器element:HTMLElement;constructor(){// 使用断言定义head的类型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}// X的值合法范围 0-290if(value <0 || value > 290){//说明蛇撞墙了throw new Error('蛇撞墙了!')}// 修改X时,是在修改水平坐标,蛇在左右移动,蛇在向左移动时,不能向右掉头,反之亦然if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === value){// 掉头了,让蛇向反向继续移动if(value > this.X){//如果新值value大于旧值,则说明向右走,发生掉头,应该继续向左走value = this.X - 10}else{value = this.X + 10}}// 移动身体this.moveBody()this.head.style.left = value +'px';// 检查有没有撞到自己this.checkHeadBody()}set Y(value:number){if(this.Y === value){return}// Y的值合法范围 0-290if(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.moveBody()this.head.style.top = value +'px';// 检查有没有撞到自己this.checkHeadBody()}// 增加蛇身体的方法addBody(){this.element.insertAdjacentHTML("beforeend","<div></div")}// 设置蛇身体移动的方法moveBody(){// 将后边的身体位置设置为前边身体的位置// 遍历获取所有的身体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;i++){let bd = this.bodies[i] as HTMLElementif(this.X === bd.offsetLeft && this.Y === bd.offsetTop){// 进入判断说明蛇头撞倒了身体,游戏结束throw new Error('撞到自己了')}}}
}export default Snake