当前位置:网站首页>Use typescript to complete simple snake eating function

Use typescript to complete simple snake eating function

2022-06-13 09:06:00 antRain

Reference material

development tool

  • vscode
  • Recommended plug-ins Live Server Can monitor file changes , And refresh

Interface effect

 Insert picture description here

Interface index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title> snake </title>
  <link rel="stylesheet" href="css/index.css">
</head>
<body>
  <div id="main">
    <!--  The main interface of the game  -->
    <div id="stage">
      <!--  Set snake  -->
      <div id="snake">
        <!--  Represents the parts of a snake  -->
        <div></div>
      </div>
      <!-- Set food ,4 individual div Represents four corners -->
      <div id="food">
        <div></div>
        <div></div>
        <div></div>
        <div></div>
      </div>
    </div>

    <!--  Set the score card of the game  -->
    <div id="score-panel">
      <!--  integral  -->
      <div>SCORE:<span id="score">0</span></div>
      <!--  Grade , Default 10,  High level and fast speed  -->
      <div>LEVEL:<span id="level">1</span></div>
    </div>

  </div>
  <script src="TS/index.js"></script>
</body>
</html>

index.css

  • Set the style of the page , It can be used in modular development less
* {
    
  margin: 0;
  padding: 0;
  box-sizing: border-box;
} /*  Clear default style  */

body {
    
  font: bold 20px "Courier"
}

#main {
    
  width: 360px;
  height: 420px;
  background-color: #b7d4a8;
  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: black;
  border: 1px solid  #b7d4a8;
  position: absolute;
}

#food {
    
  width: 10px;
  height: 10px;
  position: absolute;
  left: 40px;
  top: 100px;
  display: flex;
  flex-flow: row wrap; /*  Set the main axis to the horizontal axis   Wrap the excess part  */
  /*  Set the white space of the main axis and the side axis to be allocated between the elements  */
  justify-content: space-between;
  align-items: center;
}

#food > div {
    
  width: 4px;
  height: 4px;
  background-color: black;
  transform: rotate(45deg);
}

#score-panel {
    
  width: 300px;
  display: flex;
  justify-content: space-between;
}

index.ts

  • In modular development, you can put each class in a separate file
  • Here I use a file , have access to The command is convenient for tsc -t ES6 -w index.ts Said the use of ES6 Compile , And monitor the files
class Food {
    
  element : HTMLElement
  width: number
  size: number 
  constructor (id:string, width = 29, size = 10 ) {
    
    this.element=document.getElementById(id)
    this.width = width
    this.size = size
  }
  get X(){
    
    return this.element.offsetLeft
  }
  get Y() {
    
    return this.element.offsetTop
  }
  change() {
    
    //  Generate random positions   The scope is [0,width*10]  But it should be an integer   And is 10 Multiple 
    this.element.style.left = Math.round(Math.random()*this.width)*this.size + 'px'
    this.element.style.top = Math.round(Math.random()*this.width)*this.size + 'px'
  } //  Modify the location of the food 
}

class ScorePanel {
    
  score = 0 
  level = 1
  scoreEle : HTMLElement
  levelEle : HTMLElement   
  static maxLevel = 10
  static upScore = 1 //  Set L 1 The grade required 
  constructor (scoreId:string, levelId:string) {
    
    this.scoreEle = document.getElementById(scoreId)
    this.levelEle = document.getElementById(levelId)
    this.scoreEle.innerText = this.score + ''
    this.levelEle.innerText = this.level + ''
  }
  addScore (d = 1) {
    
    this.score += 1
    this.scoreEle.innerText = this.score + ''
    if (this.score % ScorePanel.upScore === 0) this.addLevel()
  }
  addLevel () {
    
    if (this.level < ScorePanel.maxLevel) {
    
      this.levelEle.innerText = ++this.level + ''
    }
  }
}


class Snake {
    
  head: HTMLElement //  The element representing the snake head 
  bodies: HTMLCollection //  The body of a snake contains its head 
  element: HTMLElement //  Get the container of the snake  
  range: number //  The range of a snake's head 
  constructor(id, range = 290) {
    
    this.element = document.getElementById(id)
    this.element.innerHTML = '<div></div>' //  initialization 
    this.bodies = this.element.getElementsByTagName('div')
    this.head = this.bodies[0] as HTMLElement
    this.range = range
  }
  get X() {
    
    return this.head.offsetLeft
  } //  Get snakehead x coordinate 
  get Y() {
    
    return this.head.offsetTop
  } //  Get snakehead y coordinate 

  set X(value:number) {
    
    if (this.X === value) return
    this.judge(value)
    this.move()
    this.head.style.left = value + 'px'
  }
  set Y(value:number) {
    
    if (this.Y === value) return
    this.judge(value)
    this.move()
    this.head.style.top = value + 'px'
    
  }
  addBody () {
    
    this.element.insertAdjacentHTML("beforeend","<div></div>")
  }
  move() {
    
    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'
    }
  }
  judge(value:number) {
    
    if ( value < 0 || value > this.range) {
    
      throw new Error(' The snake hit the wall ')
    }
    for(let i= this.bodies.length-1;i>0;--i) {
    
      let x = (this.bodies[i] as HTMLElement).offsetLeft
      let y = (this.bodies[i] as HTMLElement).offsetTop;
      if (x===this.X && y === this.Y) throw new Error(' Don't eat yourself ')
    }
  }
}

class GameControl {
    
  snake:Snake
  scorePanel: ScorePanel
  food: Food
  direction:string //  Snake head moving direction 
  isLive = true //  Mark that the current snake still exists =
  static directionKey = new Set(['w','a','s','d',' '])  //  The moving direction of the snake head may take 
  static speed = 200 //  Initial speed setting 
  constructor() {
    
    this.scorePanel = new ScorePanel('score','level')
    this.food = new Food("food")
    this.snake = new Snake("snake", this.food.size * this.food.width)
    this.direction = ' '
    this.init()
  }
  init() {
    
    this.food.change()
    console.log(this.food.X,this.food.Y)
    document.addEventListener('keydown',this.keydownHandler.bind(this))
    this.run()
  }//  Game initialization 
  keydownHandler(event:KeyboardEvent) {
    
    let key = event.key
    if (GameControl.directionKey.has(key)){
    
      //  Can't move in the opposite direction 
      if (this.direction === 'w' && key === 's') return
      if (this.direction === 'a' && key === 'd') return
      if (this.direction === 's' && key === 'w') return
      if (this.direction === 'd' && key === 'a') return
      this.direction = event.key
    }
  }// Create a function that responds to a keyboard press 
  run(){
    
    let x = this.snake.X, y = this.snake.Y
    switch(this.direction) {
    
      case 'w': 
        y -= 10
        break //  Move up 
      case 'a':
        x -= 10
        break //  Move to the left 
      case 's':
        y += 10
        break //  Move down the 
      case 'd':
        x += 10
        break //  To the right 
      case ' ':
        break //  A space indicates pause or resume 
    }
    try {
    
      this.checkEat(x, y)
      this.snake.X = x
      this.snake.Y = y
    }catch (err){
    
      this.isLive = false
      if (window.confirm(err.message + '  Whether to continue the game ')) {
    
        game = new GameControl()
      }
      return
    }
  
    this.isLive && setTimeout(this.run.bind(this),GameControl.speed / this.scorePanel.level) //  Turn on timed call 
  }//  Method of Snake Movement 
  checkEat (x:number, y:number) {
    
    if  (x === this.food.X && y === this.food.Y) {
    
      this.food.change()
      this.scorePanel.addScore()
      this.snake.addBody()
    }
  } //  Check whether the snake is late for food 
} //  Game controller 

let game: GameControl = new GameControl()

appendix

  • The teacher's webpack.config.js The configuration file , The other part is that I added
const path = require('path')
const HTMLWebpackPlugin = require('html-webpack-plugin')
const {
    CleanWebpackPlugin} = require('clean-webpack-plugin')

module.exports = {
    
  context: path.resolve(__dirname, ''), //  Base directory , Absolute path , Used to resolve the entry starting point from the configuration  (entry point)  And loader  (loader).
  entry: "./src/index.ts", //  Specify the entry file 
  output: {
    
    path: path.resolve(__dirname,'dist') , //  Splicing catalog 
    filename: "bundle.js" ,//  Package file name 
    environment: {
    
      arrowFunction: false
    } //  Syntax environment of output file 
  }, //  Specify the directory where the package files are located 
  module: {
    
    rules:[
      {
     
        test: /\.tsx?$/, //  Specify the file in which the rule takes effect 
        use: [
          {
    
            loader: "babel-loader",
            options: {
    
              persets: [
                "@babel/preset-env", //  Specifies the plug-in for the environment 
                {
    
                  targets: {
    
                    "chrome": "88",
                    "ie": "10"
                  }, //  A compatible browser 
                  "corejs": "3",
                  "useBuiltIns" : "usage", //  Indicates that the required resources are loaded on demand 
                }
              ] //  Set the predefined environment  
            } //  The configuration item corresponding to the loader , Each loader has its own configuration item 
          },
          "ts-loader"
        ] ,//  Array mode uses multiple loaders 
        exclude: "/node-modules/" //  Folder to exclude 
      }
    ] //  Specify the rules to load 
  }, //  Appoint webpack Modules to be used when packaging 
  resolve: {
    
    extensions: ["", ".webpack.js", ".web.js", ".ts", ".tsx", ".js"],
    alias: {
    
      '@': resolve('src')
    }, //  The configuration alias maps the original import path to a new import path 
  }, //  To configure  webpack  How to find the file corresponding to the module 
  plugins: [
    new CleanWebpackPlugin(),
    new HTMLWebpackPlugin({
    
      title : 'ts The project build ', // index.html  title 
      template: "", //  Define template location  
    })
  ],
  devServer: {
    
    
  } //  Provide virtual servers , Let's develop and debug . The corresponding plug-in needs to be installed  webpack-dev-server
}
  • part package.json Dependencies to be installed
{
    
  "script":{
    
    "build": "webpack",
    "start": "webpack serve --open chrome.exe"
  },
  "devDependencies": {
    
    "clean-webpack-plugin" : "", // webpack Clear plug-ins in , Each build will first clear the directory 
    "html-webpack-plugin":"", // webpack in html plug-in unit , Used to automatically create html file 
    "ts-loader":"", // ts loader , Used in webpack Chinese compiler ts file 
    "typescript":"", // ts compiler 
    "webpack": "", //  Building tools webpack
    "webpack-cli": "", // webpack Command line tools for 
    "webpack-dev-server": "",
    "@babel/core": "",
    "@babel/preset-enb": "",
    "babel-loader":"",
    "core-js": ""
  }
}
  • webpack-dev-server : Static resource server with real-time overload capability
原网站

版权声明
本文为[antRain]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202270534440385.html