TypeScript 学习笔记 第三部分 贪吃蛇游戏

news2024/11/18 19:52:28

尚硅谷TypeScript教程(李立超老师TS新课)

1. 创建开发环境

  1. 创建工程,使用学习笔记的第二部分
  2. 安装css部分
npm i -D less less-loader css-loader style-loader
  1. 对css部分处理,能够运行在低版本浏览器
npm i -D postcss postcss-loader postcss-preset-env
  1. 修改webpack.config.json文件
    在这里插入图片描述
// 设置less文件的处理
            {
                test: /\.less$/,
                use: [
                    "style-loader",
                    "css-loader",
                    {
                        loader: "postcss-loader",
                        options: {
                            postcssOptions:{
                                plugins: [
                                    [
                                        "postcss-preset-env",
                                        {
                                            browsers:"last 2 versions"
                                        }
                                    ]
                                ]
                            }
                        }
                    },
                    "less-loader"
                ]
            }

2. 工程目录结构

在这里插入图片描述

3. 代码部分

  • index.js
import './style/index.less'

import GameControl from "./modules/GameControl";

new GameControl()
  • index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <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>
  • /style/index.less
// 设置变量
@bg-color:#b7d4a8;

*{
  margin: 0;
  padding: 0;
  caret-color: transparent;
  // 改变盒子模型的计算方式
  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;
  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;
      border:1px solid @bg-color;
      // 开启绝对定位
      position: absolute;
      display: flex;
      flex-wrap: wrap;
      align-content: space-between;
      justify-content: space-between;
      &>div{
        width: 4px;
        height: 4px;
        background-color: black;
        transform: rotate(45deg);
      }
    }
  }
  #score-panel{
    width: 300px;
    display: flex;
    justify-content: space-between;
  }
}


  • /modules/snake.ts
export default class Snake{
    // 蛇头
    head:HTMLElement
    // 蛇身体,包括蛇头
    bodies:HTMLCollection
    // 蛇的父容器
    element:HTMLElement
    constructor() {
        this.element = document.getElementById("snake")!
        this.bodies = this.element.children
        this.head = this.element.firstElementChild as HTMLElement
    }
    // 蛇头的坐标
    get X(){
        return this.head.offsetLeft
    }
    get Y(){
        return this.head.offsetTop
    }

    // 设置蛇头的坐标
    set X(value){

        //  当蛇的第二节与蛇头的x轴坐标重合,说明发生了水平方向的掉头
        if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === value) {
                    if(value > this.X){
                    value =  this.X - 10
                }else{
                    value  =  this.X + 10
                }

        }
        this.moveBody()
        // 设置蛇头坐标
        this.head.style.left = value + 'px'
    }
    set Y(value){
        // 当蛇的第二节与蛇头的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'
    }

    // 蛇增加身体
    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';


        }
    }

    checkHandBody():boolean{
        for (let i = 1; i < this.bodies.length; i++) {
            if (this.X === (this.bodies[i] as HTMLElement).offsetLeft &&
                this.Y === (this.bodies[i] as HTMLElement).offsetTop){
                return false
            }
        }
        return true
    }
}
  • /modules/ScorePanel.ts
export default class ScorePanel{
    score = 0
    level = 1
    scoreElement : HTMLElement
    levelElement : HTMLElement
    maxLevel : number
    upScore : number
    constructor(maxLevel = 10,upScore = 10) {
        this.scoreElement = document.getElementById('score')!
        this.levelElement = document.getElementById('level')!
        this.maxLevel = maxLevel // 最大等级
        this.upScore = upScore // 多少分升一级
    }
    // 增加积分,每吃一个食物增加1分,在此处设置等级的增加
    addScore(){
        this.score ++
        this.scoreElement.innerText = this.score.toString()
        if (this.score % this.upScore === 0){
            this.addLevel()
        }
    }
    // 增加等级
    addLevel(){
        if ( ++this.level <= this.maxLevel) {
            this.levelElement.innerText = this.level.toString()
        }
    }
}

// const a = new ScorePanel()
// for (let i = 0; i < 200; i++) {
//     a.addScore()
// }
  • /modules/Gamecontrol.ts
import Snake from "./snake";
import Food from "./Food";
import ScorePanel from "./ScorePanel";

export default class GameControl {
    snake: Snake
    food: Food
    scorePanel: ScorePanel
    dircter = '' // 保存按键的值

    constructor() {
        this.snake = new Snake()
        this.food = new Food()
        this.scorePanel = new ScorePanel()
        this.init()
    }
    // 初始化操作,监听按键事件
    init() {
        // 第二个参数如果不写bind(this),那调用的函数中的this就是document,而不是类的实例化对象
        document.addEventListener("keydown", this.keydownHandler.bind(this))
        this.run()
    }
    // 按键的回调函数
    keydownHandler(event: KeyboardEvent) {
        this.dircter = event.key
    }

    run() {
        // 蛇头的原坐标
        let x = this.snake.X
        let y = this.snake.Y
        // 按下按键后,4个方向中某一个方向的坐标需要修改
        switch (this.dircter) {
            case 'ArrowUp':
            case 'Up':
                y = y - 10
                break;
            case 'ArrowDown':
            case 'Down':
                y = y + 10
                break
            case 'ArrowLeft':
            case 'Left':
                x = x - 10
                break
            case 'ArrowRight':
            case 'Right':
                x = x + 10
                break
        }

        // 蛇头下一步是不是撞墙了
        if (x < 0 || x > 290 || y < 0 || y > 290) {
            alert("蛇撞墙了")
            return
            // 检测蛇头是否撞到自己
        } else if (!this.snake.checkHandBody()) {
            alert('你咬到自己尾巴了')
            return
        } else {
            this.eachFood()
            // 同一时间只可能有一个轴的位置发生改变
            if (this.snake.Y === y) {
                this.snake.X = x
            }
            else if (this.snake.X === x) {
                this.snake.Y = y
            }
            // 开启定时器,随着等级的升高,蛇的移动速度越来越快
            let time = this.scorePanel.level * 50
            setTimeout(this.run.bind(this), 250 - time)
        }


    }

    // 检测蛇是否吃到食物,吃到食物后:新增食物,增加积分,增加蛇的身体
    eachFood() {
        if (this.snake.X === this.food.X && this.snake.Y === this.food.Y) {
            this.food.change()
            this.scorePanel.addScore()
            this.snake.addBody()

        }
    }

}
  • /modules/Food.ts
class Food{
    element:HTMLElement
    constructor() {
        this.element = document.getElementById('food')!
        this.change()
    }
    // 获取食物坐标
    get X(){
        return this.element.offsetLeft
    }
    get Y(){
        return this.element.offsetTop
    }
    // 设置食物坐标
    set X(value ){
        this.element.style.left = value + 'px'
    }
    set Y(value){
        this.element.style.top = value + 'px'
    }
    // 随机在地图上新增食物
    change(){
        let top = Math.round(Math.random()*29) *10
        let left = Math.round(Math.random()*29) *10
        this.X = left
        this.Y = top
    }
}

export default Food

// const a = new Food()
// console.log(a.X,a.Y);
// a.change()
// console.log(a.X,a.Y);

4. 配置文件

  • package.json
{
  "name": "part2",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "start": "webpack serve --open"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.23.3",
    "@babel/preset-env": "^7.23.3",
    "babel-loader": "^9.1.3",
    "clean-webpack-plugin": "^4.0.0",
    "core-js": "^3.33.3",
    "css-loader": "^6.8.1",
    "html-webpack-plugin": "^5.5.3",
    "less": "^4.2.0",
    "less-loader": "^11.1.3",
    "postcss": "^8.4.31",
    "postcss-loader": "^7.3.3",
    "postcss-preset-env": "^9.3.0",
    "style-loader": "^3.3.3",
    "ts-loader": "^9.5.1",
    "typescript": "^5.3.2",
    "webpack": "^5.89.0",
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^4.15.1"
  }
}

  • tsconfig.json
{
  "compilerOptions": {
    "module": "ES6",
    "target": "ES6",
    "strict": true,
    "noEmitOnError": true
  },
}
  • webpack.config.js
// 引入一个包
const path = require('path')
const HTMlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
// webpack中的所有的配置信息都应该写在moudle.exports中
module.exports = {
    // 当前为开发模式
    mode: 'development',
    // 指定入口文件
    entry: "./src/index.ts",

    // 打包文件的设置项
    output: {
        // 打包后文件的目录
        path: path.resolve(__dirname,'dist'),
        //  打包后文件的名字
        filename: "bundle.js",
        // 打包后文件不使用箭头函数,不使用const
        environment: {
            arrowFunction: false,
            const:false
        },

    },

    // 指定webpack打包时要使用的模块
    module: {
        // 指定要加载的规则
        rules: [
            {
                // test指定的是规则生效的文件
                test: /\.ts$/,
                // 要使用的loader
                use: [
                    // 将新版本的js转换为旧版本的js,提高代码的兼容性
                    {
                        // 指定加载器
                        loader:'babel-loader',
                        // 设置上面这个加载器的配置项
                        options: {
                            // 设置预定义的环境(代码要在那些浏览器中运行)
                            presets: [
                                [
                                    '@babel/preset-env',
                                    {
                                        // 要兼容的目标浏览器
                                        targets:{
                                            // 'chrome':'88',
                                            'ie':'10'
                                        },
                                        // 指定corejs的版本
                                        'corejs':'3',
                                        // 使用corejs的方式:usage 按需加载
                                        'useBuiltIns':'usage'
                                    }
                                ]
                            ]
                        }
                    },
                    'ts-loader', // 将ts转换为js
                ],
                // 要排除的文件
                exclude: /node_moudles/
            },
            // 设置less文件的处理
            {
                test: /\.less$/,
                use: [
                    "style-loader",
                    "css-loader",
                    {
                        loader: "postcss-loader",
                        options: {
                            postcssOptions:{
                                plugins: [
                                    [
                                        "postcss-preset-env",
                                        {
                                            browsers:"last 2 versions"
                                        }
                                    ]
                                ]
                            }
                        }
                    },
                    "less-loader"
                ]
            }
        ]
    },
    // 插件
    plugins: [
        // 自动生成html文件,并且引入相关资源
        new HTMlWebpackPlugin({
            // 自动生成的网页以路径中的网页为模板
            template: "./src/index.html"
        }),
        // 自动清除上次编译后的文件
        new CleanWebpackPlugin(),
    ],

    // 设置那些文件可以作为模块可以被引用
    resolve: {
        extensions: ['.ts','.js']
    }
}

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

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

相关文章

数据结构与算法编程题14

设计一个算法&#xff0c;通过一趟遍历在单链表中确定值最大的结点。 #include <iostream> using namespace std;typedef int Elemtype; #define ERROR 0; #define OK 1;typedef struct LNode {Elemtype data; //结点保存的数据struct LNode* next; //结构体指针…

每日一题 1410. HTML 实体解析器(中等,模拟)

模拟&#xff0c;没什么好说的 class Solution:def entityParser(self, text: str) -> str:entityMap {&quot;: ",&apos;: "",>: >,<: <,&frasl;: /,&amp;: &,}i 0n len(text)res []while i < n:isEntity Falseif …

【从入门到起飞】JavaSE—多线程(3)(生命周期,线程安全问题,同步方法)

&#x1f38a;专栏【JavaSE】 &#x1f354;喜欢的诗句&#xff1a;路漫漫其修远兮&#xff0c;吾将上下而求索。 &#x1f386;音乐分享【如愿】 &#x1f384;欢迎并且感谢大家指出小吉的问题&#x1f970; 文章目录 &#x1f354;生命周期&#x1f384;线程的安全问题&#…

opencv-Otsu‘s 二值化分割

Otsu’s 二值化是一种自适应的图像阈值选择方法&#xff0c;它通过最小化类内方差和最大化类间方差来确定一个最佳的阈值。该方法由日本学者大津展之&#xff08;Otsu&#xff09;于1979年提出&#xff0c;广泛用于图像分割。 该算法的核心在于前景与背景图像的类间方差最大 在…

PC8223(CC/CV控制)高耐压输入5V/3.4A同步降压电路内建补偿带恒流恒压输出

概述 PC8233&#xff08;替代CX8853&#xff09;是一款同步降压调节器,输出电流高达3.4A,操作范围从8V到32V的宽电源电压。内部补偿要求最低数量现成的标准外部组件。PC8233在CC&#xff08;恒定输出电流&#xff09;模式或CV&#xff08;恒定输出电压&#xff09;模式&#x…

HarmonyOS元服务开发实战—端云一体化开发

还记得我第一次接触arkui还是在22年的9月份&#xff0c;当时arkui还在一个比较初试的阶段。时隔一年再见方舟框架&#xff0c;它已经发生了令人瞩目的变化&#xff0c;不得不说华为方舟框架在更新迭代的速度已经遥遥领先。新的功能和性能优化让这个框架更加强大和灵活&#xff…

【实用】PPT没几页内存很大怎么解决

PPT页数很少但导出内存很大解决方法 1.打开ppt点击左上角 “文件”—“选项” 2.对话框选择 “常规与保存” &#xff08;1&#xff09;如果想要文件特别小时可 取消勾选 “将字体嵌入文件” &#xff08;2&#xff09;文件大小适中 可选择第一个选项 “仅最入文档中所用的字…

【SpringBoot篇】Spring_Task定时任务框架

文章目录 &#x1f339;概述&#x1f33a;应用场景&#x1f384;cron表达式&#x1f6f8;入门案例&#x1f38d;实际应用 &#x1f339;概述 Spring Task 是 Spring 框架提供的一种任务调度和异步处理的解决方案。可以按照约定的时间自动执行某个代码逻辑它可以帮助开发者在 S…

腾讯云 小程序 SDK对象存储 COS使用记录,原生小程序写法。

最近做了一个项目&#xff0c;需求是上传文档&#xff0c;文档类型多种&#xff0c;图片&#xff0c;视频&#xff0c;文件&#xff0c;doc,xls,zip,txt 等等,而且文档类型可能是大文件&#xff0c;可能得上百兆&#xff0c;甚至超过1G。 腾讯云文档地址&#xff1a;https://c…

Altium Designer学习笔记11

画一个LED的封装&#xff1a; 使用这个SMD5050的封装。 我们先看下这个芯片的功能说明&#xff1a; 5050贴片式发光二极管&#xff1a; XL-5050 是单线传输的三通道LED驱动控制芯片&#xff0c;采用的是单极性归零码协议。 数据再生模块的功能&#xff0c;自动将级联输出的数…

BootStrap【表格二、基础表单、被支持的控件、表单状态】(二)-全面详解(学习总结---从入门到深化)

目录 表格二 表单_基础表单 表单_被支持的控件 表单_表单状态 表格二 紧缩表格 通过添加 .table-condensed 类可以让表格更加紧凑&#xff0c;单元格中的内补&#xff08;padding&#xff09;均会减半 <table class"table table-condensed table-bordered"…

信创系列之大数据,分布式数据库产业链跟踪梳理笔记…

并购优塾 投行界的大叔&#xff0c;大叔界的投行 【产业链地图&#xff0c;版权、内容与免责声明】1&#xff09;版权&#xff1a;版权所有&#xff0c;违者必究&#xff0c;未经许可不得翻版、摘编、拷贝、复制、传播。2&#xff09;尊重原创&#xff1a;如有引用未标注来源…

数据结构与算法编程题15

设计一个算法&#xff0c;通过遍历一趟&#xff0c;将链表中所有结点的链接方向逆转&#xff0c;仍利用原表的存储空间。 #include <iostream> using namespace std;typedef int Elemtype; #define ERROR 0; #define OK 1;typedef struct LNode {Elemtype data; …

Cypress-浏览器操作篇

Cypress-浏览器操作篇 页面的前进与后退 后退 cy.go(back); cy.go(-1);前进 cy.go(forward); cy.go(1);页面刷新 cy.reload() cy.reload(forceReload) cy.reload(options) cy.reload(forceReload, options)**options&#xff1a;**只有 timeout 和 log forceReload 是否…

普通平衡树

题意&#xff1a;略&#xff0c;题中较清晰。 用二叉查找树来存储数据&#xff0c;为了增加效率&#xff0c;尽量使左子树和右子树的深度差不超过一&#xff0c;这样可以时间控制在logn&#xff0c;效率比较高。 右旋和左旋&#xff0c;目的是为了维护二叉树的操作&#xff0…

NX二次开发UF_CSYS_ask_matrix_of_object 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CSYS_ask_matrix_of_object Defined in: uf_csys.h int UF_CSYS_ask_matrix_of_object(tag_t object_id, tag_t * matrix_id ) overview 概述 Gets the matrix identifier atta…

Sealos 云操作系统私有化部署教程

Sealos 私有云已经正式发布了&#xff0c;它为企业用云提供了一种革命性的新方案。Sealos 的核心优势在于&#xff0c;它允许企业在自己的机房中一键构建一个功能与 Sealos 公有云完全相同的私有云。这意味着企业可以在自己的控制和安全范围内&#xff0c;享受到公有云所提供的…

Web前端—移动Web第五天(媒体查询、Bootstrap、综合案例-alloyTeam)

版本说明 当前版本号[20231122]。 版本修改说明20231122初版 目录 文章目录 版本说明目录移动 Web 第五天01-媒体查询基本写法书写顺序案例-左侧隐藏媒体查询-完整写法关键词 / 逻辑操作符媒体类型媒体特性 媒体查询-外部CSS 02-Bootstrap简介使用步骤下载使用 栅格系统全局…

数据库|TiDB v7.1.0 资源管控功能是如何降低运维难度和成本

目录 一、前言 二、资源管控流程图 三、资源管控(Resource Control)测试 &#xff08;一&#xff09;测试集群环境 &#xff08;二&#xff09;Request Unit(RU)概念 &#xff08;三&#xff09;资源管控参数 &#xff08;四&#xff09;评估实际负载所需容量 &#xff…

vue项目引入element-plus

文章目录 引入框架遇到的问题引入的时候&#xff0c;报错 ...(reading replace)...报错&#xff1a;The template root requires ...eslint报错&#xff1a; 运行 引入框架 使用add引入 遇到的问题 引入的时候&#xff0c;报错 …(reading ‘replace’)… Cannot read prop…