I am participating in the nuggets Community game creative submission Contest. For details, please see: Game Creative Submission Contest

Hello everyone, I am a bowl week, a front end that does not want to be drunk (inrolled). If I am lucky enough to write an article that you like, I am very lucky

Writing in the front

Snake this game we are familiar with, I contact this game or in the Nokia mobile phone, I believe that we have seen this mobile phone, is the following appearance:

In this article, we use front-end technology to achieve this small game, the code of this game mostly uses TS+Less writing, just practice TS.

The game is shown below:

Online experience address: ywanzhou. Making. IO/eating – snak…

HTML structure

First, let’s make sure our HTML structure is as follows:

<body>
  <! Create the game's main window -->
  <div id="main">
    <! -- Main area -->
    <div id="state">
      <! -- -- -- > snake
      <div id="snake">
        <div></div>
      </div>
      <! -- Set food -->
      <div id="food"></div>
    </div>
    <! Show -- -- -- >
    <div id="score-panel">
      <div>Score:<span id="score">0</span></div>
      <div>Level: <span id="level">1</span></div>
    </div>
  </div>
</body>
Copy the code

HTML structure is relatively simple, CSS style is not complex, if you need to go to Github to check.

Food class

First of all, we need to get the elements in the HTML structure, and then we can get the X-axis and Y-axis coordinates of the food, and finally define a method to change his coordinates, example code is as follows:

// Define the food class food
class Food {
  // Define an attribute that represents the name of the element to which the food corresponds: the type is HTMLElement
  element: HTMLElement
  constructor() {
    / /! Indicates that document.getelementById ('food') has determined that the corresponding element can be found and will not be empty
    this.element = document.getElementById("food")!
  }
  // get the x and y coordinates
  get X() {
    return this.element.offsetLeft
  }
  get Y() {
    return this.element.offsetTop
  }

  change() {
    // Generate a random position to indicate the food position. The minimum value is 0 and the maximum value is 290
    let top = Math.round(Math.random() * 29) * 10
    let left = Math.round(Math.random() * 29) * 10

    this.element.style.left = left + "px"
    this.element.style.top = top + "px"}}export default Food

Copy the code

snakes

First we define attributes to represent elements as follows:

class Snake {
  // indicates the head of a snake
  head: HTMLElement
  // Represents the body of the snake (including its head)
  bodies: HTMLCollection
  // The parent element of the snake
  element: HTMLElement
  constructor() {
    // Initialize the element
    this.element = document.getElementById("snake")!
    this.head = document.querySelector("#snake > div") as HTMLElement
    this.bodies = this.element.getElementsByTagName("div")}}Copy the code

Then define two methods, one for adding the snake body and one for moving the snake, in the following code:

// The way the snake increases its body
addBody() {
  // Add a div to element
  this.element.insertAdjacentHTML("beforeend"."<div></div>")}// Add a snake body movement method
moveBody() {
  /* Set the position of the next section to the position of the previous section, for example, set the position of the second section to the position of the snake head, because to get the position of the previous section, we need to traverse backwards

  for (let i = this.bodies.length - 1; i > 0; i--) {
    The attribute "offsetLeft" does not exist on the front body position type "Element" requires a type assertion
    let X = (this.bodies[i - 1] as HTMLElement).offsetLeft
    let Y = (this.bodies[i - 1] as HTMLElement).offsetTop

    // Set the value to the current body; (this.bodies[i] as HTMLElement).style.left = X + "px"; (this.bodies[i] as HTMLElement).style.top = Y + "px"}}Copy the code

Obtain the coordinates of the snake head, the implementation is relatively simple, the code is as follows:

// Get the snake coordinates (snake head coordinates)
get X() {
  return this.head.offsetLeft
}
get Y() {
  return this.head.offsetTop
}
Copy the code

Define a method to detect whether you hit your body as follows:

// Check if the snake's head has hit the body
checkHeadBody() {
  // Get all bodies and check if they overlap with the coordinates of the snake's head
  /* let i = 1; i < this.bodies.length; I++ starts at 1 and does not include the snake head 0 */
  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) {
      // Enter the judgment that the snake head hit the body, game over
      throw new Error("Don't hit yourself.")}}}Copy the code

Then we set the coordinates of the snake’s head. In the implementation process, we need to add some logical judgments, such as not hitting the wall, turning up when not moving down, etc.

The code is as follows:

// Set the coordinates of the snake head
set X(value: number) {
  // If the new value is the same as the old value, the new value is returned without modification
  if (this.X === value) {
    return
  }
  // Check whether the snake moves within the specified range
  if (value < 0 || value > 290) {
    throw Error("Your little snake ran into a wall.")}// When you change x, you are changing the horizontal coordinate, the snake is moving left and right, the snake is moving left, it cannot turn right, and vice versa
  /* this. Bodies [1] as HTMLElement. OffsetLeft === value this
  if (
    this.bodies[1] &&
    (this.bodies[1] as HTMLElement).offsetLeft === value
  ) {
    if (value > this.X) {
      value = this.X - 10
    } else {
      value = this.X + 10}}// Move the body
  this.moveBody()
  this.head.style.left = value + "px"

  // Check if you hit yourself
  this.checkHeadBody()
}

set Y(value: number) {
  // If the new value is the same as the old value, the new value is returned without modification
  if (this.Y === value) {
    return
  }
  // Check whether the snake moves within the specified range

  if (value < 0 || value > 290) {
    throw Error("Your little snake ran into a wall.")}// When you change Y, you are changing the vertical coordinate. The snake is moving left and right. When the snake is moving up, it cannot turn down, and vice versa
  if (this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === value) {
    if (value > this.Y) {
      value = this.Y - 10
    } else {
      value = this.Y + 10}}// Move the body
  this.moveBody()
  this.head.style.top = value + "px"
  // Check if you hit yourself
  this.checkHeadBody()
}
Copy the code

Finally, the class is exported.

export default Snake
Copy the code

Fractional grade class

Now we define a method to record scores and grades as follows:

class ScorePanel {
  // Record the score and grade respectively
  score = 0;
  level = 1;

  // The elements of the score and rank are initialized in the constructor
  ScoreEle: HTMLElement;
  LevelEle: HTMLElement;
  // Set a variable limit level
  maxLevel: number;
  upScore: number;

  constructor(maxLevel: number = 10, upScore: number = 10) {
    this.ScoreEle = document.getElementById("score")! ;this.LevelEle = document.getElementById("level")! ;this.maxLevel = maxLevel;
    this.upScore = upScore;
  }

  // set up a bonus method
  addScore() {
    // Make the score increment
    this.ScoreEle.innerHTML = ++this.score + "";
    if (this.score % this.upScore === 0) {
      this.UpLevel(); }}UpLevel() {
    // Make the level increment
    if (this.level < this.maxLevel) {
      this.LevelEle.innerHTML = ++this.level + ""; }}}export default ScorePanel;

Copy the code

Game controller

We will be the previous definition has been implemented, now we will be the first three classes to apply, the implementation code is as follows:

import ScorePanel from "./ScorePanel";
import Snake from "./snake";
import Food from "./Food";

// The game controller controls all other classes
class GameControl {
  // Define three attributes
  snake: Snake;
  food: Food;
  / / scoreboard
  scorePanel: ScorePanel;
  // Create a property to store the snake's movement direction.
  direction: string = "";
  // Create a property to record whether the game is over
  isLive = true;

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

    // Initialize the game
    this.init();
  }
  // Initialize the game method, after calling the game starts
  init() {
    document.addEventListener("keydown".this.keydownHandler.bind(this));
    this.run();
  }
  // Create a keypress response function
  keydownHandler(event: KeyboardEvent) {
    // After the user presses a key on the keyboard, it is necessary to determine whether the key pressed by the user matches the target key

    // Stores the keys when the user presses the keyboard
    this.direction = event.key;
  }

  // Define a method by which the snake moves
  run() {
    // Get the snake coordinates
    let X = this.snake.X;
    let Y = this.snake.Y;

    // Change the coordinate of the snake according to the direction of the key
    switch (this.direction) {
      // Move top up to decrease
      case "ArrowUp":
        Y -= 10;
        break;
      case "ArrowDown":
        Y += 10;
        break;
      case "ArrowLeft":
        X -= 10;
        break;
      case "ArrowRight":
        X += 10;
        break;
      default:
        break;
    }

    // Check whether the snake has eaten the food
    this.checkEat(X, Y);

    // Change the X and Y values of the snake
    try {
      this.snake.X = X;
      this.snake.Y = Y;
    } catch (e: any) {
      // Catch an abnormal pop-up message
      alert(e.message);
      // isLive is changed to false to end the game
      this.isLive = false;
    }
    // Start a timer run()
    this.isLive &&
      setTimeout(this.run.bind(this), 300 - (this.scorePanel.level - 1) * 30);
  }

  // Define a method to check whether the snake has eaten the food
  checkEat(X: number, Y: number) {
    if (X === this.food.X && Y === this.food.Y) {
      // The food position is refreshed
      this.food.change();
      / / add a point
      this.scorePanel.addScore();
      // Snake body increases by 1
      this.snake.addBody(); }}}export default GameControl;

Copy the code

Most of the code for the game has been done by this point.

Write in the last

All the code has been put on GitHub, the code is not complex, only suitable for learning.

PS: If you are big, or think this article rubbish, please ignore this article, thank you.