Learn how to make a top-down tile-based game for the Sega Mega Drive using SGDK!

Megatiler 4 - Tile Movement (Part 2)

Posted April 5, 2021

We’ve implemented a lot of movement code already, but so far it’s been not much more than a dry run. Let’s get to actually moving the player around this time!

Moving the Player (For Real This Time)

We can change the internal coordinates of our player entity using the joypad now, but in order to reflect these changes on screen we’ll have to actually move the player sprite. This is going to happen in our main game loop. As we only want to move the player sprite when the player is actually moving, let’s start with another big if-statement:

    if(player.moving == TRUE){


The rest of the code is going in the body of that statement.

Since it was so much fun the last time, let’s add another switch statement that goes through all the potential directions the player could be moving in!

    case up:
        //Move up
    case down:
        //Move down
    case left:
        //Move left
    case right:
        //Move right

Last time we modified the tilePos value of the player entity. However, since this time we want to actually move the sprite, we will modify the pos value, which stores the position of the player entity in pixels. This is what that looks like:

case up:
    player.pos.y -= 1;
case down:
    player.pos.y += 1;
case left:
    player.pos.x -= 1;
case right:
    player.pos.x += 1;

It’s pretty simple. If the player is moving up, its y-position is shifted upwards. If it’s moving right, the x-position is increased, and so on.

But SGDK will have to do the actual sprite moving, so let’s tell it to do so. At the end of the game loop, before SYS_doVBlankProcess(), add:

SPR_setPosition(player.sprite, player.pos.x, player.pos.y);

Now compile the game and try it out! Pressing a direction on the D-Pad should now move the player.


Unfortunately, the player never stops. Whoops.

When we input a direction, movePlayer checks whether the player can move in that direction and sets moving to TRUE if that’s the case. And while moving is set to TRUE, our game loop will move the player sprite in that direction at a rate of 1 pixel per frame…forever. We should probably tell our player to stop once it has reached the next tile!

Stopping the Player

We’ll slip this code between our previous switch-statement and the call to SPR_setPosition. We want to stop the player once it has reached the next tile over, but how do we do that? With math!

if (player.pos.x % TILESIZE == 0 && player.pos.y % TILESIZE == 0){
    //Stop the player

The modulus operator % comes in really handy here. We have specified a fixed TILESIZE for our tilemap, which, in our case, is 8. As we want strictly tile-based movement, this means that we only want to move our player in steps of 8 pixels, because that is always the distance to the next tile over. As our player is currently moving at 1 pixel per frame, we have to stop it once it has moved 8 pixels. We could either simply count the amount of total pixels moved and stop the player then; or we can be fancy and use the modulus operator, which returns the remainder of a division. When this remainder is 0, it means that the current position of the player is a multiple of 8…and therefore the position of a tile, which is exactly where we want the player to be.

Alright, after this chunk of theory, let’s actually stop the player. Luckily, that’s pretty easy:

if (player.pos.x % TILESIZE == 0 && player.pos.y % TILESIZE == 0){
    player.moving = FALSE;

This will break us out of the movement loop and leave the player sprite alone, until we toggle moving back on by pressing a direction on the joypad.

Try the game again and you should see that now the player is only moving one tile every time, and doesn’t move when we hit a wall or the edge of the map!


Now we can move our player around, which is cool! But before we wrap up, let’s add one final layer of polish. You might remember that our player sprite sheet contained sprites for multiple directions, so let’s use them!

First, define the animation frames to make the code easier to read:

#define ANIM_DOWN 0
#define ANIM_UP 1
#define ANIM_SIDE 2

Now we’re gonna set these animations in movePlayer, starting with the up case. After we’ve set player.dir, add this line:

player.dir = Direction;

For the down case, this would be:

SPR_setAnim(player.sprite, ANIM_DOWN);

Which is pretty self-explanatory. However, for the left/right movement we’ll have to add a little bit extra. In the case of left, these two lines will do the trick:

SPR_setAnim(player.sprite, ANIM_SIDE);
SPR_setHFlip(player.sprite, TRUE);

The second line is important here. The sprite in our sprite sheet is looking to the right; so, if we want to have it looking left, we need to flip it horizontally using SPR_setHFlip!

And, conversely, when moving right we would do:

SPR_setAnim(player.sprite, ANIM_SIDE);

It might seem superfluous to call SPR_setHFlip here because the sprite is looking right by default. However, we need to flip the sprite back in case we moved left before!

And that’s pretty much it, really. We could of course have added separate animations for moving left and right, but simply flipping sprites is a quick, easy, and resource-efficient way of dealing with multiple movement directions.



Let’s summarize the logic of our movement code. First, we check if a direction on the D-Pad has been pushed. If so, we pass this direction into the movePlayer function. This function checks whether the player can move in that direction; that is not the case if the player would run off the map or into a wall. But if the coast is clear, the function sets the player’s internal moving flag to TRUE and also updates the animation of the sprite. Once the game loop notices that, it starts to move the player in the specified direction, but stops it at the next tile. The moving flag is then set back to FALSE and will remain so until we press another button.

The whole concept is quite simple once you’ve wrapped your head around it. Of course there are other ways of implementing this type of movement, so don’t be confused if you see similar but different code snippets on the web.

Now we can move our player character around this tiled world. Next time we’ll actually give him something to do!

If you've got problems or questions, join the official SGDK Discord! It's full of people a lot smarter and skilled than me. Of course you're also welcome to just hang out and have fun!

Download the Project Files!

All patrons on Patreon get the complete source code for this tutorial, as well as other perks such as early access! And Patreon support also ensures that I can keep working on tutorials like this one. Become a Patron!
Just Want to Buy Me a Coffee?

Check out the rest of this tutorial series!

  • Megatiler 1 - Tiles
  • Megatiler 2 - Spawning the Player
  • Megatiler 3 - Tile Movement (Part 1)
  • Megatiler 4 - Tile Movement (Part 2)
  • Megatiler 5 - Coins
  • Megatiler 6 - HUD, Sound and Making an Exit
  • Megatiler 7 - Loading Levels
  • Get Words in Your Inbox!

    Be oldschool and sign up for my newsletter to get updates! Just enter your email address, prove you're not part of Skynet and you're good to go!

    Powered by CleverReach. I will not send you spam or sell/give your email address to someone else.  You can of course unsubscribe at any time. By clicking the subscribe button above, you confirm that you have read and agreed to our privacy policy.

    By using the Disqus service you confirm that you have read and agreed to the privacy policy.

    comments powered by Disqus

    Related Posts

    HaxeFlixel Tutorials!

    If you’ve popped over to the tutorial section recently you might have noticed that I’ve added my very first HaxeFlixel tutorial! It shows how to implement a simple, pixel-perfect 2D water shader which I used for Go! Go! PogoGirl. But a few of you might be wondering what a HaxeFlixel is. Well, it’s a 2D game framework that is as powerful as it is underrated! It runs on the (also underrated) Haxe language, is extremely well documented, open source, and has built-in functions for almost anything you’d need.
    Read More

    Streets of Was

    As I’m sure many of you will remember, the original Streets of Rage for the Mega Drive had multiple endings. The real canonical ending has you beat the crap out of Mr. X, thereby ending his reign of terror forever (yeah, right). However, if you confronted Mr. X with a buddy in tow, a new possible path unlocked. A quick refresher is in order. When you confront Mr. X he will ask you to join his organization.
    Read More

    Streets of Rage 2 Design Docs

    A few years ago, Yuzo Koshiro posted a pile of old game design documents for Bare Knuckle 2 aka Streets of Rage 2 on the Ancient blog to commemorate the release of Streets of Rage 2 3D on the Nintendo 3DS. These documents gave a deep insight into the game’s inner workings, technical aspects, designs and even some cut content. They were an awesome resource for one of the most awesome games ever created.

    Read More