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.