In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-05 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
Editor to share with you how to use Canvas in html5 to achieve Super Mary games, I believe most people do not know much about it, so share this article for your reference, I hope you can learn a lot after reading this article, let's go to know it!
Canvas fundamentals canvas elements
The canvas tag allows us to use JavaScript to draw various styles of graphics on a web page. To access the actual drawing interface, we first need to create a context, which is an object that provides the drawing interface. At present, there are two popular drawing styles: "2d" for 2D graphics and webgl for 3D graphics through the OpenGL interface.
For example, we can use the getContext method on the DOM element to create the context.
Let canvas = document.querySelector ('canvas'); let context = canvas.getContext (' 2d'); context.fillStyle = "yellow"; context.fillRect (10,10,400,400)
We draw a yellow square with a width and height of 400 pixels, and the coordinates at the vertex of the upper-left corner are (10,10). The coordinate system (0,0) of canvas is in its upper left corner.
Drawing of the border
In the interface of the canvas, the fillRect method is used to fill the rectangle. The method used by fillStyle to control the shape of the fill. such as
Monochrome:
Context.fillStyle = "yellow"
Gradual discoloration:
Let canvas = document.querySelector ('canvas'); let context = canvas.getContext (' 2d'); let grd = context.createLinearGradient; grd.addColorStop (0, "black"); grd.addColorStop (1, "red"); context.fillStyle = grd;context.fillRect (10,10,400,400)
Pattern pattern objects:
Let canvas = document.querySelector ('canvas'); let context = canvas.getContext (' 2d'); let img = document.createElement ('img'); img.src = "https://dss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3112798566,2640650199&fm=26&gp=0.jpg";img.onload = () = > {let pattern = context.createPattern (img,' no-repeat'); context.fillStyle = pattern; context.fillRect (10Met 10400400)}
The strokeStyle property is similar to the fillStyle property, but strokeStyle acts like the color of the stroke line. The width of the line is determined by the lineWidth property.
For example, I want to draw a yellow square with a border width of 6.
Let canvas = document.querySelector ('canvas'); let context = canvas.getContext (' 2d'); context.strokeStyle = "yellow"; context.lineWidth = 6 ten context.strokeRect (10Ling 10,400,400); path
A path is a combination of many lines. If we want to draw a variety of shapes, we will frequently use the moveTo and lineTo functions.
Let canvas = document.querySelector ('canvas'); let context = canvas.getContext (' 2d'); context.beginPath (); for (let index = 0; index)
< 400; index+=10) { context.moveTo(10, index); context.moveTo(index, 0); context.lineTo(390, index); } context.stroke(); moveTo 表示我们当前画笔起点的位置, lineTo 表示我们画笔从起点到终点的连线。以上代码执行后就是如下所示: 当然我们可以为线条绘制的图形进行填充。 let canvas = document.querySelector('canvas'); let context = canvas.getContext('2d'); context.beginPath(); context.moveTo(50, 10); context.lineTo(10, 70); context.lineTo(90, 70); context.fill(); context.closePath();绘制图片 在计算机图形学中, 通常需要对矢量图形和位图图形进行区分。 矢量图形是指: 通过给出形状的逻辑来描述指定的图片。而位图图形是指使用像素数据, 而不指定实际形状。 canvas中的 drawImage 方法允许我们将像素数据绘制到画布上。像素的数据可以来自于元素或者另外一个画布。 drawImage支持传递9个参数, 第2到5个参数表明源图像中被复制的(x, y, 高度, 宽度), 第6到9个参数给出被复制的图像在canvas画布上的位置以及宽高。 下图是玛丽多个姿势的汇总图, 我们使用 drawImage 先让他能够正常跑起来。 let canvas = document.querySelector('canvas');let ctx = canvas.getContext('2d');let img = document.createElement('img');img.src = './player_big.png'let spriteW = 47, spriteH = 58;img.onload = () =>{let cycle = 0; setInterval () = > {ctx.clearRect (0,0, spriteW, spriteH); ctx.drawImage (img, cycle*spriteW, 0, spriteW, spriteH, 0,0, spriteW, spriteH,); cycle = (cycle + 1)% 10;}}
We need to roughly intercept the size of Mary and lock Mary's position in the animation through cycle. In the synthesis, we only need to loop the first eight actions to achieve one of Mary's running movements.
Control conversion
Now we can get Mary to run to the right, but in the actual game Mary can run left and right. There are two plans here: 1. Let's draw a combination of running to the left. 2. Controls the canvas to draw the picture in turn. The first scheme is relatively simple, so we choose the second one which is more complex.
In canvas, you can call the scale method to adjust according to the scale and then draw. This method has two parameters, the first to set the horizontal scale and the other to set the vertical scale.
Let canvas = document.querySelector ('canvas'); let ctx = canvas.getContext (' 2d'); ctx.scale (3, .5); ctx.beginPath (); ctx.arc (50,50,40,0,7); ctx.lineWidth = 3bot ctx.stroke ()
The above is a simple application of scale. We called scale to stretch the circle 3 times horizontally and 0.5 times vertically.
If the parameter in scale is negative-1, the shape drawn at position x 100 will eventually be drawn to position-100. So in order to convert the image, we can't just call ctx.scale (- 1,1) before drawImage, because the converted image is not visible in the current canvas. There are two options: 1. When calling drawImage, set x to-50 to draw figure 2. By adjusting the axes, the advantage of this approach is that the drawings we write do not need to care about the change of the scale.
We use rotate to render the drawn graphics and move them through the translate method.
Function flip (context, around) {context.translate (around, 0); context.scale (- 1,1); context.translate (- around, 0);}
Our thinking goes something like this:
If we draw a triangle at positive x, it will be in position 1 by default. After calling the flip function, we first translate to the right to get triangle 2. Then get triangle 3 by calling scale to flip it. Finally, by calling the translate method again, we translate triangle 3 to get triangle 4, which is the final pattern we want.
Let canvas = document.querySelector ('canvas'); let ctx = canvas.getContext (' 2d'); let img = document.createElement ('img'); img.src ='. / player_big.png' let spriteW = 47, spriteH = 58; img.onload = () = > {ctx.clearRect (100,0, spriteW, spriteH); flip (ctx, 100 + spriteW / 2) Ctx.drawImage (img, 0,0, spriteW, spriteH, 100,0, spriteW, spriteH,);}
Look, he's been transferred by us!
Upgrade the Super Mary game
In the previous article, all of our elements were displayed directly through DOM, so after we have finished learning canvas, we can use drawImage to draw elements.
We define CanvasDisplay to replace the previous DOMDisplay, and in addition, we add a tracking view window, which can tell us which part of the level we are currently at, and I have also added the flipPlayer property so that even if Mary does not move, it still faces the direction in which it finally moved.
Var CanvasDisplay = class CanvasDisplay {constructor (parent, level) {this.canvas = document.createElement ("canvas"); this.canvas.width = Math.min (600, level.width * scale); this.canvas.height = Math.min (450,450, level.height * scale); parent.appendChild (this.canvas); this.cx = this.canvas.getContext ("2d"); this.flipPlayer = false This.viewport = {left: 0, top: 0, width: this.canvas.width / scale, height: this.canvas.height / scale};} clear () {this.canvas.remove ();}
The syncState method first calculates the new view window and then draws it in place.
CanvasDisplay.prototype.syncState = function (state) {this.updateViewport (state); this.clearDisplay (state.status); this.drawBackground (state.level); this.drawActors (state.actors);}; DOMDisplay.prototype.syncState = function (state) {if (this.actorLayer) this.actorLayer.remove (); this.actorLayer = drawActors (state.actors); this.dom.appendChild (this.actorLayer); this.dom.className = `game ${state.status} `; this.scrollPlayerIntoView (state);}
Instead of the previous update, we now have to redraw the background with each update. Because the shapes on the canvas are only pixels, there is no good way to move or delete them after painting. So the only way to update the canvas is to clear and redraw.
The updateViewport method is the same as scrollPlayerIntoView method. It checks whether the player is too close to the edge of the view.
CanvasDisplay.prototype.updateViewport = function (state) {let view = this.viewport, margin = view.width / 3; let player = state.player; let center = player.pos.plus (player.size.times (0.5)); if (center.x
< view.left + margin) { view.left = Math.max(center.x - margin, 0); } else if (center.x >View.left + view.width-margin) {view.left = Math.min (center.x + margin-view.width, state.level.width-view.width);} if (center.y
< view.top + margin) { view.top = Math.max(center.y - margin, 0); } else if (center.y >View.top + view.height-margin) {view.top = Math.min (center.y + margin-view.height, state.level.height-view.height);}}
When we succeed or fail, we need to clear the current scene, because if we fail, we need to start over, and if we succeed, we need to delete the current scene and redraw a new scene.
CanvasDisplay.prototype.clearDisplay = function (status) {if (status = = "won") {this.cx.fillStyle = "rgb (68,191,255)";} else if (status = = "lost") {this.cx.fillStyle = "rgb (44,136,214)";} else {this.cx.fillStyle = "rgb (52,166,251)";} this.cx.fillRect (0,0, this.canvas.width, this.canvas.height) }
Next, we need to draw walls and lava. First, we walk through all the walls and bricks in the current view. We use sprites.png to draw all the non-empty wall tiles (walls, lava, gold coins). In the material provided, our wall is 20px * 20px, the offset is 0, and the lava is also 20px * 20px, but the offset is 20px.
Let otherSprites = document.createElement ("img"); otherSprites.src = "img/sprites.png"; CanvasDisplay.prototype.drawBackground = function (level) {let {left, top, width, height} = this.viewport; let xStart = Math.floor (left); let xEnd = Math.ceil (left + width); let yStart = Math.floor (top); let yEnd = Math.ceil (top + height); for (let y = yStart; y < yEnd; y +) {for (let x = xStart; x < xEnd) ) let tile = level.rows [y] [x]; if (tile = = "empty") continue; let screenX = (x-left) * scale; let screenY = (y-top) * scale; let tileX = tile = = "lava"? Scale: 0; this.cx.drawImage (otherSprites, tileX, 0, scale, scale, screenX, screenY, scale, scale);}
Finally, we need to draw a model of the player.
In the previous 8 images, it is a complete motion process. The ninth portrait is the player's motionless state, and the 10th portrait is the player's state when off the ground. So when the player moves, we need to switch one frame per 60ms. Draw the ninth picture when the player is motionless and the tenth screen when the player jumps.
CanvasDisplay.prototype.drawPlayer = function (player, x, y, width, height) {width + = playerXOverlap * 2; x-= playerXOverlap; if (player.speed.x! = 0) {this.flipPlayer = player.speed.x < 0;} let tile = 8; if (player.speed.y! = 0) {tile = 9 } else if (player.speed.x! = 0) {tile = Math.floor (Date.now () / 60)% 8;} this.cx.save (); if (this.flipPlayer) {flipHorizontally (this.cx, x + width / 2);} let tileX = tile * width; this.cx.drawImage (playerSprites, tileX, 0, width, height, x, y, width, height) This.cx.restore ();}
For models that are not players, we find the corresponding image according to the offset of the corresponding model.
CanvasDisplay.prototype.drawActors = function (actors) {for (let actor of actors) {let width = actor.size.x * scale; let height = actor.size.y * scale; let x = (actor.pos.x-this.viewport.left) * scale; let y = (actor.pos.y-this.viewport.top) * scale; if (actor.type = "player") {this.drawPlayer (actor, x, y, width, height) } else {let tileX = (actor.type = = "coin"? 2: 1) * scale; this.cx.drawImage (otherSprites, tileX, 0, width, height, x, y, width, height);}}; these are all the contents of the article "how to use Canvas to implement Super Mary Games in html5". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.