After reading several Canvas-related articles, I found that the code implementation in the first two sections is still problematic. Because I know little about it, I can only implement it on my own known knowledge. But fortunately, this is a process of discovery and a process of correction and improvement. I tried to write my blog for the first time. I think this will also help me to learn more. I can learn more about it, but forget it slowly at least :).
The first two sections learned several basic plotting methods, lineTo moveTo and arc, and also learned about coordinates. However, it is silly to write, but it is just a simple implementation. For example, if the start coordinate of the checker has an offset, We need to calculate its specific start coordinate and end coordinate. In fact, Canvas has an existing method to provide the offset function. His name is translate, and he also has scaling and rotating rotate. They can all be replaced by transform. So there will be some adjustments in the code. However, this learning also happens to let me know how to achieve the animation effect. If multiple elements are on the same Canvas, animation will inevitably need to be erased and re-painted. If there is a coverage between elements, erasure needs to be considered. Of course, the simple method is to re-draw the entire canvas based on the positions of all elements. Therefore, in code design, we need to separate different elements. Each element has its own draw method and draw a Canvas in order.
Analyze the elements required by the game: 1. Board (MAP) 2. Bubble 3. Waiting area (New Three Bubbles about to enter the Board) 4. Reward area (White Star, super wild star, bomb) 5. Statistics 6. Buttons
Therefore, there must be at least several types of maps, ready, awards, bubble, and star1 in the design of objects) stars 2 (star2), bombs (boom), and scores, as well as data behind the game ). OK. First, implement it one by one. First, rewrite map and bubble.
Previously, I wrote map as a class, which is obviously not suitable. Because this game cannot have multiple maps, it is more convenient to define it as an object directly. Bubbles obviously require a lot, so it is easier to write classes. Global variables and constants that all objects in the game need to access must be defined in a game object. The game starts by calling game. start. So let's take a look at the definition of game:
[Javascript]
Var game = {canvas: document. getElementById ("canvas"), ctx: this. canvas. getContext ("2d"), cellCount: 9, cellWidth: 30, lineCount: 5, mode: 7, colors: ["red", "#039518", "# ff00dc ", "# ff6a00", "gray", "# 0094ff", "# d2ce00"], over: function () {alert ("game over");}, getRandom: function (max) {return parseInt (Math. random () * 1000000% (max ));},};
Var game = {canvas: document. getElementById ("canvas"), ctx: this. canvas. getContext ("2d"), cellCount: 9, cellWidth: 30, lineCount: 5, mode: 7, colors: ["red", "#039518", "# ff00dc ", "# ff6a00", "gray", "# 0094ff", "# d2ce00"], over: function () {alert ("game over");}, getRandom: function (max) {return parseInt (Math. random () * 1000000% (max ));},};
CellCount is the total number of cells, and cellwidth is the width of each grid. because not only does map need this, it is defined here. mode is game mode 5 is simple 7, which is difficult.
Let's look at the map code:
[Javascript]
Game. map = {startX: 40.5, startY: 60.5, width: game. cellCount * game. cellWidth, height: game. cellCount * game. cellWidth, bubbles: [], init: function () {for (var I = 0; I <game. cellCount; I ++) {var row = []; for (var j = 0; j <game. cellCount; j ++) {row. push (new Bubble (I, j, null);} this. bubbles. push (row) ;}, draw: function () {var ctx = game. ctx; ctx. save (); ctx. translate (this. startX, th Is. startY); ctx. beginPath (); for (var I = 0; I <= 9; I ++) {var p1 = I * game. cellWidth; ctx. moveTo (p1, 0); ctx. lineTo (p1, this. height); var p2 = I * game. cellWidth; ctx. moveTo (0, p2); ctx. lineTo (this. width, p2);} ctx. strokeStyle = "#555"; ctx. stroke (); // draw sub-elements (all bubbles on the board) this. bubbles. forEach (function (row) {row. forEach (function (bubble) {bubble. draw () ;}); ctx. restore () ;}, addBubble: func Tion (bubble) {var thisBubble = this. bubbles [bubble. x] [bubble. y]; thisBubble. color = bubble. color;}, getBubble: function (x, y) {var thisBubble = this. bubbles [x] [y]; if (! ThisBubble. color) {return null ;}else {return thisBubble ;}}};
Game. map = {startX: 40.5, startY: 60.5, width: game. cellCount * game. cellWidth, height: game. cellCount * game. cellWidth, bubbles: [], init: function () {for (var I = 0; I <game. cellCount; I ++) {var row = []; for (var j = 0; j <game. cellCount; j ++) {row. push (new Bubble (I, j, null);} this. bubbles. push (row) ;}, draw: function () {var ctx = game. ctx; ctx. save (); ctx. translate (this. startX, th Is. startY); ctx. beginPath (); for (var I = 0; I <= 9; I ++) {var p1 = I * game. cellWidth; ctx. moveTo (p1, 0); ctx. lineTo (p1, this. height); var p2 = I * game. cellWidth; ctx. moveTo (0, p2); ctx. lineTo (this. width, p2);} ctx. strokeStyle = "#555"; ctx. stroke (); // draw sub-elements (all bubbles on the board) this. bubbles. forEach (function (row) {row. forEach (function (bubble) {bubble. draw () ;}); ctx. restore () ;}, addBubble: func Tion (bubble) {var thisBubble = this. bubbles [bubble. x] [bubble. y]; thisBubble. color = bubble. color;}, getBubble: function (x, y) {var thisBubble = this. bubbles [x] [y]; if (! ThisBubble. color) {return null ;}else {return thisBubble ;}}};
In the init Initialization Method of map, I first deployed all the bubbles, but they were not stained. I did not maintain an array behind the ui, because I think the color of the bubble is 0, 1, and so is the same.
Instead of calculating the starting coordinate as before, the draw method uses the translate method, which facilitates code writing.
AddBubble is actually a dye. The receiving parameter is a bubble object, which comes from the bubble in the ready area.
The Ready area is actually like the Russian square. There are three prepared bubbles coming into the map area.
[Javascript]
Game. ready = {startX: 40.5, startY: 20.5, width: game. cellWidth * 3, height: game. cellWidth, bubbles: [], init: function () {this. genrate (); var me = this; me. flyin () ;}, genrate: function () {for (var I = 0; I <3; I ++) {var color = game. colors [game. getRandom (game. mode)]; this. bubbles. push (new Bubble (I, 0, color) ;}, draw: function () {var ctx = game. ctx; ctx. save (); ctx. translate (this. startX, this. startY); ctx. beginPath (); ctx. strokeStyle = "#555"; ctx. strokeRect (0, 0, this. width, this. height); ctx. stroke (); // draw the prepared bubble this. bubbles. forEach (function (bubble) {bubble. draw () ;}); ctx. restore ();},};
Game. ready = {startX: 40.5, startY: 20.5, width: game. cellWidth * 3, height: game. cellWidth, bubbles: [], init: function () {this. genrate (); var me = this; me. flyin () ;}, genrate: function () {for (var I = 0; I <3; I ++) {var color = game. colors [game. getRandom (game. mode)]; this. bubbles. push (new Bubble (I, 0, color) ;}, draw: function () {var ctx = game. ctx; ctx. save (); ctx. translate (this. startX, this. startY); ctx. beginPath (); ctx. strokeStyle = "#555"; ctx. strokeRect (0, 0, this. width, this. height); ctx. stroke (); // draw the prepared bubble this. bubbles. forEach (function (bubble) {bubble. draw () ;}); ctx. restore ();},};
Ready. init initializes three bubbles and "flies" these three bubbles into the map. ready. draw is easy to draw a small rectangle and three bubbles.
Oh, by the way, the drawing code of our bubble has also been slightly modified. It is not like the previous solid color. It has a crystal effect... Take a look:
[Javascript]
Bubble. prototype. draw = function () {if (! This. color) {return;} var ctx = game. ctx; ctx. beginPath (); // console. log ("x:" + px + "y:" + py); var gradient = ctx. createRadialGradient (this. px-5, this. py-5, 0, this. px, this. py, this. light); gradient. addColorStop (0, "white"); gradient. addColorStop (1, this. color); ctx. arc (this. px, this. py, 11, 0, Math. PI * 2); ctx. strokeStyle = this. color; ctx. fillStyle = gradient; ctx. fill (); ctx. stroke ();};
Bubble. prototype. draw = function () {if (! This. color) {return;} var ctx = game. ctx; ctx. beginPath (); // console. log ("x:" + px + "y:" + py); var gradient = ctx. createRadialGradient (this. px-5, this. py-5, 0, this. px, this. py, this. light); gradient. addColorStop (0, "white"); gradient. addColorStop (1, this. color); ctx. arc (this. px, this. py, 11, 0, Math. PI * 2); ctx. strokeStyle = this. color; ctx. fillStyle = gradient; ctx. fill (); ctx. stroke ();};
The createRadialGradient method is to draw a radioactive circle starting from the upper left corner, so there is a light effect, it is good. Let's take a look.
From Jun Zhiqiang