Canvas makes flappy bird (pixel bird) Full process, canvasflappy

Source: Internet
Author: User

Canvas makes flappy bird (pixel bird) Full process, canvasflappy
Flappy bird production process:

I. Preface

Pixel birds, a simple game, became popular on the Internet in 2014. During a period of time when the game went online, the download volume on the appleStore reached 50 million times,

In recent years, the popularity of mobile web has provided a good environment for interesting games without complex logic and exquisite animation effects,

At the same time, thanks to the communication effects of various social software platforms, creative games have a good marketing effect and won a lot of attention.

I used to query a lot of information about this game on the Internet, but most of them were disorganized. I used my own tutorials to sort out the main framework of this game for everyone to learn.

Ii. Technical Points

Basic JavaScript basics, canvas basics, and object-oriented thinking;

Iii. logic of the entire game is simple:

First, the game rules: birds hit the pipe, the ground to death, fly outside the screen to death.

Second, the bird will fall when it is flying, similar to the falling body movement. players need to constantly click the screen to let the bird fly up.

The next step is the relative movement of birds and background elements. Birds do not move, and the background moves left.

Refine the entire game:

We use the object-oriented idea to create specific things. The methods are put into the original object of the constructor.

The process of refining the game is not achieved overnight. If there is no relevant guidance, you must constantly combine your own ideas to try and make mistakes.

I am using Xmind to draw the process in the form of a brain image, do it in blocks, and constantly record my ideas. The final result is as follows:

(View the brain image, material, and complete source code by sequence number in the image:Http:// who want to practice can click here)

Brain graphs are divided into three major parts: 1. Preparation Phase 2. Main Function 3. Game optimization.



4. Game implementation:

Now we can use brain graphs to gradually implement our games.

1. Set the canvas and prepare image data. After the image is loaded, run the callback function;

<Canvas id = "cvs" width = "800" height = "600"> </canvas> <script> var imglist = [{"name": "birds ", "src": "res/birds.png" },{ "name": "land", "src": "res/land.png" },{ "name": "pipe1 ", "src": "res/pipe1.png" },{ "name": "pipe2", "src": "res/pipe2.png" },{ "name": "sky ", "src": "res/sky.png"}]; var cvs = document. getElementById ("cvs"); var ctx = cvs. getContext ("2d"); </script>Canvas preparation and image data preparation

Note the setting of this entry function here. You must ensure that other operations are performed after the image resources are loaded. For every image loaded, let's reduce imgCount -- to 0 and then execute the main function;

Function load (source, callback) {var imgEls ={}; var imgCount = source. length; for (var I = 0; I Set the main loop: here we do not use setInterval to control the number of loops. We use a timer called requestAnimationFrame ().

Because setInterval produces a time error, setInterval can only move a fixed Distance Based on time.

This has nothing to do with the thousands of milliseconds of switching operations in a carousel image, but it is very inaccurate for us to draw an animation every 16-18 milliseconds;

The advantage of the requestAnimationFrame () timer is to execute a function based on the browser's performance, which is used to obtain the interval between two draws;

The Calculation of moving distance is changed to speed X interval to solve the problem of inaccurate plotting.

Var preTime = Date. now (); // obtain the current time function run () {var now = Date. now (); // obtain the latest time dt = now-preTime; // obtain the time interval preTime = now; // update the current time ctx. clearRect (800,600,); // clear the canvas // empty draw the code execution area // empty requestAnimationFrame (run); // run the run function again} requestAnimationFrame (run ); // execute the run function for the first time;Set drawing mode

2. The main function is divided into two parts. Simply put, the main function is to display the picture, process the dynamic effect, and determine whether the foul is performed.

2.1 birds:

The bird has a wing fan effect and a falling process.

Wing fan is a switching of three images in a Sprite (setting an index attribute to control the position of the sprite). The dropping process is the moving of its y coordinate on the canvas ();

Therefore, the bird constructor should include parameters such as (MAP source, x coordinate, y coordinate, speed, fall acceleration, ctx (context canvas.

Note the following points:

  • The drawing of birdies adopts the Nine-parameter mode of canvas drawImage (they are the image, the cropping starting point of the source image, the width and height of the source image, the position attached to the canvas, and the width and height attached to the canvas );
  • The wings of the bird cannot fan too fast, so we set a valve function. When the accumulated timing exceeds 100 ms, switch one piece, and then subtract ms from the accumulated timing;
  • The whereabouts of birds require a certain amount of physical knowledge, but they are all very simple. We all achieve this through speed X time;
Var Bird = function (img, x, y, speed, a, ctx) {this. img = img; this. x = x; this. y = y; this. speed = speed; this. a = a; this. ctx = ctx; this. index = 0; // used to make the action of the Bird's wings} Bird. prototype. draw = function () {this. ctx. drawImage (this. img, 52 * this. index, 0, 52, 45, this. x, this. y, 52,45)} var durgather = 0; Bird. prototype. update = function (dur) {// change the animation durgather + = dur every 100 ms after the bird wings fan; if (durgather>) {this. index ++; if (this. index = 2) {this. index = 0;} durgather-= 100;} // this. speed = this. speed + this. a * dur; this. y = this. y + this. speed * dur ;}Constructor and action control of birds

Construct a bird and place its action refresh function and draw function in the painting area we mentioned above. The following operations are performed on similar objects:

One thing to note here is that it is still physical knowledge to let the birds fly up smoothly. Due to the acceleration, we can give the birds a smooth speed.

Load (imglist, function (imgEls) {// create an object // create a bird var Bird = new bird (imgEls ["birds"], 150,100, 0.0003, 0.0006, ctx); // main loop var preTime = Date. now (); function run () {var now = Date. now (); dt = now-preTime; preTime = now; ctx. clearRect (0, 0, 800,600); // -------- image Plot Area ------- bird. update (dt) bird. draw (); // ------------------------- requestAnimationFrame (run);} requestAnimationFrame (run); // set the click event. Give the bird an instantaneous upward speed cvs. addEventListener ("click", function () {bird. speed =-0.3 ;})})Draw birds and click birds to fly

The effect is as follows:

2.2 draw the sky:

The sky is easy to draw. You only need to use the three-parameter mode of canvas drawImage (MAP source and coordinates on the canvas ).

The only note here is that for the seamless rolling implementation, we can create two sky objects for the 800*600 resolution, but to adapt to more situations, let's write this function live.

Add the count attribute to the sky constructor to set several sky images. The count attribute allows the instance to access the images through the original method. This consideration is added to the repeated ground and pipelines.

Var Sky = function (img, x, speed, ctx) {this. img = img; this. ctx = ctx; this. x = x; this. speed = speed;} Sky. prototype. draw = function () {this. ctx. drawImage (this. img, this. x, 0)} Sky. prototype. setCount = function (count) {Sky. count = count;} Sky. prototype. update = function (dur) {this. x = this. x + this. speed * dur; if (this. x <-800) {// The width of the sky image is 800 this. x = Sky. count * 800 + this. x; // immediately switch back to the first image after moving the entire image to the left }}Sky constructor and motion function

Similarly, create two sky objects in the main function, and place the UPDATE function and the drawing function in the painting area of the main loop;

Setcount is used to set seamless scrolling.

Note: There is a hierarchical relationship between the pictures you draw and the birds cannot be painted below the sky. Of course, the final issue of overwriting is not mentioned here.

Only some related code is inserted here.

Var bird = new Bird (imgEls ["birds"], 150,100, 0.0003, 0.0006, ctx); var sky1 = new Sky (imgEls ["sky"], 0,-0.3, ctx); var sky2 = new Sky (imgEls ["sky"], 800,-0.3, ctx); // main loop var preTime = Date. now (); function run () {var now = Date. now (); dt = now-preTime; preTime = now; ctx. clearRect (800,600,); // -------- Image Rendering area ------- sky1.update (dt); sky1.draw () sky2.update (dt); sky2.draw () sky1.setCount (2); bird. update (dt) bird. draw ();//-------------------------Draw the sky

2.3 plot the ground

It is exactly the same as that of the sky. because the size of the ground image is small, we need to draw a few more images.

Var Land = function (img, x, speed, ctx) {this. img = img; this. x = x; this. speed = speed; this. ctx = ctx;} Land. prototype. draw = function () {this. ctx. drawImage (this. img, this. x, 488)} Land. prototype. setCount = function (count) {Land. count = count;} Land. prototype. update = function (dur) {this. x = this. x + this. speed * dur; if (this. x <-336) {this. x = this. x + Land. count * 336; // seamless rolling }}Ground constructor and motion function // create ---- place In the creation area var land1 = new Land (imgEls ["land"], 0,-0.3, ctx ); var land2 = new Land (imgEls ["land"], 336*1,-0.3, ctx); var land3 = new Land (imgEls ["land"], 336*2, -0.3, ctx); var land4 = new Land (imgEls ["land"], 336*3,-0.3, ctx ); // draw ---- place in the drawing area land1.update (dt); land1.draw (); land2.update (dt); land2.draw (); land3.update (dt); land3.draw (); land4.update (dt ); land4.draw (); land1.setCount (4); // sets seamless scrolling.Draw main ground code

2.4 draw Pipelines

One difficulty in pipeline painting is the determination of pipeline height.

Key points:

  • To ensure game playability, the pipeline must have a fixed height + a random height, and the white spaces between the upper and lower pipelines are fixed width.
  • The pipeline is not continuous, and there is an interval between two adjacent Pipelines
  • Note that the pipeline is playing seamlessly. After pulling back, you must pay a new random height to give the user the illusion that another pipeline has floated.


Var Pipe = function (upImg, downImg, x, speed, ctx) {this. x = x; this. upImg = upImg; this. downImg = downImg; this. speed = speed; this. ctx = ctx; this. r = Math. random () * 200 + 100; // random height + fixed height} Pipe. prototype. draw = function () {this. ctx. drawImage (this. upImg, this. x, this. r-420 // The length of the pipeline image is 420) this. ctx. drawImage (this. downImg, this. x, this. r + 150 // The White block set in the pipeline is 150px)} Pipe. prototype. setCount = function (count, gap) {Pipe. count = count; Pipe. gap = gap; // here is the special point of this drawing. The interval} Pipe is added. prototype. update = function (dur) {this. x = this. x + this. speed * dur; if (this. x <-52) {// MPs queue width 52px this. x = this. x + Pipe. count * Pipe. gap; // seamlessly scroll this. r = Math. random () * 200 + 150; // The height of the switched pipeline must be set again to give the user the illusion of a new pipeline }}Pipeline constructor and motion function // create region var pipe1 = new Pipe (imgEls ["pipe2"], imgEls ["pipe1"], 400,-0.1, ctx ); var pipe2 = new Pipe (imgEls ["pipe2"], imgEls ["pipe1"], 600,-0.1, ctx ); var pipe3 = new Pipe (imgEls ["pipe2"], imgEls ["pipe1"], 800,-0.1, ctx ); var pipe4 = new Pipe (imgEls ["pipe2"], imgEls ["pipe1"], 1000,-0.1, ctx ); var pipe5 = new Pipe (imgEls ["pipe2"], imgEls ["pipe1"], 1200,-0.1, ctx); // draw the region pipe1.update (dt ); pipelines (); pipe2.update (dt); pipe2.draw (); pipe3.update (dt); pipe3.draw (); pipe4.update (dt); pipe4.draw (); pipe5.update (dt); pipe5.draw (); pipe1.setCount (5,200); // you can specify the number and interval of pipelines.Main Code for pipeline painting

In this step, the main screen is created. Isn't it very simple? O (∩ _ ∩) O ~

2.5 determine whether the game is foul

// Let's rebuild the main loop and set a gameover to false to control function execution. // any violation will trigger gameover = true; var gameover = false; if (bird. y <0 | bird. y> 488-45/2) {// if (! Gameover) {// if the game is not over, continue to the game requestAnimationFrame (run );}Simple interpretation of gameover

2. End the game with a pipe

// When x and y arrive, we will pass in the motion track of the bird. Every time we redraw the pipeline, we will judge Pipe. prototype. hitTest = function (x, y) {return (x> this. x & x <this. x + 52) // In the middle of the tube horizontal &&(! (Y> this. r & y <this. r + 150); // in the vertical middle of the pipe}Determine whether a pipe var gameover = false; gameover = gameover | pipe1.hitTest (bird. x, bird. y); gameover = gameover | pipe2.hitTest (bird. x, bird. y); gameover = gameover | pipe3.hitTest (bird. x, bird. y); gameover = gameover | pipe4.hitTest (bird. x, bird. y); gameover = gameover | pipe5.hitTest (bird. x, bird. y); // logic terminal if (bird. y <0 | bird. y> 488-45/2) {gameover = true;} if (! Gameover) {requestAnimationFrame (run );}Integration of judgment conditions of the main cycle

At this point, our game is almost completed, and the rest is the correction of some data.

The primary point to be corrected is the collision calculation, because all our collisions are calculated in the upper left corner of the bird image, which leads to inaccurate problems, after testing, it is easy to add or subtract this distance.


3. Game Optimization

How can the birds of the bird game achieve this effect as they click and fly up or down?

The answer is to move the canvas coordinate system and select the angle ctx. translate () and ctx. rotate () of the coordinate system ();

To prevent the overall rotation of the entire coordinate system from moving

You need to add ctx. save () and ctx. restore () to the front and back of the Bird drawing function Bird. prototype. draw to separately control the Bird canvas.

Bird. prototype. draw = function () {this. ctx. save (); this. ctx. translate (this. x, this. y); // move coordinates to the center of the bird. this. ctx. rotate (Math. PI/6) * this. speed/0.3); // The bird rotates for a maximum of 30 degrees, and changes the angle as the speed changes in real time this. ctx. drawImage (this. img, 52 * this. index, 52/2, 45,-45/2,-, // The important thing here is that the entire bird coordinate system begins to move) this. ctx. restore ();}Add the bird rotation effect

Of course, do not forget to judge the pipe collision. Correct it again here.

In fact, if you want to add the rotation effect, the last correction is not needed, and you will find many repeated jobs.

The final result is as follows:

All the effects and logic of the subject have been implemented. You can add more results on your own.

If you want to practice it yourself, click the link in the details section of the game to download the relevant materials and all the source code.

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: 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.