TypeScript实现贪吃蛇游戏

news/2024/10/17 22:16:28/

TS实现贪吃蛇游戏

文章目录

    • TS实现贪吃蛇游戏
    • @[toc]
      • 1.项目效果
      • 2.项目梳理
      • 3.项目准备
      • 4.主体页面结构
      • 5.CSS样式
      • 6.TS逻辑
        • 6.1 食物逻辑
        • 6.2 蛇逻辑
        • 6.3 记分板逻辑
        • 6.4 游戏控制器逻辑
        • 6.5 程序入口ts

1.项目效果

项目体验

在这里插入图片描述

2.项目梳理

这个小游戏主要包括积分面板,食物,蛇,还有我们的游戏控制器这四个部分,分为四个类来写。

3.项目准备

  • 1.项目环境

    • node环境
    • 采用webpack进行打包
    • 采用less进行书写样式表
    • ts用来编写逻辑
  • 2.项目配置

    • package.json

      {"name": "demo","version": "1.0.0","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","build": "webpack","start": "webpack serve"},"author": "","license": "ISC","keywords": [],"description": "","devDependencies": {"@babel/core": "^7.21.8","@babel/preset-env": "^7.21.5","babel-loader": "^9.1.2","clean-webpack-plugin": "^4.0.0","core-js": "^3.30.2","css-loader": "^6.7.4","html-webpack-plugin": "^5.5.1","less": "^4.1.3","less-loader": "^11.1.0","postcss": "^8.4.23","postcss-loader": "^7.3.0","postcss-preset-env": "^8.4.1","style-loader": "^3.3.3","ts-loader": "^9.4.3","typescript": "^5.0.4","webpack": "^5.83.1","webpack-cli": "^5.1.1","webpack-dev-server": "^4.15.0"}
      }
    • tsconfig.json

      {"compilerOptions": {"module": "es2015","target": "es2015","strict": true,"sourceMap": false,//当有错误时不生成编译后文件"noEmitOnError": true},"include": ["./src/**/*"],"exclude": ["node_modules"]
      }
      
    • webpack.config.js 打包配置

      //引入一个包
      const path = require("path");
      //引入html插件
      const HTMLWebpackPlugin = require("html-webpack-plugin")
      //引入编译清除上一次文件插件
      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}},// mode: 'development',// 设置modemode: 'production',// 设置mode//指定webpack打包时要使用的模块module: {//指定要加载的规则rules: [{//test指定的是规则生效的文件test: /\.ts$/,//要使用的loaderuse: [//配置babel 适配更多浏览器{//指定加载器loader: "babel-loader",//设置babeloptions: {//设置预定义的环境presets: [[//指定环境的插件"@babel/preset-env",//配置信息{targets: {"chrome": 88,},//指定corejs的版本"corejs": "3",//使用core js的方式"usage"表示按需加载"useBuiltIns": "usage"}]]}}, "ts-loader"],//要排除的文件exclude: /node-modules/},//设置less文件的处理{test: /\.less$/,use: ["style-loader","css-loader",//引入postcss{loader: "postcss-loader",options: {postcssOptions: {plugins: [["postcss-preset-env",{browsers: "last 2 versions"}]]}}},"less-loader"]}]},plugins: [new CleanWebpackPlugin(),new HTMLWebpackPlugin({// title:"这是一个自定义title"template: "./src/index.html"})],//用来设置引用模块resolve: {extensions: [".ts", ".js"]}
      }
      

4.主体页面结构

index.html

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>贪吃蛇</title></head><body><div id="main"><div class="screen"><!--设置蛇的样式--><div id="snake"><div></div><!--            <div></div>--><!--            <div></div>--><!--            <div></div>--></div><!--食物--><div id="food"><div></div><div></div><div></div><div></div></div></div><div class="count"><h4 class="countText">SCORE: <span id="score">0</span></h4><h4 class="countText">LEVEL: <span id="level">1</span></h4></div></div></body>
</html>

5.CSS样式

index.less

@backColor: #cefdb5;
* {margin: 0;padding: 0;box-sizing: border-box;
}body {//background-color: @backColor;text-align: center;padding-top: 100px;//display: flex;
}#main {display: inline-block;width: 560px;height: 620px;background-color: @backColor;border: #0e0e0e 18px solid;padding: 20px;border-radius: 40px;text-align: center;.screen {height: 415px;width: 460px;margin: 12px auto auto;border: #0e0e0e 4px solid;position: relative;#snake {& > div {width: 15px;height: 15px;background-color: #000;border: 1px @backColor solid;position: absolute;}div:first-child {background-color: #67d01b;border-radius: 4px;}}#food {width: 15px;height: 15px;//background-color: red;border: 1px @backColor solid;position: absolute;left: 40px;display: flex;flex-flow: row wrap;justify-content: space-between;align-content: space-between;& > div {width: 6px;height: 6px;background-color: #0a7142;transform: rotate(45deg);}}}.count {margin-top: 50px;padding: 0 10px;display: flex;width: 100%;flex-direction: row;justify-content: space-between;font-size: 20px;font-weight: 600;h4 {display: inline-block;}}
}

6.TS逻辑

6.1 食物逻辑

export class Food {//定义一个属性表示食物对应的元素elementD: HTMLElement;constructor(elemet: HTMLElement) {//获取页面中的元素给elementD// document.getElementById("#food")!;this.elementD = elemet;this.change()}get X() {return this.elementD.offsetLeft;}get Y() {return this.elementD.offsetTop;}//修改食物位置change() {//生成一个随机的位置// console.log(this.elementD)//食物的位置最小是 0 x 最大是460  y最大是420 390 435;let top = Math.round(Math.random() * 26) * 15let left = Math.round(Math.random() * 29) * 15;this.elementD.style.left = left + 'px'this.elementD.style.top = top + 'px'}}

6.2 蛇逻辑

我们的主角,主要逻辑难点在蛇身的移动与碰撞检验

export class Snake {//表示蛇头元素head: HTMLElement;//蛇的身体bodies: HTMLCollectionelement: HTMLElementconstructor() {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(val: number) {if (this.X == val) {return}if (val < 0 || val > 435) {throw new Error("你撞墙了")}this.head.style.left = val + "px"}set Y(val: number) {if (this.Y == val) {return}if (val < 0 || val > 390) {throw new Error("你撞墙了")}this.head.style.top = val + "px"}//蛇增加身体addBody() {this.element.insertAdjacentHTML("beforeend", `<div></div>`)}moveBody(x: number, y: number) {//遍历所有的身体 头已经改过了 不需要改for (let i = 1; i < this.bodies.length - 1; i++) {let currentEle = this.bodies[i] as HTMLElement;let x1 = parseInt(currentEle.style.left.substring(0, currentEle.style.left.indexOf("px")))let y1 = parseInt(currentEle.style.top.substring(0, currentEle.style.top.indexOf("px")))if (this.X == x1 && this.Y == y1 && i > 1) {throw new Error("你撞上了自己的身体!")}}for (let i = this.bodies.length - 1; i > 0; i--) {let houEle = this.bodies[i] as HTMLElement;let qianEle = this.bodies[i - 1] as HTMLElement;if (i == 1) {houEle.style.left = x + 'px';houEle.style.top = y + 'px';} else {houEle.style.left = qianEle.style.left;houEle.style.top = qianEle.style.top;}}}
}

6.3 记分板逻辑

export class ScorePanel {score: number = 0;level: number = 1;scoreEle: HTMLElement;levelEle: HTMLElement;MaxLevel:number;UpScore:number;constructor(scoreEle: HTMLElement, levelEle: HTMLElement,maxLevel:number=10,upScore:number=5) {this.scoreEle = scoreEle;this.levelEle = levelEle;this.MaxLevel=maxLevel;this.UpScore=upScore;}addScore() {this.score++;this.scoreEle.innerHTML = this.score + ""if (this.score%this.UpScore==0){this.addLevel()}}addLevel() {if (this.level >= this.MaxLevel) {return}this.level++;this.levelEle.innerHTML = this.level + ""}}

6.4 游戏控制器逻辑

整个游戏的运行与控制逻辑都在这里,里面有按键触发逻辑等,是用来调度蛇与食物和记分板的一个控制类

//游戏控制器import {Food} from "./Food";
import {Snake} from "./Snake";
import {ScorePanel} from "./ScorePanel";export class GameControl {food: Food;snake: Snake;scorePanel: ScorePaneldirection: string = ""time: anyisLive: boolean = trueconstructor(food: Food, scorePanel: ScorePanel, snake: Snake) {this.food = food;this.snake = snake;this.scorePanel = scorePanel;this.init();this.run();}init() {//banging键盘按下的事件document.addEventListener("keydown", this.keydownHandler.bind(this))}/***    ArrowUp*    ArrowDown*     ArrowLeft*     ArrowRight*/keydownHandler(event: KeyboardEvent) {let a = " ArrowUp ArrowDown ArrowLeft ArrowRight "let b = "wasd"let key = event.key;if (a.indexOf(" " + key + " ") != -1 || b.indexOf(key) != -1) {// console.log(event.key)//上的时候不可以按下//左的时候不可以按右switch (this.direction) {case "ArrowUp":case "Up":case "w":switch (key) {case "ArrowDown":case "Down":case "s":return;}breakcase "ArrowDown":case "Down":case "s":switch (key) {case "ArrowUp":case "Up":case "w":return;}breakcase "ArrowLeft":case "Left":case "a":switch (key) {case "ArrowRight":case "Right":case "d":return;}breakcase "ArrowRight":case "Right":case "d":switch (key) {case "ArrowLeft":case "Left":case "a":return;}break}this.direction = event.key// this.run()}}/*** 蛇移动方法**/run() {//获取蛇现在的坐标let x = this.snake.X;let y = this.snake.Y;let x1 = this.snake.X;let y1 = this.snake.Y;switch (this.direction) {case "ArrowUp":case "Up":case "w":// 向上移动top减少y -= 15;break;case "ArrowDown":case "Down":case "s":y += 15break;case "ArrowLeft":case "Left":case "a":x -= 15break;case "ArrowRight":case "Right":case "d":x += 15break;}try {this.snake.X = x;this.snake.Y = y;//判断是否吃到食物this.checkEat(x, y);this.snake.moveBody(x1, y1)} catch (e: any) {this.isLive = falsealert(e.message)return}// console.log(x, y)if (this.time && this.isLive) {clearTimeout(this.time)}this.time = setTimeout(this.run.bind(this), 250 - (this.scorePanel.level - 1) * 50)}checkEat(X: number, Y: number) {if (this.food.X == X && this.food.Y == Y) {//吃到食物了this.scorePanel.addScore()//重新刷新食物点位this.food.change()//蛇要增加一节this.snake.addBody()}}
}

6.5 程序入口ts

用来引入所有需要的模块,包括样式模块

import './style/index.less'
import {Food} from "./modules/Food";
import {ScorePanel} from "./modules/ScorePanel";
import {GameControl} from "./modules/GameControl";
import {Snake} from "./modules/Snake";let foodEle = document.getElementById("food")!;
let food = new Food(foodEle);
let scorePanel = new ScorePanel(document.getElementById("score")!,document.getElementById("level")!)let snake = new Snake();let gameControl = new GameControl(food,scorePanel,snake);

http://www.ppmy.cn/news/101910.html

相关文章

腾讯云服务器CVM和轻量应用服务器区别

关于腾讯云轻量应用服务器和云服务器CVM的区别&#xff0c;之前腾讯云百科写过一篇文章来对比&#xff0c;如今2023阿腾云又更新了一篇新的区别对比文章&#xff0c;比之前的要更加详细&#xff0c;包括轻量服务器的使用限制、CPU型号、公网限制月流量、内网连通性、硬盘存储等…

测试类型(单元、集成、系统或手动测试)

测试类型(单元、集成、系统或手动测试) 单元测试 单元是系统的单个组件&#xff0c;例如类或单个方法。孤立地测试单元称为单元测试。 优点&#xff1a;速度快/易控/易写 缺点&#xff1a;缺乏现实性/无法捕获所有错误&#xff08;例如与其他组件或服务的交互&#xff09; 单元…

Unity 反射探针

反射射探针 是用来模拟反射周边物体的光照信息的一种解决方案让物体&#xff0c;受周围物体的光照或材质进行影响的一种模拟光照效果。如下图效果&#xff1a; 反射探针属性截图 反射探针类型 Baked 烘焙模式&#xff0c;此种模式需要反射的物体是静态的不能移动&#xff0c;但…

客户案例 | 思腾合力GPU算力节点助力实时云渲染

客户介绍 平行云是国内领先的云化XR概念倡导者与技术先行者&#xff0c;LarkXR是平行云研发的云化XR PaaS平台。LarkXR能够帮助XR领域企业级客户快速实现技术、产品及平台的云化转型&#xff0c;高效使能企业的云化XR业务&#xff0c;有效保护客户的内容安全&#xff0c;让多种…

充分发挥C/C++test的价值(上)

对于开发测试来说&#xff0c;最有效的环境就是能够深度集成到开发人员IDE中的统一测试解决方案。例如&#xff0c;团队可能会将测试工作集中在最近更新的、高风险的代码上&#xff0c;而Parasoft C/Ctest这样的集成工具就是最合适的解决方案。 软件验证和确认&#xff08;Ver…

初识设计模式

设计模式的思想 来自日常生活 设计模式的好处六大原则类别创建型&#xff08;创建对象&#xff09;结构型&#xff08;构建模块之间的关系&#xff09;行为型&#xff08;交互&#xff09; 重要模式详述单例模式工厂模式抽象工厂模式建造者模式装饰器模式适配器模式代理模式迭代…

知乎新财报,商业化难题有解了?

不知从什么时候开始&#xff0c;商业化好似成为了一朵乌云&#xff0c;笼罩在内容平台头顶&#xff0c;而为摆脱这一困局&#xff0c;内容平台也是屡屡出招。作为种草内容平台的小红书&#xff0c;最近更是动作频频。比如&#xff0c;小红书先是上线了团购功能&#xff0c;入局…

机器视觉陶瓷板智能检测设备在工业质检中的应用

随着工业自动化的不断发展&#xff0c;机器视觉技术在质量控制领域中的应用越来越广泛。在陶瓷制品生产中&#xff0c;机器视觉技术可以帮助企业实现陶瓷板的智能检测&#xff0c;减少人工操作的错误率&#xff0c;提高生产效率和产品质量。本文将介绍机器视觉陶瓷板智能检测设…