

We could also use setInterval, but requestAnimationFrame has some nice optimizations in place already, like running at 60 frames per second (or as close as it can) and stopping the animation loop when the browser/tab loses focus.Įssentially, the requestAnimationFrame is a recursive function - to create our animation loop, we'll call requestAnimationFrame again from the function we're passing as the argument.Are you an artist away from Tibia? Is your real-life job related to art? This is what we'll use to create our loop. Now we're ready to animate our character! Let's take a look at requestAnimationFrame in the MDN docs. Either is fine though - a number of games in the 80s used two step animations. Instead of the animation cycle repeating "left step, right step", it will repeat "stand, left, stand, right" - it's a slightly better animation cycle. This is to show what our animation cycle will look like, rather than just drawing the top three frames of the sprite sheet. There's also an extra line in that list of drawFrame calls. That wouldn't work with a walking animation if, say, the character moves 4 or 5 pixels each frame. scaledWidth * canvasX) would mean everything moves/changes an entire scaled character width at a time. Moving the scaledWidth multiplier inside the function (i.e. The canvas "x" and "y" values still take pixel values so we have better control over positioning the character. Our drawFrame function handles the sprite sheet math, so we only need to pass in frame numbers (starting at 0, like an array, so the "x" frames are 0, 1, and 2). We'll start with drawing this frame starting at (0, 0) on the canvas and keep the proportions. The first frame will start at (0, 0) and end at (16, 18). Our sprite sheet's character frame size is conveniently labeled in the file name ( 16x18), so that gives us our width and height attributes. Now that we've gone over the drawImage method, let's actually see it in action. Then ending coordinates are calculated as ( sx + sWidth, sy + sHeight). If the source parameters ( sx, sy, sWidth, sHeight) are (10, 15, 20, 30), the the starting position (in grid coordinates) would be (10, 15) and stretch to (30, 45). Let's break it down to one section, say the source image. The "Width" and "Height" parameters ( sWidth, sHeight, dWidth, and dHeight) refer to the width and height of the sprite sheet and canvas, starting at their respective "x" and "y" positions. In other words, (50, 30) is 50 pixels to the right and 30 pixels down. It's essentially a grid, where the top left starts at (0, 0) and moves positively to the right and down. The "x" and "y" parameters ( sx, sy, dx, dy) relate to the sprite sheet (source) and canvas (destination) starting positions, respectively. The last four ( dx, dy, dWidth, and dHeight) relate to the destination - the canvas. The next four ( sx, sy, sWidth, and sHeight) relate to the source image - the sprite sheet. Don't worry, it's not as bad as it seems. Whoa, there are a lot of parameters in that method! Especially the third form, which is the one we'll be using. 😊īefore we get to animating our image, let's look at the drawImage context method, as that's what we'll use for automatically slicing up the sprite sheet and applying it to our canvas. I think we can use all three for a smoother walking animation, though. Technically, the left column is a standing (no animation) while the middle and right columns are animation frames. The first (top) row is the character walking in a downward direction, the second row is walking up, the third row is walking left, and the fourth (bottom) row is walking right. Now that we're set up, let's take a look at the image.Įach row represents and animation cycle. If we were dealing with multiple images, we'd probably want to use Promises to wait for all of them to load before doing anything with them. For the sake of this tutorial, this will work.
#TITAN SOULS CHARACTER SPRITE SHEET CODE#
All of animation code will go in the init function. This is to ensure the image is loaded before we try working with it. The init function is called after the image is loaded, via img.onload. Enter fullscreen mode Exit fullscreen mode
