Adventures in Mega Drive Coding Part 2: Tiles

Posted January 19, 2018

WARNING: These are outdated and obsolete! Instad check out the new >tutorial section<. There you'll learn everything you could here but better!

Note: These are not tutorials, I'm just chronicling my progress as I figure stuff out. Some of the things I do might make an experienced Mega Drive coder cry out in anguish. Feel free to use these posts to guide yourself along, but be aware I might be leading you off a cliff!

Motivated by my first big success (getting Text on the screen) I decided to go all in and actually try to display some graphics this time. But first I set up an IDE to make things easier for myself. I decided to go with Code::Blocks as I had used that waaaay back in the day when I first learned programming. Yes, I started with C. No, I don’t remember much of it. One cool thing is that now the emulator automatically loads up the rom after I compile the project, which saves me some time and hassle.

Anyway, with the IDE and toolchain set up I got to work on getting some graphics on the screen. The Mega Drive uses 3 planes to display stuff: 2 scrolling playfields (called Plane A and B respectively) and 1 sprite plane. Each plane is made up of tiles (also called chars) with a size of 8x8 pixels. These tiles are the basic unit when it comes to loading and displaying graphics on the MD. Thanks to SGDK it’s not hard to get one of those on the screen: You load the data, then place it. Or, translated to code:

VDP_loadTileData( (const u32 *)tile, 1, 1, 0);
VDP_setTileMapXY(PLAN_A, 1, 6, 6);

Now, the first function is still a bit confusing to me, but from what I understand it loads the tile tile into position 1 of the VRAM. I’m not entirely sure what the second 1 is supposed to be; the ´0´ indicates that the DMA should not be used, which is still a bit advanced for me.

The second function is a lot easier: On Plane A it draws the tile stored at position 1 of the VRAM, at position 6,6. The position is given in tiles, not pixels.

And the result looks like this:


Thrilling! The tile I’m using isn’t actually a graphic I loaded by the way, but rather just a C array:

const u32 tile[8]=

Obviously drawing tiles in hex is slightly less convenient than using something like Photoshop, so we’ll take a look at how to load graphics made in a different software soon, but for now we’ll stick to our hex-tile.

As you might expect, drawing multiple tiles on the screen is as simple as just calling VDP_setTileMapXY() multiple times:

VDP_setTileMapXY(PLAN_A, 1, 6, 6);
VDP_setTileMapXY(PLAN_A, 1, 7, 6);
VDP_setTileMapXY(PLAN_A, 1, 9, 6);
VDP_setTileMapXY(PLAN_A, 1, 8, 7);

However! There is still a bit more you can do with a tile. First, you can add color. Each tile on a playfield can have one of 4 different color palettes applied to it. Secondly, you can actually draw tiles flipped (horizontally and/or vertically) without having to use any more memory, which is pretty cool.

So how do we do any of that? By passing these properties into VDP_setTileMapXY():

VDP_setTileMapXY(PLAN_A, TILE_ATTR_FULL(PAL2, 0, 1, 0, 1), 6, 6);

The first and last two arguments are the same as before: We’re drawing a tile on Plane A at position 6,6. However, instead of just specifying the position of the desired tile in VRAM we actually set more properties via TILE_ATTR_FULL(PAL2, 0, 1, 0, 1). These properties are as follows:

  1. Use Palette 2
  2. Draw the tile with low priority
  3. Flip the tile vertically
  4. Don’t flip the tile horizontally
  5. Use the tile at position 1 in VRAM

A little sidenote at this point: C doesn’t actually have boolean values, so instead of trueand false you use 1and 0 respectively. And here is the result of our added properties:


As you can see the first tile is now green and upside-down, a bit like me the morning after a bender. Palette 2 doesn’t have to be green of course, that’s just the way SGDK defines it by default. We’ll get into defining palettes next time.

Another thing we’ll cover next time is the tile priority: Simply put, it allows you to change the draw order of tiles. Usually plane A is drawn above plane B, but if you change the priority of a tile you can override this. This seems like a pretty powerful feature in the hands of someone who knows what they’re doing.

And that’s it for this installment, I hope you enjoyed it. As always, if there are any questions or things you are curious about, don’t hesitate to let me know! Either post in the comments below or hit me up on Twitter @ohsat_games.

See you next time!

Check out the rest of this series!

  • Adventures in Mega Drive Coding Part 1: The Journey Begins
  • Adventures in Mega Drive Coding Part 2: Tiles
  • Adventures in Mega Drive Coding Part 3: Importing Graphics
  • Adventures in Mega Drive Coding Part 4: More Tiles
  • Adventures in Mega Drive Coding Part 5: Palettes and Splitting Tiles
  • Adventures in Mega Drive Coding Part 6: Enter Sprites
  • Adventures in Mega Drive Coding Part 7: Handling Input
  • Join my Discord Server!

    Hang out, get news, be excellent!

    Come hang out!

    Want To Buy Me a Coffee?

    Coffee rules, and it keeps me going! I'll take beer too, though.

    Related Posts

    Triple Update

    POST | | #PogoGirl #Mega Drive #JettyCat #Shino-kun

    A new game, an old game, and a Mega Drive game? Excellent!

    Go! Go! Pogogirl Is Coming to Mega Drive!

    POST | | #PogoGirl #Mega Drive

    It is finally happening: Go! Go! PogoGirl is coming to the Sega Mega Drive!

    HaxeFlixel Tutorials!

    POST | | #Ramblings #Retro #Mega Drive

    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.

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

    comments powered by Disqus