In the previous section, we left a flyin method not introduced. Here we want to write a separate HTML5 animation implementation.
In section 2, we drew a bubble and successfully wiped the bubble. But at that time, we also said that we should not erase the line of the board, so we made an offset. So HTML5 canvas is still low-level, and there is no layer concept. If you erase it and try to make it back, how can you make it? The answer is re-painting. Yes, the entire canvas is re-painted, so you don't have to worry about where to fill it. Although it brings performance loss, it definitely reduces the coding difficulty. In addition, the computer's ability is not inferior. In this case, the draw method should be used for all the objects to be drawn on the canvas. This is required. In addition, all elements have the upper and lower concepts. Therefore, you must first draw the following elements and then draw the above elements. The upper and lower layers depend on the concept of child elements. In this way, after the parent element is drawn, the child element is traversed to be drawn, so there is no need to worry about masking.
If you want to "fly" the three bubbles in the ready area, you need to re-paint the canvas when the bubble moves. The re-painting is not required when the bubble does not move. The movement of a bubble is easy to implement, as long as the X and Y coordinates of the bubble are changed. If you want to achieve the animation effect, You Have To regularly re-paint the animation during the coordinate change, you can use setinterval.
In addition, we not only need to re-paint the flying movements, but after the game starts, the players also need to click to move a bubble to another lattice, so we need to re-paint it here. So much information will be drawn, and the whole re-painting work will be handed over to game. Game controls all the parent elements.
Start: function () {This. map. init (); this. ready. init (); this. draw (); this. canvas. onclick = This. onclick ;}, over: function () {alert ("game over") ;}, draw: function () {This. CTX. clearrect (0, 0,400,600); this. CTX. save (); this. map. draw (); this. ready. draw (); this. CTX. restore () ;}, play: function (action, interval) {var me = This; play = setinterval (function () {Action (); me. draw () ;}, interval | 1) ;}, stop: function () {clearinterval (play); this. draw (); // console. log (this. ready. bubbles. length );},
Game. Start is used to initialize all parent elements,
No need to mention game. Over, but it is not specific here.CodeThe operation bubble cannot be continued at the end.
Game. Draw draws all parent Elements
Game. Play is the re-painting method. This method is used when re-painting is required. Receives two parameters. The first parameter is the action to be taken during repainting, and the interval parameter is the draw interval. Different actions may have different intervals.
It is possible that this implementation is a wild path. The real re-painting should be called instead of calling the re-painting method after the game starts, but only in the specific genie (each element) the Update Status is like the action here. This is the current implementation. If the re-painting Code cannot be reconstructed later, the core code remains unchanged, but the modification mechanism is not a big problem.
Game. Stop stops re-painting and calls a draw again to ensure that the final painting is correct.
next, consider the implementation of flyin. Knowing the XY coordinates of the start and end, the flying path is not a problem. It is nothing more than the addition, subtraction, and subtraction of x y. In terms of animation, our game. the action of play is to add or subtract ready. the XY coordinate of the bubbles. The logic of flying in is not that simple. First, three spaces are not stained. If there are less than three spaces, then gameover is required. Therefore, map needs to provide a method to return three blank grids. In addition, after a new bubble is generated in the ready area, the flying bubbles need to be deleted, and the map needs to dye the three blank grids. This completes the entire inbound effect.
another logic is to check whether bubbles can be eliminated after the flight is completed. Let's talk about this later.
first, you can obtain three spaces:
Getemptybubbles: function () {var empties = []; this. Bubbles. foreach (function (ROW) {row. foreach (function (bubble) {If (! Bubble. color) {empties. push (new bubble (bubble. x, bubble. y) ;}}) ;}); If (empties. length <= 3) {game. over (); return [];} var result = []; var useds = []; for (VAR I = 0; I <empties. length; I ++) {If (result. length = 3) {break;} var isused = false; var Ra = game. getrandom (empties. length); For (VAR m = 0; m <useds. length; m ++) {isused = Ra === useds [m]; If (isused) break;} If (! Isused) {result. Push (empties [Ra]); useds. Push (RA) ;}} console. Log (useds); return result ;},
There is still a lot of code to get three random spaces... Then there is the implementation of flyin.
First, set the status one by one to store the status of the fly in. The logic behind the three steps can be implemented only after they are completed. The bubble object also adds the PX and Py members (the actual coordinates of the bubble) to control the movement of each pixel. In fact, I wrote code for a long time when calculating the flying path. Although there are just a few lines of code, the development process is still quite laborious. A variety of weird flights... The flight starts from X ++ y ++. This is a 45 ° flight, but it is clear that the inclination of the flight line (from the start to the end) is not 45 °, it would be silly to fly X or Y first and then go straight. Therefore, the slope is used to calculate the current y coordinate. The coordinates of X can be fixed and changed in Changshu. I drew a slope formula. If you forget it, you can take a look. The current y value can be calculated based on the ratio of length to width.
Flyin: function () {var emptys = game. map. getemptybubbles (); If (emptys. length <3) {// game overgame. over (); return;} var me = This; var status = [0, 0, 0]; game. play (function () {If (status [0] & status [1] & status [2]) {game. stop (); status = [0, 0, 0]; me. bubbles = []; me. genrate (); return;} For (VAR I = 0; I <me. bubbles. length; I ++) {If (status [I]) {continue;} var target = emptys [I]; var X2 = target. PX + game. map. startx-me. startx; var y2 = target. PY + game. map. starty-me. starty; var current = me. bubbles [I]; var tmpwidth = 2; If (current. px <X2) {current. py = (Y2-current. PY)/(x2-current. px) * tmpwidth + current. PY; current. PX + = tmpwidth;} else if (current. px> x2) {current. py = (Y2-current. PY)/(current. PX-X2) * tmpwidth + current. PY; current. PX-= tmpwidth;} else {current. PY + = tmpwidth;} If (current. PY> Y2) {current. py = Y2;} If (current. px> x2) {current. px = x2;} If (current. px = X2 & current. py = Y2) {status [I] = 1; current. X = target. x; current. y = target. y; game. map. addbubble (current); console. log (1 );}}});}
Now that we have implemented the animation effect, we will implement another animation effect by the way, that is, when the bubble is clicked, the bubble will respond (that is, the flash will flash ), otherwise, the user does not know it. Therefore, you must add a flashing action to the bubble.
The Code indicates that the brightness of a light is re-painted at an interval of 50 milliseconds, and the brightness value (outer circle radius) is between 10 and 30. In this way, the light is dark, and then the light is dark. Interesting :)
Bubble. prototype. play = function () {var me = This; var ISUP = true; game. play ("Light _" + this. X + "_" + this. y, function () {If (ISUP) {me. light ++;} If (! ISUP) {me. light --;} If (Me. light = 30) {ISUP = false;} If (Me. light = 10) {ISUP = true ;}, 50) ;}; bubble. prototype. stop = function () {// This. light = 10; var me = This; game. stop ("Light _" + this. X + "_" + this. y); game. play ("Restore _" + this. X + "_" + this. y, function () {If (Me. light> 10) {me. light --;} else {me. light = 10; game. stop ("Restore _" + me. X + "_" + me. y) ;}}, 50 );};
Careful friends may find that a parameter is added to the parameter that calls the game. Stop method. Here I want to explain. If no parameters exist, game. play and stop will cause problems, because they all use an interval, clear will interrupt other animations, so we need to pass a name for each action, this allows the game to control each action in a finer granularity. The playback code of game has also been adjusted as follows:
Play: function (name, action, interval) {var me = this; this. actions [name] = setinterval (function () {Action (); me. draw () ;}, interval | 1) ;}, stop: function (name) {clearinterval (this. actions [name]); this. draw ();},
Demo address: http://jsfiddle.net/maddemon/VtMSU/embedded/result/