当前位置:   article > 正文

【TypeScript】第五部分 小项目练习(贪吃蛇)_typescript实现一个小项目

typescript实现一个小项目

TypeScript】第五部分 小项目练习(贪吃蛇)



5. 小项目练习(贪吃蛇

5.1 准备工作

package.json

我把该文件放在下面,有需要的直接创建package.json将下面的代码复制进去,然后 npm i 下载相关的依赖

{
  "name": "webpack-ts",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack-dev-server"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.17.9",
    "@babel/preset-env": "^7.16.11",
    "babel-loader": "^8.2.4",
    "clean-webpack-plugin": "^4.0.0",
    "core-js": "^3.21.1",
    "html-webpack-plugin": "^5.5.0",
    "postcss": "^8.4.12",
    "postcss-loader": "^6.2.1",
    "postcss-preset-env": "^7.4.3",
    "ts-loader": "^9.2.8",
    "typescript": "^4.6.3",
    "webpack": "^5.72.0",
    "webpack-cli": "^4.9.2",
    "webpack-dev-server": "^4.8.1"
  },
  "dependencies": {
    "css-loader": "^6.7.1",
    "less": "^4.1.2",
    "less-loader": "^10.2.0",
    "style-loader": "^3.3.1"
  }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

webpack.config.js

const {resolve}  = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')

module.exports = {
    entry:'./src/index.ts',
    output:{
        filename:"js/index.js",
        path:resolve(__dirname,'build')
    },
    module:{
        rules:[
            {   //处理ts
                test:/\.ts$/,
                use:[
                    //配置babel
                    {
                        //加载器
                        loader:'babel-loader',
                        options:{
                            //预设环境
                            presets:[
                                [
                                    //指定预设环境
                                    "@babel/preset-env",
                                    {
                                        //兼容目标浏览器
                                        targets:{
                                            "chrome":58,
                                            "ie":11
                                        },
                                        //corejs的版本
                                        "corejs":3,
                                        //配置按需加载
                                        "useBuiltIns":"usage"
                                    }
                                ]
                            ]
                        }
                    },
                    //将ts转为js
                    {loader:'ts-loader'}
                ],
                exclude:/node_modules/
            },
            {
                //处理less
                test:/\.less$/,
                use:[
                    "style-loader",
                    "css-loader",
                    // 处理css的兼容性问题
                    {
                        // 加载器
                        loader:'postcss-loader',
                        options:{
                            postcssOptions:{
                                plugins:[
                                    [
                                        'postcss-preset-env',
                                        {
                                            browsers:'last 2 versions'
                                        }
                                    ]
                                ]
                            }
                        }
                    },
                    // 将less转为css
                    "less-loader"
                ],
                exclude:/node_modules/
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html'
        }),
        new CleanWebpackPlugin()
    ],
    //用来告诉webpack 哪些文件可以导入
    resolve:{
        extensions:['.ts','.css','.js']
    },
    mode:'development'
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87

tsconfig.json

{
    "compilerOptions":{
        "strict": true,
        "target": "es2015",
        "module": "es2015",
        "noEmitOnError": true
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

5.2 实现效果

在这里插入图片描述

具体代码实现:

index.ts

import '../style/index.less'
import Control from "../modules/Control"

new Control()

  • 1
  • 2
  • 3
  • 4
  • 5

Control.ts

import ScorePanel from "../modules/ScorePanel"
import Food from "../modules/Food"
import Snack from "../modules/Snack"

class Control{
    food:Food
    snack:Snack
    scorepanel:ScorePanel
    direction = ''
    isLive = true
    constructor(){
        this.food = new Food()
        this.snack = new Snack()
        this.scorepanel = new ScorePanel()
        //初始化游戏,调用则游戏开始
        this.init()
    }
    //定义一个初始化函数
    init(){
        /* 
            在这里this会出现问题,因为在这里this是由document调用所以this指向document
            解决办法:
                - 可以使用箭头函数
                - bind()
        */
        // document.addEventListener('keydown',(event:KeyboardEvent)=>{
        //     this.SnackDirection(event)
        // })
        document.addEventListener('keydown',this.SnackDirection.bind(this))
        this.run()
    }

    //键盘按下事件
    SnackDirection(event:KeyboardEvent){
        // 修改direction属性
        this.direction = event.key
    }

    //让蛇跑起来
    run(){
        let x = this.snack.X
        let y = this.snack.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.checkFood(x,y)

       try {
            // 修改蛇的位置
            this.snack.X = x
            this.snack.Y = y
       } catch (error) {
           alert(error)
           this.isLive = false
       }

        this.isLive && setTimeout(()=>{
            this.run()
        }, 100-(this.scorepanel.num2 - 1)*10);
    }


    //检查是否吃到东西
    checkFood(x:number,y:number){
        if(this.food.X === x && this.food.Y === y)
        {
            //进入判断表示吃到了东西
            this.food.foodRandom()
            this.snack.addBody()
            this.scorepanel.addScore
        }
    }



}

export default Control
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83

Food.ts

class Food{
    element:HTMLElement
    constructor(){
        this.element = document.querySelector('#food')!
    }

    // 获取食物当前的位置
    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'
    }

    /* 
        1.食物随机跳变
            分析:
                 - 跳变的范围 0-290
                 - 并且你要满足是10的倍数,因为设定
                    都一步为10格,要不然一直吃不到
    */
   foodRandom(){
        //生成随机数
        let left = Math.round(Math.random()*29)*10
        let top = Math.round(Math.random()*29)*10
        //设置food的位置
        this.X = left
        this.Y = top
   }

}

export default Food

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

ScorePanel.ts

class ScorePanel{
    score:HTMLElement
    level:HTMLElement
    num1 = 0  //分数初始值
    num2 = 1  //等级初始值
    maxLevel:number  // 设置最大的等级
    setScore:number //设置多少分升一级
    constructor(setScore = 10,maxLevel = 10){
        this.setScore = setScore
        this.maxLevel = maxLevel
        this.score = document.querySelectorAll('#score span')[0] as HTMLLinkElement
        this.level = document.querySelectorAll('#score span')[1] as HTMLLinkElement
    }

    // 增加分数
    addScore(){
        this.score.innerText = ++this.num1 +''
        if(this.num1 % this.setScore === 0)
        {
            this.addLevel()
        }
    }

    // 升级
    addLevel(){
        if(this.num2 < this.maxLevel)
        {
            this.level.innerText = ++this.num2 +''
        }
    }
}

export default ScorePanel
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

Snack.ts

class Snack{
    head:HTMLElement
    bodies:HTMLCollection
    element:HTMLElement
    constructor(){
        //获取头部
        this.head = document.querySelector('.head')!
        //获取身体
        this.bodies = document.getElementById('snack')!.getElementsByTagName('div')
        //获取snack容器
        this.element = document.querySelector('#snack')!
    }

    //获取头部的位置
    get X ()
    {
        return this.head.offsetLeft
    }

    get Y ()
    {
        return this.head.offsetTop
    }

    //设置头部的位置
    set X(value){
        //当位置未发生改变则不进行赋值
        if(this.X === value)
        {
            return
        }

        //限制蛇移动的范围
        if(value < 0 || value > 290)
        {
            throw 'GAME OVER ! 游戏结束!'
        }

        //解决蛇掉头问题
        if(this.bodies[1] && value === (this.bodies[1] as HTMLElement).offsetLeft)
        {
            //进入判断就表示调头了
            if(value > this.X)
            {
                value -= 20
            }else
            {
                value += 20
            }
        }

        this.moveBody()
        this.head.style.left = value + 'px'
        this.checkHead()
    }   

    set Y(value){
        //当位置未发生改变则不进行赋值
        if(this.Y === value)
        {
            return
        }

        //限制蛇移动的范围
        if(value < 0 || value > 290)
        {
            throw 'GAME OVER ! 游戏结束!'
        }

         //解决蛇掉头问题
         if(this.bodies[1] && value === (this.bodies[1] as HTMLElement).offsetTop)
         {
             //进入判断就表示调头了
             if(value > this.Y)
             {
                 value -= 20
             }else
             {
                 value += 20
             }
         }

        this.moveBody()
        this.head.style.top = value + 'px'
        this.checkHead()
    }   

    addBody(){
        this.element.insertAdjacentHTML('beforeend','<div></div>')
    }

    //添加身体移动的方法
    /* 
        实现的逻辑:
            第四节的位置 --> 第三节的位置
            第三节的位置 --> 第二节的位置
            第二节的位置 --> 第一节的位置
    */
    moveBody(){
        for(let i = this.bodies.length-1; i>0; i--)
        {
            let left = (this.bodies[i-1] as HTMLElement).offsetLeft;
            let top = (this.bodies[i-1] as HTMLElement).offsetTop;
            (this.bodies[i] as HTMLElement).style.left = left + 'px';
            (this.bodies[i] as HTMLElement).style.top = top + 'px';

        }
    }

    //检查是否撞头
    checkHead(){
        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)
            {
                // 如果进入了判断就表示撞到自己了
                throw '撞到自己了!!游戏结束!!'
            }
        }
}

}

export default Snack
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124

总结

以上就是今天要讲的内容,希望对大家有所帮助!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/1002561
推荐阅读
相关标签
  

闽ICP备14008679号