如何使用typeScript实现贪吃蛇游戏?

news2024/11/27 22:36:46
1.配置文件

image-20221212153711209

配置文件写过一次之后,可以复制粘贴使用,修改部分细节就可以了。
package.json

{
  "name": "snake",
  "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.12.9",
    "@babel/preset-env": "^7.12.7",
    "babel-loader": "^8.2.2",
    "clean-webpack-plugin": "^3.0.0",
    "core-js": "^3.8.0",
    "css-loader": "^5.0.1",
    "html-webpack-plugin": "^4.5.0",
    "less": "^3.12.2",
    "less-loader": "^7.1.0",
    "postcss": "^8.1.13",
    "postcss-loader": "^4.1.0",
    "postcss-preset-env": "^6.7.0",
    "style-loader": "^2.0.0",
    "ts-loader": "^8.0.11",
    "typescript": "^4.1.2",
    "webpack": "^5.6.0",
    "webpack-cli": "^4.2.0",
    "webpack-dev-server": "^3.11.0"
  }
}

tsconfig.json

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

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,
            const: false
        }
    },
    // 指定webpack打包时要使用模块
    module: {
        // 指定要加载的规则
        rules: [
            {
                // test指定的是规则生效的文件
                test: /\.ts$/,
                // 要使用的loader
                use: [
                     // 配置babel
                     {
                         // 指定加载器
                         loader:"babel-loader",
                         // 设置babel
                         options: {
                             // 设置预定义的环境
                             presets:[
                                 [
                                     // 指定环境的插件
                                     "@babel/preset-env",
                                     // 配置信息
                                     {
                                         // 要兼容的目标浏览器
                                         targets:{
                                             "chrome":"58",
                                             "ie":"11"
                                         },
                                         // 指定corejs的版本
                                         "corejs":"3",
                                         // 使用corejs的方式 "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"
                ]
            }
        ]
    },

    // 配置Webpack插件
    plugins: [
        new CleanWebpackPlugin(),
        new HTMLWebpackPlugin({
            // title: "这是一个自定义的title"
            template: "./src/index.html"
        }),
    ],

    // 用来设置引用模块
    resolve: {
        extensions: ['.ts', '.js']
    }

};

然后使用命令:npm install 下载依赖

然后创建 src 文件夹 创建index.html文件和index.ts文件

然后使用命令:npm run build 打包

下载样式解析器:npm i -D less less-loader css-loader style-loader

下载postcss做样式兼容:npm i -D postcss postcss-loader postcss-preset-env

在webpack.config.js做如下配置:

            // 设置less文件的处理
            {
                test: /\.less$/,
                use:[
                    "style-loader",
                    "css-loader",

                    // 引入postcss
                    {
                        loader: "postcss-loader",
                        options: {
                            postcssOptions:{
                                plugins:[
                                    [
                                        "postcss-preset-env",
                                        {
                                            browsers: 'last 2 versions'
                                        }
                                    ]
                                ]
                            }
                        }
2.搭建基础样式和结构

image-20221212154053119

src/index.html

<body>
    <div id="main">
        <!-- 游戏舞台 -->
        <div id="stage">
            <!-- 设置蛇 -->
            <div id="snake">
                <!-- 蛇体 -->
                <div></div>
                <!-- 食物 -->
                <div id="food">
                    <div></div>
                    <div></div>
                    <div></div>
                    <div></div>
                </div>
            </div>
        </div>
        <!-- 设置游戏记分牌 -->
        <div id="score-panel">
            <div>
                SCORE:<span id="score">0</span>
            </div>
            <div id="level">
                LEVEL:<span id="level"></span>1</span>
            </div>
        </div>
    </div>
</body>

src/style/index.less

//设置变量
@bg-color: #b7d4a8;

//清除默认样式
* {
  margin: 0;
  padding: 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: 15px;
  display: flex;
  // flex-flow: column;
  flex-direction: column;
  align-items: center;
  justify-content: space-around;
}

// 游戏舞台样式
#stage {
  width: 304px;
  height: 304px;
  border: 2px solid black;
  position: relative;
  // margin: 10px auto;
  // 设置蛇的样式
  #snake {
    & > div {
      width: 10px;
      height: 10px;
      background-color: black;
      border: 1px solid @bg-color;
      position: absolute;
    }
  }
  //   设置食物
  #food {
    width: 10px;
    height: 10px;
    position: absolute;
    left: 50px;
    top: 80px;

    display: flex;
    flex-flow: row wrap;
    justify-content: space-between;
    align-content: space-between;

    & > div {
      width: 4px;
      height: 4px;
      background-color: red;
      transform: rotate(45deg);
    }
  }
}

//游戏记分牌
#score-panel {
  width: 300px;
  display: flex;
  flex-direction: row;
  justify-content: space-around;
}

image-20221212154000151

3.实现food类

Food.ts

//定义食物类
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() {
      //随机生成
      //舞台长度是300,食物的位置最小是0,最大是290
      //蛇移动一次是一格,一格是10,所以要求食物的距离是整10
      let top = Math.round(Math.random() * 29) * 10; //round向上取整,取得到1
      let left = Math.round(Math.random() * 29) * 10;
  
      this.element.style.left = left + "px";
      this.element.style.top = top + "px";
    }
  }

  export default Food;
4.实现scorePanel类

scorePanel.ts

//定义记分牌类
class scorePanel {
    //分数和等级
    score = 0;
    level = 1;
    //分数和等级所在的元素,在构造函数中进行优化
    scorefile: HTMLElement;
    levelEle: HTMLElement;
  
    //设置一个变量限制等级
    maxLevel: number;
    //设置一个变量表示多少分升一级
    upScore:number;
  
    constructor(maxLevel: number = 10,upScore:number=10) {
      this.scorefile = document.getElementById("score")!;
      this.levelEle = document.getElementById("level")!;
      this.maxLevel = maxLevel;
      this.upScore=upScore;
    }
  
    //设置一个加分的方法
    addScore() {
      //使积分自增
      this.score++;
      this.scorefile.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;

index.ts

import "./style/index.less";
import Food from "./moduls/Food";
import scorePanel from "./moduls/ScorePanel";
5.初步完成snake类

Snake.ts

class Snake{
    //表示蛇头的元素
    head:HTMLElement;
    //表示蛇身体(包括蛇头)
    bodies:HTMLCollection;
    //表示蛇的容器
    element:HTMLElement;

    constructor(){
        this.element=document.getElementById("#snake")!;
        this.head=document.getElementById("#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){
        this.head.style.left=value+'px'
    }
    set Y(value:number){
        this.head.style.top=value+'px';
    }

    //蛇增加身体的方法
    addBody(){
        //向element中添加一个div
        this.element.insertAdjacentHTML('beforeend','<div></div>');
    }

}
export default Snake;
6.键盘事件GameControl
import Food from "./Food";
import scorePanel from "./ScorePanel";
import Snake from "./Snake";

class GameControl {
  //蛇
  snake: Snake;
  //食物
  food: Food;
  //记分牌
  scorePanel: scorePanel;
  //创建一个属性来存储蛇移动的方向
  direction: string = "";
  //创建一个属性用来记录游戏是否结束
  isLive = true;

  constructor() {
    this.snake = new Snake();
    this.food = new Food();
    this.scorePanel = new scorePanel();

    this.init();
  }

  //游戏初始化,调用后游戏开始
  init() {
    //绑定键盘按下的事件
    document.addEventListener("keydown", this.keydownHandler.bind(this));
    this.run();
  }

  //创建一个键盘按下的响应函数
  keydownHandler(event: KeyboardEvent) {
    //需要验证event.key是否合法,用户是否按下了正确的按键
    //修改direction的属性
    this.direction = event.key;
    console.log(event.key);
  }

  //获取蛇现在的坐标
  run() {
    let X = this.snake.X;
    let Y = this.snake.Y;

    switch (this.direction) {
      case "ArrowUp":
        Y -= 10;
        break;
      case "ArrowDown":
        Y += 10;
        break;
      case "ArrowLeft":
        X -= 10;
        break;
      case "ArrowRight":
        X += 10;
        break;
    }

    //判断蛇是否吃到食物,调用吃到食物的方法
    this.checkEat(X,Y);

    try {
      //修改蛇的X和Y
      this.snake.X = X;
      this.snake.Y = Y;
    } catch (error) {
      alert(error);
      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;

7.完善snake类

1.吃到食物之后,蛇体跟随增加,分数增加,食物变换位置

2.蛇撞墙游戏结束,蛇撞到自己身体,游戏结束

3.蛇在一个方向移动时不能掉头

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;
        }

        //蛇的合法值在0-290
        if(value<0||value>290){
            throw new Error("蛇撞墙了!!")
        }

        //修改x时,是在修改水平坐标,蛇在左右移动时,如果在左移动就不能向右掉头。反之亦然。
        if(this.bodies[1]&&(this.bodies[1] as HTMLElement).offsetLeft===value){
            // value大于当前的X,说明往右掉头了
            if(value>this.X){
                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;
        }

        //蛇的合法值在0-290
        if(value<0||value>290){
            throw new Error("蛇撞墙了!!")
        }

        //防止掉头
        if(this.bodies[1]&&(this.bodies[1] as HTMLElement).offsetTop===value){
            // value大于当前的Y,说明往上掉头了
            if(value>this.Y){
                value=this.Y-10
            }else{
                value=this.Y+10
            }
        }

        //移动身体
        this.movebody();

        this.head.style.top=value+'px';
        //检查是否撞到身体
        this.checkheadbody()
    }

    //蛇增加身体的方法
    addBody(){
        //向element中添加一个div
        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;
            console.log(X,Y);
            
            //将值设置在当前的身体上
            (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;

image-20221215222820423

贪吃蛇项目就到这里啦!如果大家想要项目源文件的话,一键三连,评论区回复“学习”,看到就会发你哦

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/91986.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络协议——RPC协议综述

拿最简单的场景&#xff0c;客户端调用一个加法函数&#xff0c;将两个整数加起来&#xff0c;返回它们的和。 如果放在本地调用&#xff0c;那是简单的不能再简单了&#xff0c;。但是一旦变成了远程调用&#xff0c;门槛一下子就上去了。 如何解决这五个问题&#xff1f; …

秦力洪复盘2022:蔚来的长板和误判

作者 | 张祥威 编辑 | 王博最初我们看蔚来&#xff0c;觉得它是中国的特斯拉。后来它主动挑战宝马&#xff0c;以46万的平均单价在高端品牌阵营厮杀&#xff0c;看上去又具备成为宝马的潜力。再到后来&#xff0c;蔚来宣布将推出全新品牌&#xff0c;喊话月销5万辆&#xff0c;…

[附源码]Nodejs计算机毕业设计基于大数据的高校国有固定资产管理及绩效自动评价系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

Django学习15 -- 验证码

1. 验证码 验证码&#xff08;CAPTCHA&#xff0c;Completely Automated Public Turing test to tell Computers and Humans Apart&#xff09;&#xff0c;全自动区分计算机和人类的图灵测试的简称&#xff0c;一种区分用户是计算机还是人的公共全自动程序。防止恶意破解密码、…

Java+Swing+mysql实现学生选课管理系统

JavaSwing实现学生选课管理系统一、系统介绍二、系统展示1.课程查询2.课程添加3.退课三、系统实现四、其他1.其它系统2.获取源码一、系统介绍 本系统实现了学生登录和管理员登录&#xff0c;学生实现选课&#xff0c;查看已选课程&#xff0c;修改密码&#xff0c;查看学生信息…

Vue.use 与 Vue.prototype 在注册插件时,使用上有什么区别

很多使用Vue开发的童鞋&#xff0c;可能对Vue的原型对象prototype有了解过&#xff0c;但对于Vue.use只知如何使用&#xff0c;却不知其背后的含义。那么&#xff0c;今天我们就来瞧一瞧Vue.use()背后的逻辑。 &#x1f388; 首先&#xff0c;Vue.use()是什么&#xff1f; 官方…

外汇天眼:投资200美元起 每天收益7%!千万别被蒙蔽双眼!

12月14日&#xff0c;英国金融行为监管局( FCA )首次对 GoldVest FX 发出警告&#xff0c;提示投资者警惕与这家未经授权的公司打交道。 FCA警告称&#xff1a;GoldVest FX 在未经我们授权的情况下在英国提供金融服务或产品&#xff0c;如果一旦遭受资金损失&#xff0c;您将无…

logback-spring.xml 配置化说明记录如何在SpringBoot项目里面配置logback-spring.xml教程说明

目录 前言描述 logback-spring.xml 配置项详细 配置位置路径 前言描述 无论什么样的java应用都需要日志分级&#xff0c; 日志记录器(Logger)是日志处理的核心组件。log4j具有5种正常级别(Level)。 DEBUG Level指出细粒度信息事件对调试应用程序是非常有帮助的。1.static L…

【三维目标检测】FCAF3D(二)

FCAF3D数据和源码配置调试过程请参考上一篇博文&#xff1a;【三维目标检测】FCAF3D&#xff08;一&#xff09;_Coding的叶子的博客-CSDN博客。本文主要详细介绍FCAF3D网络结构及其运行中间状态。 1 模型总体过程 FCAF3D模型的整体结构如下图所示。该模型属于anchor-free目标…

SIoU Loss 原理与代码解析

paper&#xff1a;SIoU Loss: More Powerful Learning for Bounding Box Regression code&#xff1a;https://github.com/meituan/YOLOv6/blob/main/yolov6/utils/figure_iou.py#L75 存在的问题 之前的目标检测模型的回归损失考虑到了预测的bounding box和gt box之间的dis…

【头歌C语言程序与设计】选择结构程序设计进阶

目录 写在前面 正文 第1关&#xff1a;快递费用计算 第2关&#xff1a;计算一元二次方程的根 第3关&#xff1a;产品信息格式化 写在最后 写在前面 本文代码是我自己所作&#xff0c;本人水平有限&#xff0c;可能部分代码看着不够简练&#xff0c;运行效率不高,但都能运…

cmake笔记 编译与链接

文章目录概述编译最简单的hello world编译工程化的helloWorld更工程化的Hello World&#xff1a; 构建静态库与动态库如何使用外部共享库和头文件其他有用的cmake命令include_directoriesfind_package file(GLOB variable [RELATIVE path] [globbing expressions]...)windows 下…

【Maven基础】IDEA环境使用

第一节 创建父工程 1、创建 Project 2、开启自动导入 创建 Project 后&#xff0c;IDEA 会自动弹出下面提示&#xff0c;我们选择**『Enable Auto-Import』**&#xff0c;意思是启用自动导入。 这个自动导入一定要开启&#xff0c;因为 Project、Module 新创建或 pom.xml 每次…

微服务的相关概念及知识

微服务概念 微服务的概念最早是在2014年由Martin Fowler和James Lewis共同提出&#xff0c;他们定义了微服务是由单一应用程序构成的小服务&#xff0c;拥有自己的进程与轻量化处理&#xff0c;服务依业务功能设计&#xff0c;以全自动的方式部署&#xff0c;与其他服务使用HT…

6-zookeeper-hadoop-ha原理简述-fail

6-zookeeper-hadoop-ha故障转移机制&#xff0c;原理简述: HA概述&#xff08;2.X版本架构&#xff09;。 1&#xff09;、HA&#xff08;High available&#xff09;&#xff0c;即高可用&#xff08;7*24小时不间断服务。&#xff09; 1、zookeeper协调服务&#xff0c;通…

jsp+ssm计算机毕业设计毕业设计管理系统【附源码】

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JSPSSM mybatis Maven等等组成&#xff0c;B/S模式 Mave…

Qt扫盲-QScrollBar理论总结

QScrollBar理论总结1. 简述2. 滚动条组成3. 常用设置5. 信号6. 键盘功能1. 简述 QScrollBar其实就是一个滚动条控件&#xff0c;它使用户能够访问大于用于显示文档的小组件的文档部分。它提供了用户在文档中的当前位置以及可见的文档量的可视指示。滚动条通常配备其他控件&…

什么是MOS管的米勒效应

在说MOS管的米勒效应之前我们先看下示波器测量的这个波形: 这个波形其实就是这个MOS管开关电路的波形&#xff0c;探头1这个黄色的测量的是MOS管的栅极&#xff0c;探头2这个蓝色的测量的是MOS管漏极 大家有没有发现这个黄色的波形在上升的过程中出现了一个平台&#xff0c;其实…

一年半经验如何准备前端面试

typeof NaN 的结果是什么&#xff1f; NaN 指“不是一个数字”&#xff08;not a number&#xff09;&#xff0c;NaN 是一个“警戒值”&#xff08;sentinel value&#xff0c;有特殊用途的常规值&#xff09;&#xff0c;用于指出数字类型中的错误情况&#xff0c;即“执行数…

如何快速拥有好的测试idea

如果接手任意一个测试任务&#xff0c;如何开始测试以及怎么快速的形成测试点呢?其实也是有一套小套路的。大概整理了下&#xff0c;可以从6个方面来考虑入手。 1.项目 快速了解项目背景、信息对象、项目风险、测试资料、债务、交流、语境分析、交付品、工具。 项目的提出动机…