欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 能源 > TypeScript学习案例(1)——贪吃蛇

TypeScript学习案例(1)——贪吃蛇

2025/5/9 18:45:39 来源:https://blog.csdn.net/2401_87291474/article/details/147743558  浏览:    关键词:TypeScript学习案例(1)——贪吃蛇

预览:

贪吃蛇

第一章:项目搭建

1、创建一个名为 practice 文件夹

2、配置文件

2.1 package.json

{"name": "practice","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","build": "webpack","start": "webpack serve --open chrome.exe"},"keywords": [],"author": "","license": "ISC","devDependencies": {"@babel/core": "^7.27.1","@babel/preset-env": "^7.27.1","babel-loader": "^8.4.1","clean-webpack-plugin": "^3.0.0","core-js": "^3.42.0","html-webpack-plugin": "^4.5.0","ts-loader": "^8.4.0","typescript": "^4.9.5","webpack": "^5.99.7","webpack-cli": "^4.10.0","webpack-dev-server": "^3.11.3"}
}

2.2 tsconfig.json

{"compilerOptions": {"module": "ES2015","target": "ES2015","strict": true,"noEmitOnError": false}
}

2.3 webpack.config.js

// 引入一个包
const path = require('path');
// 引入html插件
const HTMLWebpackPlugin = require('html-webpack-plugin');
// 引入clean插件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');// webpack中的所有的配置信息都应该写在module.exports中
module.exports = {// 指定入口文件entry: "./src/index.ts",// 指定打包文件所在目录output: {// 指定打包文件的目录path: path.resolve(__dirname, 'dist'),// 打包后文件的文件filename: "bundle.js",// 告诉webpack不使用箭头environment:{arrowFunction: false}},// 指定webpack打包时要使用模块module: {// 指定要加载的规则rules: [{// test指定的是规则生效的文件test: /\.ts$/,// 要使用的loaderuse: [// 配置babel{// 指定加载器loader:"babel-loader",// 设置babeloptions: {// 设置预定义的环境presets:[[// 指定环境的插件"@babel/preset-env",// 配置信息{// 要兼容的目标浏览器targets:{"chrome":"58","ie":"11"},// 指定corejs的版本"corejs":"3",// 使用corejs的方式 "usage" 表示按需加载"useBuiltIns":"usage"}]]}},'ts-loader'],// 要排除的文件exclude: /node-modules/}]},// 配置Webpack插件plugins: [new CleanWebpackPlugin(),new HTMLWebpackPlugin({// title: "这是一个自定义的title"template: "./src/index.html"}),],// 用来设置引用模块resolve: {extensions: ['.ts', '.js']}};

3、下载依赖:在终端输入 npm i

4、配置less依赖

  1. 在终端输入 npm i -D less less-loader css-loader style-loader
  2. 更改 webpack.config.js 配置文件的 module 下的 rules 后增加以下内容
//设置less文件处理{test: /\.less$/,use: ["style-loader","css-loader","less-loader"]}

5、配置 postcss 依赖

  1. npm i -D postcss postcss-loader postcss-preset-env
  2. 更改 webpack.config.js 配置文件,在设置 less 文件处理中的 “css-loader”, 后加入
//引入postcss{loader:"postcss-loader",options:{postcssOptions:{plugins:[["postcss-preset-env", {browsers: "last 2 versions"}]]}}},

6、打包: npm run build

第二章:项目界面

1、 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>

2、 index.less(记得在index.ts内引入样式)

//设置变量
@bg-color: #b7d4a8;// 清除默认样式
* {margin: 0;padding: 0;box-sizing: border-box;
}body{font: bold 20px "Courier New";
}// 设置主窗口样式
#main {width: 360px;height: 420px;background-color: @bg-color;margin: 100px auto;border: 10px solid black;border-radius: 20px;// 设置主窗口的子元素为弹性布局display: flex;// 设置主轴的方向flex-flow: column;// 设置侧轴的对齐方式align-items: center;// 设置主轴的对齐方式justify-content: space-around;}// 设置游戏舞台样式
#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-wrap: wrap;justify-content: space-between;align-content: space-between;&>div {width: 4px;height: 4px;background-color: #555;}}
}// 设置游戏得分样式
#score-panel {width: 304px;display: flex;justify-content: space-between;
}

3、效果

在这里插入图片描述

第三章:完成类的定义

1、创建 moduls 文件夹,用于装不同的类

2、完成 Food 类

//定义食物链Food
class Food {// 定义一个属性表示食物所对应的食物element : HTMLElementconstructor() {this.element = document.getElementById("food")!}// 定义一个方法,获取食物的坐标get X() {return this.element.offsetLeft}get Y() {return this.element.offsetTop}// 修改食物的位置change() {// 生成一个随机位置// 食物的位置最小是0,最大是290// 蛇移动一次就是一格,一格的大小是10,所以食物的坐标必须是10的倍数let top = Math.round(Math.random() * 29) * 10let left = Math.round(Math.random() * 29) * 10this.element.style.left = left + "px"this.element.style.top = top + "px" }
}//测试代码
// const food = new Food()
// console.log(food.X, food.Y)
// food.change()
// console.log(food.X, food.Y)export default Food

3、完成 ScorePanel 类

// 表示记分牌的类
class ScorePanel {// 定义一个属性表示分数score = 0// 定义一个属性表示等级level = 1scoreEle : HTMLElementlevelEle : 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 + ""}}
}//测试代码
// const scorePanel = new ScorePanel()
// scorePanel.addScore()
// scorePanel.addScore()
// scorePanel.addScore()
// scorePanel.addScore()
// console.log(scorePanel.score)export default ScorePanel

4、初步完成 Snake 类

class Snake {// 定义一个属性表示蛇的头部head : HTMLElement// 定义一个属性表示蛇的身体(包括蛇头)bodies : HTMLCollection// 获取蛇的容器element : HTMLElementconstructor() {// querySelector 只会取一个 就取的是第一个this.head = document.querySelector("#snake > div") as HTMLElement;this.bodies = document.getElementById("snake")!.getElementsByTagName("div")this.element = document.getElementById("snake")!}// 获取蛇的坐标get X() {return this.head.offsetLeft;}get Y() {return this.head.offsetTop;}//设置蛇的坐标set X(value : number) {// 如果蛇的坐标和value相等,则不进行设置if(this.X === value) {return}this.head.style.left = value + "px"}  set Y(value : number) {// 如果蛇的坐标和value相等,则不进行设置if(this.Y === value) {return}this.head.style.top = value + "px"}// 添加蛇的身体addBody() {this.element.insertAdjacentHTML("beforeend", "<div></div>")}
}export default Snake

第四章:游戏控制器

1、创建 GameControl.ts

2、GameControl 键盘控制

import Snake from "./Snake";
import Food from "./Food";
import ScorePanel from "./ScorePanel";//游戏控制器,控制其他所有类
class GameControl {// 定义三个属性snake : Snakefood : FoodscorePanel : ScorePanel// 创建一个属性来存储蛇的移动方向(默认是向右移动)direction : string = "Right"constructor() {this.snake = new Snake()this.food = new Food()this.scorePanel = new ScorePanel()this.init()}// 创建一个方法来初始化游戏init() {// 绑定键盘按下的事件document.addEventListener("keydown", this.keydownHandler.bind(this))}/*ArrowUp Up wArrowDown Down sArrowLeft Left aArrowRight Right d*/// 创建一个键盘按下的响应函数keydownHandler(event : KeyboardEvent) {this.direction = event.key}}export default GameControl

3、GameControl 使蛇移动

    // 创建一个属性用来记录游戏是否结束isLive : boolean = true// 创建一个控制蛇移动的方法run() {//  获取蛇现在的坐标let X = this.snake.Xlet Y = this.snake.Y// 根据方向来移动switch (this.direction) {case "ArrowUp":case "Up":case "w":Y -= 10;break;case "ArrowDown":case "Down":case "s":Y += 10;break;case "ArrowLeft":case "Left":case "a":X -= 10;break;case "ArrowRight":case "Right":case "d":X += 10;break;}this.snake.X = Xthis.snake.Y = Y// 设置定时调用this.isLive && setTimeout(this.run.bind(this), 300 - (this.scorePanel.level - 1) * 30)}

4、蛇撞墙和吃食检测

4.1 蛇撞墙

4.1.1 在 Snack 类的设置蛇的坐标内判断并的抛出异常

	//设置蛇的坐标set X(value : number) {// 如果蛇的坐标和value相等,则不进行设置if(this.X === value) {return}// x 的值的合法范围是 0-290if(value < 0 || value > 290) {throw new Error("撞墙了")}this.head.style.left = value + "px"}  set Y(value : number) {// 如果蛇的坐标和value相等,则不进行设置if(this.Y === value) {return}// y 的值的合法范围是 0-290if(value < 0 || value > 290) {throw new Error("撞墙了")}this.head.style.top = value + "px"}

4.1.2 在 GameControl 类内捕获异常

			this.snake.X = Xthis.snake.Y = Y

修改为

// 检查蛇是否撞墙try {this.snake.X = Xthis.snake.Y = Y} catch (e) {// 如果蛇撞墙了,则游戏结束alert(e.message)this.isLive = false}

4.2 蛇吃食

4.2.1 在检查蛇是否撞墙之前检查蛇是否吃到食物

		// 检查蛇是否吃到食物this.checkEat(X, Y)

4.2.2 在 GameControl 内定义方法

	// 定义一个方法,用来检查蛇是否撞墙checkEat(X : number, Y : number) {if(X === this.food.X && Y === this.food.Y) {this.snake.addBody()this.food.change()this.scorePanel.addScore()}   }

5、蛇的身体移动

5.1 在 Snack 内添加一个方法

// 添加一个蛇身体移动的方法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';}}

5.2 在 set X()和 set Y()内引用 moveBody 方法并处理掉头

//设置蛇的坐标set X(value : number) {// 如果蛇的坐标和value相等,则不进行设置if(this.X === value) {return}// x 的值的合法范围是 0-290if(value < 0 || value > 290) {throw new Error("撞墙了")}// 判断蛇是否掉头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"}  set Y(value : number) {// 如果蛇的坐标和value相等,则不进行设置if(this.Y === value) {return}// y 的值的合法范围是 0-290if(value < 0 || value > 290) {throw new Error("撞墙了")}// 判断蛇是否掉头if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === value) {// 如果发生掉头,让蛇反方向继续移动if(value > this.Y) {//如果新值value大于旧值,则说明蛇在向下走,此时应该发生掉头,应该使蛇向左走value = this.Y - 10} else {value = this.Y + 10}}this.moveBody()this.head.style.top = value + "px"}

6、 检查碰撞自己

6.1 定义一个 checkBody 方法

// 检查头和身体相撞checkBody() {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("撞到自己了")}}}

6.2 在set X()和 set Y()的最后引用方法

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词