melonJs – Animation Tutorial

melonJs

Following on from our previous tutorial around setting up your melonJs typescript boilerplate environment the next step is to implementation our player animations.

Structure

Well, before we jump in creating let’s talk about what you have setup now. From the folder structure you have a few directories ready to go. Your src folder is where you will carry out most of your work. Inside your scripts folder is where your TypeScript will live inside your data folder is where you pop your assets (e.g., sprites). You can largely ignore the public directory; this is where you generate your production ready code to deploy to your production web server. This is generated by node.js so it is best left alone.

Moving Dude

So, we could end the tutorial here but all we have done it set you up ready to start development so that wouldn’t be very nice. For the rest of the tutorial, we are going to get a dude on the screen (sprite) and make him move around (including basic animation). We will be releasing other tutorials cover other areas (such as loading up maps from tiled). What we will run through might not be the best structure and is aimed at being more functional than code perfect, but it will provide a good starting point.

melonJs Asset Loading

So, before we start coding, we are going to need a sprite asset for our dude. We have a modified sprite sheet originally from itch.io by @lotus_lotus. To download the modified version, you will need for the rest of the tutorial download the zip file here.

Melon.Js helps keeps a nice simple structure for your assets which the pre-loader understands. Once you have your png (make sure you extract it from the zip file) drop it into your src/data/img folder (well it is an image so img makes sense, right?).

Next, we will need to tell melon.js about our new sprite, one of the great features of melon.JS is how the simple process to pre-load assets. Pre-loading assets will make your game much faster and reduce lag compared to loading them on demand.

To pre-load our sprite then head over to the /src/manifest.ts file. You will see that there are a couple of assets already defined (there are the fonts used to display Hello World). We can safely delete these as we won’t need them any longer, it might be easier to edit one though to add our sprite.

Name – This can be any string you like and is what you will use to reference the asset in your game code.

Type – lets melon.js know what type of asset it is preloading (here is the current complete list “audio”, binary”, “image”, “json”, “js”, “tmx”, “tmj”, “tsx”, “tsj”, “fontface”).

Src – This is the relative location of the assets as from the src folder. To load in our dude.png then we will use:

{
      name: "dude",
      type: "image",
      src:  "/data/img/dude.png"
}

Sprite sheets

If you looked at our image you downloaded, you will likely have noticed that there is more than one image of our guy and wondered why this is. If you know why you can skip ahead to the next section. The image we downloaded is called a sprite sheet. A sprite sheet is when you have an image file which contains a collection of other images. In our case we are using it to load all the sprites we will need for our animation. There are other uses of sprite sheets (e.g., tile maps) but we won’t go into that now. The key here is that melon.JS supports sprite sheets, we will just need to add some code to tell it how to handle the asset.

Let’s see the dude!

Before we worry about getting our dude to move around and get animated let’s start by just seeing him on the screen, kind of our own version of hello world.

The boilerplate usefully comes with a PlayerEntity class we can jump straight into. If you want to add more players, collectables etc. you can take a copy of the structure and code away. For now, we are going to use the current template.

Head on over to /src/script/renderables/player.ts and we can have a quick talk about what you can see. As PlayerEntity extends Entity (a melon.js class) then there are several built in functions we can overload to piggyback from.

The constructor is called when we create a new PlayerEntity, this can be used to setup everything we need for our player. The update function is called frequently as part of the game loop, this is used when you need to run some code each frame (for example adding movement to our dude). onCollision allows you to detect when our dude collides with something, for example a wall or another player. We won’t be using onCollision in this tutorial. As we just want to get our dude to appear on the screen, we can setup some basics. Firstly, the base class must be called (the super line). For now, we will hardcode the location and settings, normally you would pass these in. Replace the super call with the below:

super(100, 100 , {
    height: 16,
    width: 16,
    image: "dude"
});

This tells the base class that we want to create our dude at position 100, 100 and he is going to be 16×16 pixels. The image is the name of the asset we preloaded.

Before we will see anything else on the screen, we need to update our play stage. To do this head over to /src/stage/play.ts. This contains the code which is loaded when we switch to the play stage. Currently our game comes with two default stages of titleand play. Firstly, we need to import a few more classes from melonjs, add Renderable, pool, Vector2d to the import list so it looks like the below:

import { Stage, game, ColorLayer, BitmapText, Renderable, pool, Vector2d } from 'melonjs';

As melonJs is modular you only need to import the parts you need.

Next, we need to fix our forces, namely gravity. By default, melonJs applies gravity which will cause our dude to fall to the bottom of the screen. If we imagine we are creating a top-down game then we will want to turn this off. Under the line which is creating a ColorLayer add the following:

game.world.gravity = new Vector2d()

This creates a new empty Vector2 which is what is used to define gravity, by creating a new one it sets it to 0, 0 meaning apply no gravity in either direction.

Next, we can delete the hello world text which came with the template. You can safely delete the code which adds the BitmapText:

// add a font text display object
//@ts-ignore
game.world.addChild(new BitmapText(game.viewport.width / 2, game.viewport.height / 2, {
    font : "PressStart2P",
    size : 4.0,
    textBaseline : "middle",
    textAlign : "center",
    text : "Hello World !"
}));

The final step to getting the dude on the screen is to pull him from the pool and add him to the game world. To make things load faster melonJs allows you to add predefined assets/objects as templates to a pool. The code supplied in the boilerplate automatically adds our player. If you want to see how take a look in the index.ts file.

We can pull our player template from the pool and then add him to the world. Add the following 2 lines in place of the code you just deleted above:

const player = pool.pull("mainPlayer", 0, 0, 0)
game.world.addChild(player as Renderable)

Fire it up

Now we are ready to try running and see if our dude appears on the screen. As we did a while back now just enter npm run dev into the terminal and navigate to http://localhost:5173/. Once our game loads you will see something on the screen but behaving oddly. You should be able to see your dude, but it will be flashing through sprites. To fix this let’s take a look at how we can add animations.

Here’s looking at you, dude

Firstly, lets get our dude standing still, probably a good start. First, we will setup a couple of helper functions to make things easier. Our dude can look in 4 directions (up, down, left, right). When melonJs loads in our sprite sheet it slices it up based on the size we gave it (when creating our player) and uses an index starting top left along the row, then drops to the next one until it reaches the end. As our sprite sheet contains animation images for walking too, we need to make sure we pick the idle animations out. On this occasion we have done this for you:

Left is frame 15, right is frame 10, up is frame 5 and down is frame 0. Now we have this we can create a simple function to register these for us. Add the following function under the onCollision method:

setupAnimations(sprite: Sprite) {
    sprite.addAnimation("idle_left", [15]);
    sprite.addAnimation("idle_right", [10]);
    sprite.addAnimation("idle_up", [5]);
    sprite.addAnimation("idle_down", [0]);
}

You will also need to update the import to add Sprite.

The other useful function we can add is to set the current animation for the sprite based on its name. Under the method we created above add the following new code:

setAnimation(sprite: Sprite, name: string) {
    sprite.setCurrentAnimation(name);
}

Now these are in place we can just hook them up.

Going back up the class under where we call the constructor code then we can call our two new functions. To setup our animations add:

this.setupAnimations((this.renderable as Sprite));

Then add the following line, this will fix our first animation to being idle facing down:

this.setAnimation((this.renderable as Sprite), 'idle_down');

If you left things running, you will find your browser will be refreshing as you go along (this is known as hot reloading). If not, you can simply run npm run dev in the terminal again. You should now find our dude looking at you on the screen.

Now, if you want to see the power of the setAnimation function we created you can update idle_down to idle_up and he will be looking the other way.

Walk this way!

Now we have a static image, but it is a little off a game character. Luckily, we have been laying the foundations as we go so loading in a walking animation is reasonably simple for us. Firstly, we have a little setup around animation speed. In melonJs you need to define the speed you want your animation to run at. At the top, just under where the class is defined add the following line:

ANIMATION_SPEED = 150;

This gives us a value we can use in our function for the animation speed. This means you can easily change it in the future and see the impact.

Now we can add the additional animations for walking. Inside the setupAnimations function we created earlier, under the lines adding our idle animations add the following:

sprite.addAnimation("walk_left", [16,17,18,19], this.ANIMATION_SPEED)
sprite.addAnimation("walk_right", [11,12,13,14], this.ANIMATION_SPEED)
sprite.addAnimation("walk_up", [6,7,8,9], this.ANIMATION_SPEED)
sprite.addAnimation("walk_down", [1,2,3,4], this.ANIMATION_SPEED)

In a similar way that we defined our idle positions we now define walking. You will notice the main differences are we have an array of frames; these are the ids we want the animation to cycle through. We also pass our animation speed we created earlier so the engine knows how quickly to cycle through them.

Before we look at movement controls lets see if we can use one of the new animations. If you update the this.setAnimation call we added to the constructor earlier and change idle_down to walk_down you should see an animation play. Feel free to try out the other positions if you like. When you are down change back to idle_down so we are ready to add controls.

If you are ready and want to add keyboard controls and get our dude walking around then head on over to the next tutorial.

Leave a Reply

Your email address will not be published. Required fields are marked *

WordPress Cookie Plugin by Real Cookie Banner