This issue, we’re back to working on TIC-80, the fantasy computer for making retro games!
As a refresher, last time we started the basics of a platformer. We talked about how to make a character react to gravity and make the ground solid. We also played with the sound wave generator in order to make custom sound effects. This time we’ll be talking about:
- How to use the full map system in order to have more than one screen for our game
- How to refactor the code we wrote last time so we can more easily add features
- How to use the music tracker to create a little background tune in our game
As a refresher, our code from last time looked like:
t=0 x=96 y=0 vy=0 function TIC() cls(0) map(0,0) if btn(2) then x=x-1 end if btn(3) then x=x+1 end if mget(x//8,(y+6)//8) == 2 or (mget(x//8,(y+6)//8) == 1) then vy = 0 else vy = vy +1 end if btn(0) and mget(x//8,(y+6)//8) == 2 then vy=-8 sfx(0,"C#4",20) end y = y + vy spr(3+t%60//30,x,y,0,1) t=t+1 end
We used a number of global variables – x, y, vy — to represent the state of the player: their x and y coordinates and their velocity in the y direction. We then wrote a main game loop, the TIC function, that handled keyboard inputs for movement. We drew the one screen we painted with a call to map(0,0). Our code used the mget function extensively to ask TIC what kind of tile was in a location: we used this to figure out if we were standing on the ground.
This time around we’ll be moving between screens. As a reminder, in TIC-80 you have a map editor that shows you the full map of the game, split visually into a bunch screen-sized chunks:
What we want is for the player to move across this big map as they move left and right or up and down.
There are multiple ways to do this. I’m showing a way that I personally think is pretty simple, but linked below is another tutorial by Bruno Oliveira that takes a very different approach to handling levels and multiple screens in TIC. Check his platformer out and see which way you like better!
In our version, we’ll be treating the screen-sized segments you can see in the map editor as individual screens in our game and we’ll switch between them as the player moves. If their y-coordinate is less than 0, we’ll move to the screen above. If their y-coordinate is greater than 136, we’ll move to the screen below. Similarly if the x-coordinate is less than 0, we’ll move to the screen to the left and if it’s greater than 240 we’ll move to the screen to the right. In terms of retro games, this means we’re treating screens more like Megaman than Mario!
First, we’ll add two more global variables at the top of our code. This time we’ll call them mapIndexX and mapIndexY. We’ll use them to keep track of which screen we’re on. Initialize them both to 0 like in the following:
mapIndexX = 0 mapIndexY = 0
These variables are like macro x and y coordinates. The mapIndexX and mapIndexY variables are both 0 at the upper-left corner of the map, increasing to 7 and 7 for the bottom-right corner of the map.
Next, we write a helper function to figure out what kind of tile is currently drawn to a part of the screen, calculated from x and y coordinates and the values of the mapIndex variables.
function currTile(x,y) local realX = x + 240*mapIndexX local realY = y + 136*mapIndexY return mget(realX//8,realY//8) end
We can use this currTile function to refactor out our constant tests for whether our player is touching the ground.
function isGround(x,y) local t = currTile(x,y) return t == 1 or t == 2 or t == 11 or t == 12 end
If you’re following along, change the numbers in this function to be the indices of all the ground sprites you’re using in your game!
Now we can finally mess around with the main game loop to finish our refactoring and make the game switch screens as the player moves.
function TIC() cls(0) map(30*mapIndexX,17*mapIndexY) if btn(2) then x=x-1 if isGround(x,y) then x = x + 1 end end if btn(3) then x=x+1 if isGround(x,y) then x = x - 1 end end if isGround(x,y+6) then vy = 0 else vy = vy +1 end if btn(0) and isGround(x,y+6) then vy=-8 sfx(0,"C#4",20) end y = y + vy if x > 240 then mapIndexX = mapIndexX + 1 x = 0 end if x < 0 then mapIndexX = mapIndexX - 1 x=240 end if y < 0 then mapIndexY = mapIndexY - 1 y = 136 end if y > 136 then mapIndexY = mapIndexY + 1 y=0 end spr(3+t%60//30,x,y,0,1) t=t+1 end
Experiment to try: We’ve coded our game so that screens are discrete units—if you leave one screen you are wholly on another. There’s nothing about TIC that requires us to treat screens that way! Instead, try making the screen move incrementally when you cross the edge.
Now let’s add a little background music. Last time we made simple sound waves in the sound editor. What’s new this time is that once you’ve made those custom sounds, you can use them as your instruments in the music editor!
This music editor is an example of a tracker. Trackers are used a lot in making retro chiptune music, particularly the kind where you’re literally reprogramming an old game boy or other hardware to make the song with their built-in soundchips. You can read the tracker from top to bottom: the start of the song is at the top and the end of the song is the bottom. The different columns are all the notes that can play at the same time. So, for example, the middle C major chord of C-4, E-4, G-4 would look like:
Try typing in this little snippet! Can you figure out what it’s the start of? Hint: it’s a song for tiny babies.
Exercise: How close can you come to replicating the sound of those Otamatone meme song covers using custom sound waves and the tracker?
One thing that might not be obvious about a tracker is that the last note played continues until you add a rest or a different note!
To go deeper into making a platformer check out my full game – with comments – here. In this version of the game, we’ll also have code to add in a few enemy types, a big boss fight, and a projectile attack.
Learn More
Bruno’s platformer tutorial
https://medium.com/@btco_code/writing-a-platformer-for-the-tic-80-virtual-console-6fa737abe476
A neat, free, tracker for making chiptunes
Tutorial to make a simple platformer on the TIC-80
https://www.infinitelimit.net/article/simple-platformer-tic-80