H5 game development: Snake and h5 Game Development

Source: Internet
Author: User

H5 game development: Snake and h5 Game Development

There are two classic ways to play a snake:

The first is what I first experienced in the handheld game machine when I was a child (accidentally exposing my age). The specific method is to clear customs after a snake eats a certain amount of food, and the speed will increase after customs clearance; the second is the game that Nokia installed on its mobile phone in 1997. Its gameplay is to stop eating food. I want to implement the second method.

MVC design pattern

Based on the snake classic, the author also uses a classic design Model: MVC (Model-View-Control) when implementing it ). The various statuses and data structures of the game are managed by the Model. The View is used to display changes to the Model. The interaction between the user and the game is completed by the Control (the Control provides various game API interfaces ).

Model is the core of the game and the main content of this article. View involves some performance issues. Control is responsible for business logic. The benefit of this design is that the Model is completely independent, and the View is the Model state machine. Both the Model and View are driven by Control.

Model

Take a look at a classic image of a snake.

Web Front-end/H5/javascript Learning Group: 250777811

Welcome to follow this public account → [web Front-end EDU] and learn the front-end together! You are welcome to leave a message to discuss and forward it together.

A snake has four key participants:

Stage ism * nMatrix (two-dimensional array), the index boundary of the matrix is the wall of the stage, and the Members on the matrix are used to mark the location of food and snakes.

The empty stage is as follows:

[[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],]

Food (F) and snakes (S) appear on the stage:

[[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,F,0,0,0,0,0,0,0],[0,0,0,S,S,S,S,0,0,0],[0,0,0,0,0,0,S,0,0,0],[0,0,0,0,S,S,S,0,0,0],[0,0,0,0,S,0,0,0,0,0],[0,0,0,0,S,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],]

Because the operations on two-dimensional arrays are not as convenient as one-dimensional arrays, we use one-dimensional arrays as follows:

[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,F,0,0,0,0,0,0,0,0,0,0,S,S,S,S,0,0,0,0,0,0,0,0,0,S,0,0,0,0,0,0,0,S,S,S,0,0,0,0,0,0,0,S,0,0,0,0,0,0,0,0,0,S,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,]

On the stage matrix, snakes and foods only map the two on the stage. Each of them has an independent data structure:

  • A snake is a coordinate index linked list;
  • Food is an index that points to the coordinates of the stage.
Snake Activity

There are three types of snake activity:

  • Move)
  • Eat)
  • Collision)
Mobile

What changes have taken place inside a snake while it is moving?

The snake chain table does two things during a moving process: Insert a new node to the header, and remove an old node at the end of the table. If an array is used to represent a snake chain table, the movement of the snake is the following pseudocode:

function move(next) {snake.pop() & snake.unshift(next); } 

Is it appropriate to use arrays as a snake chain table? This is the question that I first thought about. After all, the arrayunshift & popIt can seamlessly represent the movement of snakes. However, convenience does not mean good performance,unshiftThe time complexity of inserting elements into an array is O (n ),popThe time complexity of removing the elements at the end of the array is O (1 ).

The movement of a snake is a high-frequency action. If the algorithm complexity of an action is O (n) and the length of the snake is large, the game performance may be faulty. The greedy snake I want to implement is theoretically a long snake, so my reply in this article is ------ arrays are not suitable for use as a snake chain table.

A snake chain table must be a real linked list structure. The time complexity of deleting or inserting a node in the linked list is O (1). Using the linked list as the data structure of the snake chain table can improve the game performance. Javascript does not have a ready-made linked list structure. I wrote a Chain List class called Chain,ChainProvidedunshfit & pop. The following Pseudo Code creates a snake chain table:

let snake = new Chain(); 

Food & Collision

The difference between "food" and "Collision" is that food hits "food" and hits "wall 」. The author believes that "food" and "Collision" are two branches of the three possible results of a snake moving at a time. Three possible outcomes of snake movement are: "forward", "eat", and "Collision 」.

Let's look back at the pseudocode of snake movement:

function move(next) {snake.pop() & snake.unshift(next); } 

In the codenextIndicates the index value of the grid to be entered by the snake header, only when this grid is0When the snake can "forward", when this grid isSIndicates "colliding" yourself. When this grid isFIt indicates eating.

Seems to have missed the wall? During the design process, the author did not design the wall in the matrix of the stage, but expressed the wall hit by indexing. Simply putnext === -1It indicates the perimeter and hitting the wall.

The following pseudocode indicates the snake's overall activity process:

// B indicates hitting the wall let cell =-1 = next? B: zone [next]; switch (cell) {// food case F: eat (); break; // hit your case S: collision (S); break; // wall hitting case B: collision (B): break; // forward default: move ;}

 

Random feeding

Random feeding refers to the random selection of an index value on the stage to map the location of the food. This seems simple. You can directly write it like this:

// Pseudocode food = Math. random (zone. length)> 0;

If you consider the premise that the food is not overlapped with the snake body, you will find that the random code above does not guarantee that the food feed location does not overlap with the snake body. Because the security of this algorithm is gambling, it is called the "gambling algorithm 」. To ensure food safety, I have extended the algorithm:

// Pseudo-code function feed () {let index = Math. random (zone. length)> 0; // is the current position occupied return zone [index] = S? Feed (): index;} food = feed ();

 

Although the above Code can theoretically ensure the absolute security of food consumption, the author calls this algorithm a gambling algorithm 」, because the above algorithm has a fatal BUG ------ excessive recursion or endless loop.

To solve the above fatal problem, I have designed the following algorithms for random feeding:

// Pseudo-code function feed () {// number of unused spaces let len = zone. length-snake. length; // if (len = 0) return; // zone index let index = 0, // space counter count = 0, // The rnd blank lattice is the final position for food consumption. rnd = Math. random () * count> 0 + 1; // The total number of spaces while (count! = Rnd) {// The current grid is empty. Add a zone [index ++] ===0 & ++ count;} return index-1;} to the total count ;} food = feed ();

 

The average complexity of this algorithm is O (n/2 ). The O (n/2) complexity does not cause any performance problems because it is a low-frequency operation. However, I think the complexity of this algorithm is still a bit high. Looking back at the first "gambling algorithm", although the "gambling algorithm" is unreliable, it has an advantage-time complexity is O (1 ).

Reliable Probability of the gambling algorithm = (zone. length-snake. length)/zone. length.snake.lengthIs a dynamic value, and its change range is:0 ~ zone.length. The average Reliable Probability of the "gambling algorithm" is as follows:

"Gambling algorithm" average Reliable Probability = 50%

It seems that the gambling algorithm can still be used. So I re-designed an algorithm:

// Pseudo-code function bet () {let rnd = Math. random () * zone. length> 0; return zone [rnd] === 0? Rnd:-1;} function feed () {...} food = bet (); if (food =-1) food = feed ();

 

The average complexity of the new algorithm can be effectively reduced to O (n/4), and sometimes it takes some luck in life :).

View

In View, you can select a game rendering engine based on your preferences.PIXIAs a game rendering engine.

View has two main tasks:

That is to say, View is the process of restoring the design draft using the rendering engine. The purpose of this article is to introduce the implementation of "snake". How to use a rendering engine is not the scope of this article. The author wants to introduce "How to Improve rendering efficiency 」.

The snake that shows the Model in the View can be simply like the following pseudocode:

// Clear the snake View on The view. snake. clean (); model. snake. forEach (node) =>{ // create the snake node on the View let viewNode = createViewNode (node); // combine a new snake view. snake. push (viewNode );});

 

The time complexity of the above Code is O (n ). As mentioned above, snake movement is a high-frequency activity. We should try to avoid running O (n) code at a high frequency. To analyze three snake activities: "mobile", "food", and "Collision 」.

First, the Model has a "Collision", and the View should be directly paused in the rendering Model. The game is in the dead state, and the next cause is Control.

The snake (linked list) in the Model does two things during a "move" process: Insert a new node to the header, and remove an old node from the end of the table; the snake (Linked List) during a "food" operation, you only need to insert a new node to the header.

If you perform a differentiation check on the snake chain table of the Model in the View, if the View only incrementally updates the difference, the time complexity of the algorithm can be reduced to O (1 )~ O (2 ). The following is the optimized pseudocode:

Let snail KEA = model. snake, snail KEB = view. snake; // incrementally update the tail while (snakey B. length <= snail Kea. length) {headA = snail Kea. next (); // the header node matches if (headA. data = headB. data) break; // The else does not match {// Insert the header node if (snail Kea. HEAD === headA. index) {snail KEB. unshift (headA. data);} // Insert the second node else snail KEB to the snakb. insertAfter (0, headA. data) ;}} // incrementally update the header let tailA = snakey. last (), tailB; while (snail KEB. length! = 0) {tailB = snail KEB. last (); // The End Node matches if (tailA. data = tailB. data) break; // does not match else snakb. pop ();}

 

Control

Control mainly involves three tasks:

"Game-user interaction" refers to the APIs and events that need to be used in external game provision. The proposed APIs is as follows:

Name Type Deltail
Init Method Game Initialization
Start Method Start the game
Restart Method Start the game again
Pause Method Pause
Resume Method Restore
Turn Method Control the steering of a snake. For example: turn ("left ")
Destroy Method Destroy a game
Speed Property Speed of snake Movement

The event is as follows:

Name Detail
Countdown Hours
Eat Food
Before-eat Trigger before eating
Gameover Game ended

Events are uniformly mounted under game instances.eventObject.

Snake. event. on ("countdown", (time) => console. log ("remaining time:", time ));

"Driving Model" only does one thing ------ update the direction of the Model snake to the direction specified by the user. "Synchronous View and Model" is also relatively simple. Check whether the Model has been updated. If there is an update notification, View updates the game interface.

Conclusion

Add the source code of the snake Project

Web Front-end/H5/javascript Learning Group: 250777811

Welcome to follow this public account → [web Front-end EDU] and learn the front-end together! You are welcome to leave a message to discuss and forward it together.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.