本项目使用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),所以食物的坐标必须是整10
let 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 = true
constructor(){
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 Down
ArrowLeft Left
ArrowRight Right
*/
keydownHandler(event:KeyboardEvent){
// 修改direction的属性
this.direction = event.key
}
// 创建一个控制蛇移动的方法
run(){
// 获取蛇现在的坐标
let X = this.snake.X
let Y = this.snake.Y
switch(this.direction){
case "ArrowUp":
case "Up":
// 向上移动 top减少
Y -= 10
break;
case "ArrowDown":
case "Down":
// 向下移动 top增加
Y += 10
break;
case "ArrowLeft":
case "Left":
// 向左移动 left减少
X -= 10
break;
case "ArrowRight":
case "Right":
// 向左移动 left减少
X += 10
break;
}
// 检查蛇是否吃到了食物
this.checkEat(X,Y)
// 修改蛇的值
try{
this.snake.X = X
this.snake.Y = Y
}catch (e) {
console.log(e,'1212')
// 进入catch,捕获异常,弹出信息
alert(e + 'GOME OVER')
// 将isLIve设置为false
this.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:number
constructor(maxLevel: number = 10,upScore:number = 10){
this.scoreEle = document.getElementById("score")!;
this.levelEle = document.getElementById("level")!;
this.maxLevel = maxLevel
this.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-290
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大于旧值,则说明向右走,发生掉头,应该继续向左走
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-290
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.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 HTMLElement
if(this.X === bd.offsetLeft && this.Y === bd.offsetTop){
// 进入判断说明蛇头撞倒了身体,游戏结束
throw new Error('撞到自己了')
}
}
}
}
export default Snake