Note source: Hook Education – big front end employment Training camp
Content: Notes, thoughts and experiences in the process of learning
Snake game case
Analyze the objects that need to be encapsulated
In the whole game, we can see two objects, namely food and snake. At the same time, we can also encapsulate the logic of the game into objects, so that we can abstract out three objects
Note: This can be encapsulated using self-calling functions (execute functions immediately), exposing the object through the Window
Food object
Analyze properties and methods
Properties:
- The background color of the food
- Food width and speed
- Food positioning throughout the game interface —-top and left values
Methods:
- Food is rendered to the stage, so there needs to be a method of rendering to the stage, and random positioning is required
- Delete the food method. When the snake encounters the food, it needs to delete the food. Of course, considering that there may be multiple food in the later stage, it needs to create a food set to accommodate all the food
Code implementation
<! Create a new index.html file -->
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
<! -- Introducing styles -->
<link rel="stylesheet" href="./css/index.css">
</head>
<body>
<! -- Stage elements -->
<div class="box" id="box"></div>
<! -- External JS files introduced (only three so far, more to come)
<script src="./js/tools.js"></script>
<script src="./js/food.js"></script>
<script src="./js/index.js"></script>
</body>
</html>
Copy the code
/* Create an index. CSS file */
/* Style reset */
* {
margin: 0;
padding: 0;
}
/* Stage style */
.box {
position: relative;
width: 500px;
height: 500px;
background: #ccc;
}
Copy the code
// Create a new food.js file
// To avoid naming messy variables or functions globally, use the self-calling function (execute the function immediately) to define Food on window, followed by window. Food or simply call the constructor with Food
(function () {
// Create a variable. Store the location property of the food, which is set to absolute location
var ps = 'absolute';
// Create a new constructor
function Food(obj) {
// To avoid incorrect formatting of data passed in by the user, use a judgment that if the user passed in data of object type, use it directly, otherwise use empty object
obj = obj instanceof Object ? obj : {};
// Set the values of the five properties and give them default values in case the user does not enter them
/ / width
this.width = obj.width || 20;
/ / height
this.height = obj.height || 20;
//定位top
this.top = obj.top || 0;
/ / position left
this.left = obj.left || 0;
/ / the background color
this.backgroundColor = obj.backgroundColor || 'skyblue';
// Use an attribute to hold the element nodes that will be generated later, so that more than one food can be used later
this.items = [];
}
// Redefine the Food prototype object
Food.prototype = {
// Point to Food manually
constructor: Food,
// Render method, create a new element and render it to the stage
// Parameters: the stage to render to -- element, in this case box element
reader: function (father) {
// Sets the CSS style of the element
// Random top positioning value: Using the random number method of the tool object Tools, to avoid the occurrence of dislocation first, we split the stage into small squares
// Top = random number (0, stage height/food height -1) * food height
this.top = tools.getRandomNumber(0, father.clientHeight / this.height - 1) * this.height;
//left position value, same principle as above
this.left = tools.getRandomNumber(0, father.clientWidth / this.width - 1) * this.width;
// Create an element node
var fooder = document.createElement('span');
// Sets the element node attributes
// Locate attributes and use variables to facilitate later modification
fooder.style.position = ps;
/ wide/high
fooder.style.width = this.width + 'px';
fooder.style.height = this.height + 'px';
// Locate the offset property
fooder.style.top = this.top + 'px';
fooder.style.left = this.left + 'px';
/ / the background color
fooder.style.backgroundColor = this.backgroundColor;
// Add elements to the stage
father.appendChild(fooder);
// Store elements
this.items.push(fooder);
},
// Delete element method
// Parameter 1: stage element
// Argument 2: the subscript of the element to be deleted
remove: function (father, index) {
father.removeChild(this.items[index]);
this.items.splice(index, 1); }}// Store the constructor inside window. Since window can be omitted, we can use Food directly
window.Food = Food; }) ()Copy the code
// Create a new tools.js file
// a tool object to store methods that will be used
var tools = {
// Generate a random number
getRandomNumber: function (min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1) + min);
},
// Generate random colors
getRandomColor: function () {
return 'rgb(' + this.getRandomNumber(0.255) + ', ' + this.getRandomNumber(0.255) + ', ' + this.getRandomNumber(0.255) + ') '; }}Copy the code
The snake object
Properties and methods
Properties:
- The width and height of each snake joint
- Special attributes for each section: positioning left and top values, background color (snake head and body are different)
- The direction of movement of the snake
Methods:
- Render to stage method (Reader)
Code implementation
// Add the snake constructor to the window, just like food
(function () {
// Create a variable that represents the location of the snake node, set to absolute location
var ps = 'absolute';
// Snake constructor
function Snick(opt) {
// Determine if the passed argument is an object type, if yes, empty otherwise
opt = opt instanceof Object ? opt : {};
// Write the width and height properties and default values for the snake section
this.width = opt.width || 20;
this.height = opt.height || 20;
// Put each section of the snake body into an array for later modification
// Snake array: Each element inside is an object that stores the location properties and background color of the snake section
this.body = [
// The first one represents the head of the snake, and the rest represent each section of the snake's body. Note that the head and the body are prohibited in different colors
{
x: 3.y: 2.color: 'red'
}, {
x: 2.y: 2.color: 'blue'
}, {
x: 1.y: 2.color: 'blue'}].// The default movement direction of the snake is right, up, down, or left
this.direction = 'right';
}
// Redefine the constructor prototype object
Snick.prototype = {
// Point to the constructor manually
constructor: Snick,
// Render method
// Parameters: stage elements
reader: function (father) {
// We need to render each snake section to the stage, so we need to traverse the entire snake array
// Create two new variables to save reading this.body.length every time
for (let i = 0, len = this.body.length; i < len; i++) {
// Create a new element node
var me = document.createElement('span');
// Sets the inline style of the element node
// Location mode
me.style.position = ps;
/ wide/high
me.style.width = this.width + 'px';
me.style.height = this.height + 'px';
// Locate the offset property
me.style.top = this.body[i].y * this.height + 'px';
me.style.left = this.body[i].x * this.width + 'px';
// Background color
me.style.backgroundColor = this.body[i].color;
// Insert each section into the stagefather.appendChild(me); }}}// Assign the entire constructor to the window
window.Snick = Snick; }) ()Copy the code
The game object
Properties and methods
Properties:
- Food Object Instance
- Snake Object Instance
- The stage object
Methods:
- Initialization (Render food and snake initialization)
Code implementation
// Create a new game.jss
// Write to the self-calling function (immediately executed inside the function), again placing the constructor on the window object
(function () {
// Gameobject constructor
// Parameters: stage elements
function Game(map) {
// Three attributes
// Food instance
this.food = new Food();
/ / instance
this.snick = new Snick();
// Stage elements
this.map = map;
}
// Bloodshot gameobject prototype object
Game.prototype = {
// Execute the constructor
constructor: Game,
// Initialize the snake and food to the stage
inIt: function () {
this.food.reader(this.map);
this.snick.reader(this.map); }}// Put the game constructor above the window
window.Game = Game; }) ()// Test the code
// Get the stage
var map = document.getElementById('box');
// Create a game instance
var game = new Game(map);
// Perform game initialization
game.inIt();
Copy the code
Game logic implementation
Snake movement and game over
We need to add a motion method to the snake. We can do this using the previous snake instance’s Reader method (we can use a timer to execute the snake’s Reader method at regular intervals), but note that we need to remove the rendered snake before calling the method, otherwise you will find two snakes
Snake deletion method
Ideas:
- In order to delete we have to find the element to delete
- In our snake rendering method, every snake section added to the stage is stored in an array property (this.items)
- Add the remove method (remove) to the snake prototype to call the array traversal of this property to remove it
- And then we call the snake render method (Reader)
/ / snick. Js file
// Add the snick array to the snick constructor
this.items = [];
// Add the delete snake method to Snick
// Delete the snake method
// Parameters: stage elements
remove: function (father) {
// Iterate through the snake section array, removing each item from the stage element
for (let i = 0, l = this.items.length; i < l; i++) {
// Delete a node
father.removeChild(this.items[i]);
}
// Reset the snake node array
this.items = [];
}
Copy the code
Snake position update method
Ideas:
- Create a new upDate method for the snake instance.
- (Every time the snake moves, the snake body (except the head) will reach the position of the previous section, so we update the position of the previous section and assign the position to the next section, and the head will adjust itself according to the direction of movement).
/ / snick. Js file
// Add to the snick prototype object
// Snake node position update method
upDate: function () {
// Loop through the array of snakes, setting the location of each snake to the location of the previous one
for (let i = this.body.length - 1; i > 0; i--) {
this.body[i].x = this.body[i - 1].x;
this.body[i].y = this.body[i - 1].y;
}
// Modify the position of the snake head according to the direction of movement
switch (this.direction) {
case 'right':
this.body[0].x++;
break;
case 'left':
this.body[0].x--;
break;
case 'top':
this.body[0].y--;
break;
case 'buttom':
this.body[0].y++;
break; }}Copy the code
Make the snake move and stop the game beyond the edge
movement
We’ve already defined the snake delete method, position update method, and render method inside the snake, so all we need to do to move the snake is repeat delete, update, and render methods
Game over
We judge whether the head of the snake is beyond the edge of the game stage every time the snake moves. We can judge the x and Y values of the head of the snake. When x or Y is less than 0 or greater than the maximum score, the game can be stopped
Finally realize
We can write this whole process inside a function, so that we don’t need to write it inside the constructor, and write a timer inside the function that continuously executes the snake’s deletion, position update, render method, and each time decide whether to go beyond the stage edge.
Note that this points to a problem, because writing this inside an external function might invalidate this, so we need to manually place this
//game.js
// Write to the self-calling function (immediately executed inside the function), again placing the constructor on the window object
(function () {
// Define a variable that points to the constructor's this
var that;
// Gameobject constructor
// Parameters: stage elements
function Game(map) {
// Three attributes
// Food instance
this.food = new Food();
/ / instance
this.snick = new Snick();
// Stage elements
this.map = map;
// Assign this to that in the constructor
that = this;
}
// Rewrite the gameobject prototype object
Game.prototype = {
// Execute the constructor
constructor: Game,
// Initialize the snake and food to the stage
inIt: function () {
this.food.reader(this.map);
this.snick.reader(this.map);
// Call the snake movement function to execute the snake movement and the game end operationsnickRun(); }}// The snake movement function is a private function that can only be called internally. Note that this is used instead of this
function snickRun() {
// Create a timer that repeats the snake movement and determines the end of the game
var timer = setInterval(function () {
// Execute the snake delete method
that.snick.remove(that.map);
// Execute the snake position update method
that.snick.upDate();
// Execute the snake render method
that.snick.reader(that.map);
// Calculate the maximum number of copies, when the snake head x or Y exceeds the maximum number of copies, the game ends
var maxX = that.map.offsetWidth / that.snick.width;
var maxY = that.map.offsetHeight / that.snick.height;
// Determine the position of the snake head. Once it is found that the snake head exceeds the boundary, delete the timer and prompt the game to end
if (that.snick.body[0].x < 0 || that.snick.body[0].x >= maxX || that.snick.body[0].y < 0 || that.snick.body[0].y >= maxY) {
// Delete the timer
clearInterval(timer);
// The game is over
alert('Game over'); }},150)}// Put the game constructor above the window
window.Game = Game; }) ()// Test the code
// Get the stage
var map = document.getElementById('box');
// Create a game instance
var game = new Game(map);
// Perform game initialization
game.inIt();
Copy the code
Control the direction of the snake
We rely on the keyboard to control the direction of the snake’s movement, so we need to monitor the events of the keyboard press, identify the direction key press, and change the direction of the snake’s movement
// Listen for keyboard press events to change the direction of snake movement
function chageDirection() {
// Add the monitor keyboard press event to the entire page to determine the direction of the snake movement. Note that here to determine the original direction, do not set the reverse direction
document.onkeydown = function (e) {
// Get the value of the pressed key
var code = e.keyCode;
// Get the current direction
var direction = that.snick.direction;
// Change direction
switch (code) {
case 37:
that.snick.direction = direction === 'right' ? direction : 'left';
console.log(that.snick.direction);
break;
case 38:
that.snick.direction = direction === 'down' ? direction : 'up';
console.log(that.snick.direction);
break;
case 39:
that.snick.direction = direction === 'left' ? direction : 'right';
console.log(that.snick.direction);
break;
case 40:
that.snick.direction = direction === 'up' ? direction : 'down';
console.log(that.snick.direction); }}}Copy the code
The food disappears and the snake grows longer
Train of thought
1. Determine whether the positioning of the snake head is equal to the positioning of the food. If you want to wait, it means that they overlap and prove that you have eaten the food
2, after eating the food to generate new food, new food to perform the rendering method of food
3. To grow the snake after eating food, push a data in the snake’s body array. This data is the same as the data of the last item of the current snake
SnickRun () snickRun ()
// Determine whether the snake head overlaps with the food, and determine the location
if (that.snick.body[0].x * that.snick.width === that.food.left && that.snick.body[0].y * that.snick.height === that.food.top) {
// If it overlaps
// Delete the food
that.food.remove(that.map, 0);
// Create a new food
that.food.reader(that.map);
// Create a variable to get the last section of the snake
var last = that.snick.body[that.snick.body.length - 1];
// Add a section at the end of the snake
that.snick.body.push({
x: last.x,
y: last.y,
color: 'blue'
});
}
Copy the code
Upgrade the number of food \ hit yourself game over
The snake grows longer when the food disappears
-
We need to render multiple foods at initialization
-
Each time we move, we need to determine whether the head of the snake is on top of each food item, and we need to walk through the food array
//game.js inIt: function () { // Initializes adding three foods this.food.reader(this.map); this.food.reader(this.map); this.food.reader(this.map); this.snick.reader(this.map); // Call the snake movement function to execute the snake movement and the game end operation snickRun(); // Executes the change direction function to listen for global keypress eventschageDirection(); }}function snickRun() { // Create a timer that repeats the snake movement and determines the end of the game var timer = setInterval(function () { // Execute the snake delete method that.snick.remove(that.map); // Execute the snake position update method that.snick.upDate(); // Execute the snake render method that.snick.reader(that.map); // Calculate the maximum number of copies, when the snake head x or Y exceeds the maximum number of copies, the game ends var maxX = that.map.offsetWidth / that.snick.width; var maxY = that.map.offsetHeight / that.snick.height; // Multiple foods, traversing the food array to determine if it collided with the snake head for (let i = 0, l = that.food.items.length; i < l; i++) { // Get snakehead location and food location var headX = that.snick.body[0].x * that.snick.width, headY = that.snick.body[0].y * that.snick.height, foodX = parseFloat(that.food.items[i].style.left), foodY = parseFloat(that.food.items[i].style.top); // Determine the overlap between the snake head and the food if (headX === foodX && headY === foodY) { // Overlap delete food that.food.remove(that.map, i); // Create a new food that.food.reader(that.map); // Create a variable to get the last section of the snake var last = that.snick.body[that.snick.body.length - 1]; // Add a section at the end of the snake that.snick.body.push({ x: last.x, y: last.y, color: 'blue'}); }}// Determine the position of the snake head. Once it is found that the snake head exceeds the boundary, delete the timer and prompt the game to end if (that.snick.body[0].x < 0 || that.snick.body[0].x >= maxX || that.snick.body[0].y < 0 || that.snick.body[0].y >= maxY) { // Delete the timer clearInterval(timer); // The game is over alert('Game over'); } // Add snake head touching body to end game // Run through all snake segments except the snake's head, and determine whether they collide for (let i = 1, l = that.snick.body.length; i < l; i++) { // Check whether there is a collision if (that.snick.body[0].x === that.snick.body[i].x && that.snick.body[0].y === that.snick.body[i].y) { // Delete the timer clearInterval(timer); // The game is over alert('Game over'); }}},150)}Copy the code
Final code implementation
Note: there is no use of code compression and merge code operations, there is no parameter to the self-calling function, you can perform later
index.html
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
<! -- Introducing styles -->
<link rel="stylesheet" href="./css/index.css">
</head>
<body>
<! -- Stage elements -->
<div class="box" id="box"></div>
<! Import external js files -->
<script src="./js/tools.js"></script>
<script src="./js/food.js"></script>
<script src="./js/snick.js"></script>
<script src="./js/game.js"></script>
<script src="./js/index.js"></script>
</body>
</html>
Copy the code
Index.css
/* Style reset */
* {
margin: 0;
padding: 0;
}
/* Stage style */
.box {
position: relative;
width: 500px;
height: 500px;
background: #ccc;
}
Copy the code
Tools.js
// a tool object to store methods that will be used
var tools = {
// Generate a random number
getRandomNumber: function (min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1) + min);
},
// Generate random colors
getRandomColor: function () {
return 'rgb(' + this.getRandomNumber(0.255) + ', ' + this.getRandomNumber(0.255) + ', ' + this.getRandomNumber(0.255) + ') '; }}Copy the code
food.js
// To avoid naming messy variables or functions globally, use the self-calling function (execute the function immediately) to define Food on window, followed by window. Food or simply call the constructor with Food
(function () {
// Create a variable. Store the location property of the food, which is set to absolute location
var ps = 'absolute';
// Create a new constructor
function Food(obj) {
// To avoid incorrect formatting of data passed in by the user, use a judgment that if the user passed in data of object type, use it directly, otherwise use empty object
obj = obj instanceof Object ? obj : {};
// Set the values of the five properties and give them default values in case the user does not enter them
/ / width
this.width = obj.width || 20;
/ / height
this.height = obj.height || 20;
//定位top
this.top = obj.top || 0;
/ / position left
this.left = obj.left || 0;
/ / the background color
this.backgroundColor = obj.backgroundColor || 'skyblue';
// Use an attribute to hold the element nodes that will be generated later, so that more than one food can be used later
this.items = [];
}
// Redefine the Food prototype object
Food.prototype = {
// Point to Food manually
constructor: Food,
// Render method, create a new element and render it to the stage
// Parameters: the stage to render to -- element, in this case box element
reader: function (father) {
// Sets the CSS style of the element
// Random top positioning value: Using the random number method of the tool object Tools, to avoid the occurrence of dislocation first, we split the stage into small squares
// Top = random number (0, stage height/food height -1) * food height
this.top = tools.getRandomNumber(0, father.clientHeight / this.height - 1) * this.height;
//left position value, same principle as above
this.left = tools.getRandomNumber(0, father.clientWidth / this.width - 1) * this.width;
// Create an element node
var fooder = document.createElement('span');
// Sets the element node attributes
// Locate attributes and use variables to facilitate later modification
fooder.style.position = ps;
/ wide/high
fooder.style.width = this.width + 'px';
fooder.style.height = this.height + 'px';
// Locate the offset property
fooder.style.top = this.top + 'px';
fooder.style.left = this.left + 'px';
/ / the background color
fooder.style.backgroundColor = this.backgroundColor;
// Add elements to the stage
father.appendChild(fooder);
// Store elements
this.items.push(fooder);
},
// Delete element method
// Parameter 1: stage element
// Argument 2: the subscript of the element to be deleted
remove: function (father, index) {
father.removeChild(this.items[index]);
this.items.splice(index, 1); }}// Store the constructor inside window. Since window can be omitted, we can use Food directly
window.Food = Food; }) ()Copy the code
Snick.js
// Add the snake constructor to the window, just like food
(function () {
// Create a variable that represents the location of the snake node, set to absolute location
var ps = 'absolute';
// Snake constructor
function Snick(opt) {
// Determine if the passed argument is an object type, if yes, empty otherwise
opt = opt instanceof Object ? opt : {};
// Write the width and height properties and default values for the snake section
this.width = opt.width || 20;
this.height = opt.height || 20;
// Put each section of the snake body into an array for later modification
// Snake array: Each element inside is an object that stores the location properties and background color of the snake section
this.body = [
// The first one represents the head of the snake, and the rest represent each section of the snake's body. Note that the head and the body are prohibited in different colors
{
x: 3.y: 2.color: 'red'
}, {
x: 2.y: 2.color: 'blue'
}, {
x: 1.y: 2.color: 'blue'}].// The default movement direction of the snake is right, up, down, or left
this.direction = 'right';
// Create an array of snake nodes
this.items = [];
}
// Redefine the constructor prototype object
Snick.prototype = {
// Point to the constructor manually
constructor: Snick,
// Render method
// Parameters: stage elements
reader: function (father) {
// We need to render each snake section to the stage, so we need to traverse the entire snake array
// Create two new variables to save reading this.body.length every time
for (let i = 0, len = this.body.length; i < len; i++) {
// Create a new element node
var me = document.createElement('span');
// Sets the inline style of the element node
// Location mode
me.style.position = ps;
/ wide/high
me.style.width = this.width + 'px';
me.style.height = this.height + 'px';
// Locate the offset property
me.style.top = this.body[i].y * this.height + 'px';
me.style.left = this.body[i].x * this.width + 'px';
// Background color
me.style.backgroundColor = this.body[i].color;
// Insert each section into the stage
father.appendChild(me);
this.items.push(me); }},// Delete the snake method
// Parameters: stage elements
remove: function (father) {
// Iterate through the snake section array, removing each item from the stage element
for (let i = 0, l = this.items.length; i < l; i++) {
// Delete a node
father.removeChild(this.items[i]);
}
// Reset the snake node array
this.items = [];
},
// Snake node position update method
upDate: function () {
// Loop through the array of snakes, setting the location of each snake to the location of the previous one
for (let i = this.body.length - 1; i > 0; i--) {
this.body[i].x = this.body[i - 1].x;
this.body[i].y = this.body[i - 1].y;
}
// Modify the position of the snake head according to the direction of movement
switch (this.direction) {
case 'right':
this.body[0].x += 1;
break;
case 'left':
this.body[0].x -= 1;
break;
case 'up':
this.body[0].y -= 1;
break;
case 'down':
this.body[0].y += 1;
break; }}}// Assign the entire constructor to the window
window.Snick = Snick; }) ()Copy the code
Game.js
// Write to the self-calling function (immediately executed inside the function), again placing the constructor on the window object
(function () {
// Define a variable that points to the constructor's this
var that;
// Gameobject constructor
// Parameters: stage elements
function Game(map) {
// Three attributes
// Food instance
this.food = new Food();
/ / instance
this.snick = new Snick();
// Stage elements
this.map = map;
// Assign this to that in the constructor
that = this;
}
// Rewrite the gameobject prototype object
Game.prototype = {
// Execute the constructor
constructor: Game,
// Initialize the snake and food to the stage
inIt: function () {
// Initializes adding three foods
this.food.reader(this.map);
this.food.reader(this.map);
this.food.reader(this.map);
this.snick.reader(this.map);
// Call the snake movement function to execute the snake movement and the game end operation
snickRun();
// Executes the change direction function to listen for global keypress eventschageDirection(); }}// The snake movement function
function snickRun() {
// Create a timer that repeats the snake movement and determines the end of the game
var timer = setInterval(function () {
// Execute the snake delete method
that.snick.remove(that.map);
// Execute the snake position update method
that.snick.upDate();
// Execute the snake render method
that.snick.reader(that.map);
// Calculate the maximum number of copies, when the snake head x or Y exceeds the maximum number of copies, the game ends
var maxX = that.map.offsetWidth / that.snick.width;
var maxY = that.map.offsetHeight / that.snick.height;
// Multiple foods, traversing the food array to determine if it collided with the snake head
for (let i = 0, l = that.food.items.length; i < l; i++) {
// Get snakehead location and food location
var headX = that.snick.body[0].x * that.snick.width,
headY = that.snick.body[0].y * that.snick.height,
foodX = parseFloat(that.food.items[i].style.left),
foodY = parseFloat(that.food.items[i].style.top);
// Determine the overlap between the snake head and the food
if (headX === foodX && headY === foodY) {
// Overlap delete food
that.food.remove(that.map, i);
// Create a new food
that.food.reader(that.map);
// Create a variable to get the last section of the snake
var last = that.snick.body[that.snick.body.length - 1];
// Add a section at the end of the snake
that.snick.body.push({
x: last.x,
y: last.y,
color: 'blue'}); }}// Determine the position of the snake head. Once it is found that the snake head exceeds the boundary, delete the timer and prompt the game to end
if (that.snick.body[0].x < 0 || that.snick.body[0].x >= maxX || that.snick.body[0].y < 0 || that.snick.body[0].y >= maxY) {
// Delete the timer
clearInterval(timer);
// The game is over
alert('Game over');
}
// Add snake head touching body to end game
// Run through all snake segments except the snake's head, and determine whether they collide
for (let i = 1, l = that.snick.body.length; i < l; i++) {
// Check whether there is a collision
if (that.snick.body[0].x === that.snick.body[i].x && that.snick.body[0].y === that.snick.body[i].y) {
// Delete the timer
clearInterval(timer);
// The game is over
alert('Game over'); }}},150)}// Listen for keyboard press events to change the direction of snake movement
function chageDirection() {
// Add the monitor keyboard press event to the entire page to determine the direction of the snake movement. Note that here to determine the original direction, do not set the reverse direction
document.onkeydown = function (e) {
// Get the value of the pressed key
var code = e.keyCode;
// Get the current direction
var direction = that.snick.direction;
// Change direction
switch (code) {
case 37:
that.snick.direction = direction === 'right' ? direction : 'left';
console.log(that.snick.direction);
break;
case 38:
that.snick.direction = direction === 'down' ? direction : 'up';
console.log(that.snick.direction);
break;
case 39:
that.snick.direction = direction === 'left' ? direction : 'right';
console.log(that.snick.direction);
break;
case 40:
that.snick.direction = direction === 'up' ? direction : 'down';
console.log(that.snick.direction); }}}// Put the game constructor above the window
window.Game = Game; }) ()Copy the code
index.js
(function () {
// Get the stage
var map = document.getElementById('box');
// Create a game instance
var game = new Game(map);
// Perform game initializationgame.inIt(); }) ()Copy the code
Performance optimization
Reduce the number of SENDING HTTP requests
Put all the code into one file and pay attention to the order of reference
Compressed JS code
You can use the online – tool.oschina.net/jscompress/ compression tools
Problems with self-calling functions
This can cause problems if two self-calling functions are next to each other without a semicolon in between
Solution: Add a semicolon after or before a self-calling function. The best way is to add a semicolon before a self-calling function
Self-calling function arguments
- In the previous code, self-executing functions can add parameters and arguments to window
- Undefined may change in older browsers, and wrapping undefined in self-calling functions prevents it from being tampered with
Such as:
(function(window.undefined){body})(window.undefined)
Copy the code