Introduction: Platformer With Infinite Levels on GameGo With Makecode Arcade
GameGo is a Microsoft Makecode compatible retro gaming portable console developed by TinkerGen STEM education. It is based on STM32F401RET6 ARM Cortex M4 chip and made for STEM educators or just people who like having fun creating retro video games.You can follow this tutorial and try the game in Makecode Arcade simulator and then run it on GameGo.
In this article we're going to make a platformer game with infinite randomly generated levels. In a platformer, the player controlled character must jump and climb between suspended platforms while avoiding obstacles. Environments often feature uneven terrain of varying height that must be traversed. The player often has some control over the height and distance of jumps to avoid letting their character fall to their death or miss necessary jumps. We'll implement all these basic elements and also add a custom function that will generate new levels as we reach the end of the last one. Let's begin!
Step 1: The Hero
As a first step we will create our alter-ego. My drawing skills are pretty bad, so I just decided to use one from the Gallery ;) Unlike the previous game we made, in this platformer our playable character can only move left and right and also it can jump. So instead of having two different sprites for the main character, one is enough this time - we can just flip sprite's image when we change direction.
First thing to do is to add background and tile map. I have chosen 32x8 long tile map - for the first level we'll draw it manually, as in screenshot 2. Then we add our playable character with set mySprite to sprite of kind Player block and place it on the top of tile 0-5. We also set the camera to move with playable character and control its left and right movement - we'll set velocity vy of movement to 0, since our character shouldn't be able to float freely on the map along y-direction. Add two on ... button pressed blocks, one for left button, one for right. When left button is pressed, we check if our direction was "left" before pressing the button. If it was, we just continue going left. If it wasn't we need to flip our character's sprite image. Similar logic for right movement.
All good for now, the only problem seems that our hero cannot seem to overcome any obstacle. So we need to add jumping. We'll monitor the controls for up button press and when it is detected, we'll set variable jumping to 1, make note of the time jumping movements started and set character's sprite velocity vy to -200(going up). Then after specified period of time, we'll set the velocity to 200(going down), so our hero wouldn't shoot up to the sky as a rocket.
I think we created a hero worthy of the challenge now! Well, where is the challenge?
Step 2: The Enemies
We will use an array structure to store the sprites of the enemies. For type of enemies we'll take a little shortcut and use bats :) not a coronavirus reference, it's just bats can fly, that's why we won't need to "simulate" gravity for them, as we do with our playable character. Use on created sprite of kind Enemy block to place newly created bats on random spawn tile (marked with a little white mark) and set their vx velocity to -10(slowly drifting right). Then within on game update every 2000 ms block we iterate through each item of enemy_list and randomly change their direction, while also flipping the bats' sprites if necessary (to reflect the change in movement direction). Finally, we add on sprite of kind Player overlaps with otherSprite of kind Enemy block, where we do a simple check if player has been hit already. If it wasn't we deduct one life, set hit flag to 1(has been hit) and start the timer. Once 500 ms since last hit time passed we change flag hit back to 0. We do that in order for player to avoid loosing too many of it's precious lives after colliding with an enemy.
Let's check how are we doing. Well, the scene certainly seems livelier with all the bats flying around and biting our player. Now we need a weapon to do our heroic deeds!
Step 3: The Weapon
For the weapon, I was drawing the inspiration from an old Nintendo game about two chipmunk brothers :) Let's add the crate sprites to the level, the similar way we do with adding the enemies. We also initialize has_crate variable to -1, which indicates our character doesn't carry a crate. In on sprite of kind Player overlaps with otherSprite of kind Food block, we check if we already holding a crate and if we don't, we set the has_crate variable to the index of the crate sprite in the list. Then in on game update block we move that sprite together with player's sprite and if button A is pressed, we change crate's vx velocity to 1200 or -1200(depending on the direction of movement of the character). We also set has_crate variable back to -1 again and change the type of sprite of the crate that was launched into the air just now to Projectile.
Lastly, we need for the crates to actually destroy the enemies when launched (but not when the enemies just randomly stumble across a crate! that's why we assigned crates to type Food and change it to Projectile only when launched) and self-destroy when hitting the wall. We use another on sprite of kind Projectile overlaps with otherSprite of kind Enemy block for that - in that case we destroy both sprites and raise score by one. If Projectile hits the wall, we destroy its sprite.
Almost done now! The game is playable now, but hardly any challenge still - only one level and fairly simple at that. We could make more levels by hand or write an algorithm that would generate these levels automatically for us - although they won't be as pretty as human-made levels of course.
Step 4: Infinite Adventures
The function for random level generation looks a bit scary at first, but it is really a simple series of steps to algorithmically generate a new level, in the way that a new level is passable for playable character. First, we take care of getting our character to that new level - by using on sprite of kind Player overlaps ... at location - we use portal door tile as the trigger to a new level. In generate_level function we initialize variables row, col and chance. Also we create a new tile map, same size as before, but empty. Here's a little caveat though - in order to use set ... at tilemap row ... col ... block, the tilemap needs to have these particular tiles --- that is a bit counter intuitive and maybe a bug in Makecode. So, what you'll need to do is to create a tilemap, put all the tile types you want to use in random generation AND then erase them.
We manually put the first tile (0x6) and player on top of it. Then we repeat next step 30 times - next step is simple series of True-False checks, which decide on whether next column tile us going to be 1)same level as previous 2)one up or 3)one down. There is also very small chance that next tile is going to be a lava tile - we don't want too many of these! After every tile generated we fill the space below it with lava - just for sake of prettiness. As a final step we add the enemies and the crates and place them on top of random spawn tiles.
Step 5: Adventure Begins
Voila! We finished our platformer and our hero can go on an infinite adventure, defeating bats and destroying crates. if you are encountering problems, you can download the code from our GitHub repository.
It is just a blueprint and there are definitely some improvements that can be made, for example different kinds of enemies, bonuses, better level generation and so on. If you do make an improved version of the game, share it in the comments below! For more information on GameGo and other hardware for makers and STEM educators, visit our website, https://tinkergen.com/ and subscribe to our newsletter.
TinkerGen has created a Kickstarter campaign for MARK(Make A Robot Kit), a robot kit for teaching coding, robotics, AI!