I have one month to make an MMO: Day 14

Yuan Gao (Meseta)
Meseta’s MMO experiment
5 min readSep 9, 2019

More graphical updates today, but focusing on the code rather than pure content generation

A shorter day for me today. I’m taking it a bit easier, and also trying to fix my sleep cycle, which has since lapsed back into full “nocturnal” mode. Something that I will do by default without a regular 9–6 job keeping me regular.

Tile Animation and tearing

GameMaker has support for animated tiles. It does this by taking an existing tileset, and defining a sequence of tiles that are part of an animation. I noticed this beach tileset has animated water tiles, and it works well with GM’s animated tiles, though requires some tedious clicking to set up the sequences.

The way this works is, GameMaker will see that a tile in the tilemap matches one of the animation sequences defined for the tileset, and will then automatically swap that tile out for the next member of the sequence at the FPS you provide.

It’s a neat and easy way of doing tileset animations, since no information needs to be embedded in the tile data itself, you just tell GM “these tiles are part of an animation sequence”, and it works it out by itself.

However, I found an interesting limitation in these animation tiles in GameMaker: it’s not possible to set the animation frame. As soon as the tilemap is created, it’ll start playing the animations. This is a problem because I’m chunk-loading these tile layers dynamically as the player moves around, so the tilemaps are created at different times from each other, and so will start playing their animations in a staggered way.

The result is some bad tearing along the chunks:

The tearing is most noticeable dirctly to the right of the player, where there appears to be the confluence of four different chunks, three of which have animated water tiles playing at slightly different frames.

GM has a function for fetching the current tile animation position for a given tilemap (tilemap_get_frame()), but it has no corresponding function to set the frame (no tilemap_set_frame())! Some workarounds are possible. For example, instead of loading the chunk right away, I could monitor the animation frame of other chunks until the right frame comes around, before finally loading the chunk fully so that it starts the animation at the correct time.

However, I’m leaving this issue to be solved later, and I’ve submitted a feature request to YYG to see if they’ll add in this missing function.

Sprite drawing

The sprites in the sprite pack (from FinalBossBlues) come in RPG-maker style sprite sheets, that include typically 12 frames of animation for 4-direction movement.

This means there’s 3 sprites per direction, usually:

  • left foot forward for walking animation
  • feet together, used for both intermediate frame for walking, and idle pose
  • right foot forward for walking animation

However, in GameMaker, we don’t have any automatic animation frame handling, so the conceptually easiest, but perhaps most time-consuming method is to create four animated walking sprites, and four idle sprites. The walking sprites would need to have all four frames so that walking is smooth

So we need 4 of these and another 4 static sprites

The result should be 8 separate sprites per character, and the movement code will simply select from which sprite/animation to play depending on what direction the player is facing, and whether they’re stationary.

But of course, this is massively time consuming, and involves manually generating a bunch of sprites for every character. As you can probably see, there are ways to cut down on the number of sprites with code. I decided to just use the 12-sprite sheet directly, and just use code to draw the right part of the sprite at each frame. I won’t go into too much detail, but the code looks something like this:

Ignore my slightly f*’d up binary calculation on line 6

The sum result is we can now use RPGMaker character tile sheets in GameMaker without doing any fancy conversion!

Depth sorting

Since we’re in a sort of 3/4 top down view, the draw order of the sprites need to be correct so that sprites lower down on the screen are drawn above sprites further up. The traditional go-to method of depth = -y is not suitable here because I’m using layers, and layers have depth. If I used depth = -y carelessly, I could end up sending objects behind the terrain layer, causing them to be invisible. In addition to this, since the world is very very large, it is definitely possible for y to exceed 16000, which would put the object outside valid draw depths.

To resolve this, I’m using depth = -y style sorting but doing so relative to the camera position instead, and centring that around the Instances layer. I’ve adjusted the automatic layer separation too to give me a good amount of depth between the layers above and below Instances layer to avoid objects clipping behind or above layers they’re not supposed to

I have to re-fetch the instance layer depth every frame because when chunks load in, it could cause layers to re-order themselves so that a new layer can be inserted in. The above code in the end step event will allow objects to jump themselves to the correct depth even after a layer insertion due to chunk-load.

The final result?

You may notice that I’ve used the little girl sprite as a stand in for chickens. I don’t yet have any chicken sprites, so this’ll do for now.

Day 14 Task summary

I’ve added in new character sprites; and also fixed the depth sorting. I haven’t yet completed the dialog engine, I had realised I needed a character sprite that I could interact with before even triggering the dialogue, so decided to add the characters first.

Now we’re in a good position to finish the dialogue engine, before looking at a few refactoring items relating to warping the user from place to place and anything else I can fit in.

--

--

Yuan Gao (Meseta)
Meseta’s MMO experiment

🤖 Build robots, code in python. Former Electrical Engineer 👨‍💻 Programmer, Chief Technology Officer 🏆 Forbes 30 Under 30 in Enterprise Technology