Lisp Game Jam Log #9

My game jam entry is coming along nicely, and the deadline has been extended by 3 days, so I have some more time to polish it and write about it.

Screenshot of a game with five colored characters and many coins and gems scattered around the level.The "engine" parts of my game are mostly finished now, so I have been working on implementing and polishing the gameplay mechanics. I now have fairly satisfying player movement, random spawning of players (and respawning, if they fall off the screen), and random spawning of treasure. For demonstration purposes, I spawned all 5 players in this screenshot, although there are currently only controls available for two of them.

Player spawning is based on tile labels. Each tile in a level can have a 3-character label which assigns it some special behavior. In the case of player spawning, there are six labels: pl1 through pl5, which are specific to players 1 through 5, plus pl*, which can be used by any player. At the start of the game, the algorithm will try to put a player at a spawn point that is specific to that player, but if it can't find a specific spawn point, it will fall back to selecting one of the general spawn points. (And, in the case that the level has no spawn points at all, the player will spawn in the center of the level.) If a player falls off the screen, they will be moved back to a random spawn point, either specific to that player or a general spawn point.

The treasure spawning system is similar, but more complex. There are five labels, tr1 through tr5, that can be applied to tiles to mark the tiles as treasure spawn points. The number specifies the "grade" of the spawn point, which affects what kinds of treasure appear there, and how often. Lower grade spawn points spawn mostly coins, but very often. Higher grade spawn points spawn mostly gems, but less often. The low-grade spawn points are meant to be scattered around the level in easy-to-reach places, with a few high grade spawn points in hard-to-reach places. You can see this in the screenshot, where the gold coins and green gem are in more difficult and perilous positions than the copper or silver coins. This follows the game design principle of balancing risk and reward — higher risks offer higher rewards.

The algorithm for spawning treasure first finds all the tiles in the level that have a label indicating it is a treasure spawn point. Then it shuffles that list into a random order, and begins iterating through the list, separating it into two piles. If the tile passes a random check (based on the chance specified for its treasure grade), the tile is put into the "chosen" pile. If the tile fails the check, it is put into the "rejected" pile. The algorithm terminates if enough tiles are chosen, but if it gets to the end of the original list and doesn't have enough tiles, it will repeat the process using the "rejected" pile, giving those tiles a second (or third, etc.) chance to spawn treasure.

It is possible that a level might not have any labelled treasure spawn points, so as a fallback the algorithm simply chooses tiles at random, and spawns low-grade treasure there.

It was not strictly necessary to make the algorithm so complex. Most levels should already have relatively few high-grade treasure spawn points, so high-grade treasure would naturally be more rare (fewer tiles = less chance of being selected in the shuffle). But, this algorithm will allow me to tweak the odds for gameplay balance, and it was fun to write the list traversal code.

I have not yet programmed entity/entity collision, so it is not yet possible for players to pick up treasure. That will be my next step. I was previously thinking that treasure would disappear after a few seconds, so that the treasure is constantly circulating, encouraging the players to move around the level. But for simplicity, I will probably make the treasures remain until a player picks them up, then immediately spawn another treasure to replace it.

Another thing I did yesterday was create a highly-commented template level, to help people get started making their own level. It is not yet possible to choose a different level, but I will definitely at least add a command line flag to choose the level. If I have time, I might add a GUI to select the level.

I noticed last night that there is a performance issue with my game. While you play, the game gradually uses more and more CPU, and its framerate gradually gets choppier and choppier. I suspect that this is caused by the app putting pressure on CHICKEN's garbage collector, since many temporary rects are being allocated and thrown away during the collision detection, which occurs hundreds of times per second.

Unfortunately I'm not experienced with profiling CHICKEN code, so I am not completely sure that my intuition is correct. But, I'll try to reduce and reuse the rects during collision detection, and see if that helps. If I can't figure out what the problem is, then I guess I'll make it part of the gameplay: see which player can collect the most treasure before the game's framerate becomes completely unplayable! :P

Previous post: Lisp Game Jam Log #8 Next post: Lisp Game Jam Log #10