Making a game in PICO-8: Bashing against collision

This is the third part of my diary about making my first-ever game, using PICO-8 [official site]. So No Frog Left Behind now has a map and you can move the player around. But I’m now on my third big session on it and I’ve got a long way to go before there’s any kind of game there.

Key to getting an actual game running is working out when things collide, like players with impassable water and frogs with bullets, and frogs with boxes. For this is a game about pushing frogs into boxes with bullets. And collision is my Agincourt.

Having looked at proper games’ code and not really understood it, I know I’m going to have to solve this my own terrible way, but I can see that they often use ‘flags’ on sprites so the game knows which are solid objects. With a little more investigation, I find that you can get the game to consult the flag on a given sprite with something called fget(). And there’s another command called mget(). This looks at a location in the map sheet you’ve drawn for the game in the editor.

I’ve got a plan. We mark water with a flag to say you can’t move there. We get the game to continually look up on the map what tiles are to the sides, above and below the player’s position, and if they’re flagged as impassable, it doesn’t let the player move.

What follows is a great deal of mistake-making. First I fail to put the right number of brackets into my nested horror equation and end my statements properly. Then I fail to marry the map’s small 16×16 scale to the screen’s 128×128 scale properly so it’s looking up the wrong place on the map. As I spend hours muddling through it all, I get the game to write out on the screen what it thinks is passable around the player (FALSE) and impassible (TRUE), along with the player’s coordinates.

Here is the rats nest of a solution I came to for checking to the left:

if btnp(0) and (fget((mget((((player.x-32)/8)-1), ((player.y-32)/8))),0)) == false then
    player.x -= 8
end

Bear in mind it also needs to check in each other direction, too. I know this is a complete horrorshow and I apologise profusely. But it works! My character now walks on the lily pads! (Though the frog here moves about completely randomly and freely because I haven’t done that bit yet.)

My little internal system is functioning. I feel great. It’s at this point that I decide, flushed with success and on a total whim, that I’ll make the game turn-based, so things will happen only after you move. Something like this transforms a game utterly from action to strategy. And it takes about 15 seconds to implement, using a little counter that resets every time you press a button. I’m realising that game development is easy!

And thus I go to work on the frog and so begins my great chastening.

I try to apply the same principles to the frog so, realism be damned, it also can’t go in the water, but instead of taking player input it’s going to move randomly, because, believe it or not, I probably can’t program an AI system. I have it pick a random direction, then check whether it can move there. If it can’t it’ll stay where it is for some froggy-style unpredictability.

It doesn’t really behave itself from the start. It sometimes moves diagonally (because I used the variable for going down twice). It goes in the water for no apparent reason (I was checking for the wrong flag). Even when I finally see it behaving correctly, I still don’t trust it, so I also put up debug text about what it thinks is around it.

But it totally doesn’t make any sense, contradicting the frog’s own movements entirely. I can’t see any pattern to the madness and pore over my spaghetti code. After about 45 minutes of my head in my hands I realise the text is reporting the frog’s last move because I was capturing the information about its location before the move that you see.

Game development is hard and it is always my fault. And next I have to make bullets to fire at the frog. It feels like the cliff face just keeps getting sheerer.

Here’s the full series, which we’ll be publishing daily over the week of Christmas. Also, just to note that PICO-8 is available right now in a Humble GameDev Software Bundle, in case you’re interested in trying it out.

From this site

14 Comments

  1. Stopsignal says:

    As someone who already passed through all of this in GameMaker, this is both relatable and funny, and I love it. Keep it going.

  2. Tacroy says:

    Pro tip: nested for loops allow you to iterate over all eight (or four, depending) adjacent cells without typing in all out.

    For instance:

    for(i = -1; i <= 1; i += 2)
    for(j = -1; j <= 1; j += 2)
    check(x + i, y + j)

    Will check all adjacent but not diagonal squares.

    Note that if you want to check all eight, a naive version will check x, y as well… Just keep that in mind.

    And if you’re using Python or some other, nicer language, consider doing everything with iterators. Why worry about x, y coordinates when really what you want to look at is a list of adjacent squares, regardless of the definition of “adjacent”.

    • Isair says:

      If you’re feeling fancy it can be done in one loop

      for(i = 0; i < 4; i += 1)
      check(x + (i + 1)/2 – 1, y + i – i/2 * 3);

      Though this only works with integers.

    • fredcadete says:

      Eerrm, I think what you wrote would actually check the diagonals and not the adjacents. Unrolling the loop:

      check(x-1,y-1)
      check(x-1,y+1)

      And those are usually diagonals.

      There’s really not a very readable solution without resorting to compound types (like a table of the four possible movement vectors) and maybe at this point Alex was sticking to simple integers?

    • Scandalon says:

      Is there a particular reason to be checking every adjacent tile? Why not only test the single target tile once a move is attempted? This would work for both player and “AI”.

  3. MrBehemoth says:

    Game development is hard and it is always my fault.

    As MrsBehemoth often reminds me as I pull out my hair, this is in fact the beauty of it. Whatever chaos unfolds on the screen, you can always be sure that the computer is doing exactly what you told it to do.

    • Premium User Badge

      MajorLag says:

      That’s only true until the first time you run into an undocumented bug in an underlying API. Then it’s doing exactly what some other idiot told it to do.

  4. Michael Fogg says:

    Hate to be the guy, but identical header pics on Xmas styled posts are really negatively affecting the RPS expierience. I wish for a return to scheduled programming.

  5. Mi-24 says:

    That code editor looks quite hard to read.

    Also the AI might be easier to program than you think.
    If you know the coordinates that you want the frog to travel to you can use the A* (A star) Path finding algorithm.

    It works really well with a grid based movement system and also happens to have the nice property of being very efficient and always finding the shortest path if one exists.

    maybe you don’t need to use it now but if you ever do want to do any pathfinding in the future I’d recommend looking into it.

  6. April March says:

    Prediction: when the game is done, Alex will realize it could have been made, much more easily, on Puzzlescript.

  7. ThePuzzler says:

    Since I don’t think this story is up yet and this is the nearest thing to a relevant article: Did you guys know that Frog Fractions 2 has now been discovered hidden in another game?

  8. Bartack says:

    I purchased this: link to humblebundle.com

  9. vanessallawton says:

    I leave my 9 to 5 job and now I aam getting paid 98usd hourly. How? I work-over internet! My old work was making me miserable, so I was forced to try-something NEW. One year after…I can say my life is changed-completely for the better! Check it out what i do——KLa

    ————->>>> link to ow.ly