Skip to main content

GameDev Lessons: Endless Runners Part 1

Every Game Developer probably starts with an endless runner and there are many tutorials on the internet to do just that but after building a few myself, I can tell you that most of those tutorials are filled with bad advice which from a learning point of view makes sense to help a beginner get the concepts quickly but in the long run they can turn things into a gruesome mess which becomes a chore to update or improve upon.

It is my opinion that although a tutorial should have instructions that are quick and easy to replicate, it is much more important to organize the code and assets in such a way that they can be easily built upon. Almost every tutorial at the end of the day should be self contained as much as possible so that they can be easily changed by the person following it. This means, instead of simply uploading a zip file containing the whole project, each part of the tutorial should be organized in such a way so they can be easily copied into an existing project.

Now with that done we can begin with Endless Runners...

Basics

So an endless runner is a game which has the objective of getting the protagonist of the game as far as possible in the endless universe that is being generated and with the sole purpose of that universe to stop the protagonist from achieving that objective. Along the way, the player will get bonuses for quick movements, pickups and powerups, score multipliers and many other entities that will help the player. As the runner progresses through the game, obstacles are placed closer and closer, speed of the protagonist gets faster and faster, assistive entities get rarer and rarer eventually reaching the point where the player can no longer continue. There are many games in this genre of games such as the legendary Pepsi man, Subway Surfer, Temple Run etc.

Game Decision Map

With the above description, before we begin making the game we need to make decisions. The chart below will help you with this.

Fig. 1 Endless Runner Decision Map

In the above decision map, I have decided that there will be a single protagonist, a single entity that will help the player, a single entity that will hurt him and world built with multiple segments. At this point in time all of these objects can be simple cubes but each should have its own prefab in its own folder with an accompanying script. 

Getting our hands dirty & Unforeseen Pitfalls

The first step is to build the endless universe in which everything else will be placed and this is where you will face the most common pitfall that a lot of tutorials will ignore. There are two process you need to ensure, grid-snapped world segments and object pooling. The latter will be useful for other entities as well but the former is what we need to focus on.  

Pitfall #1 Invisible walls

Every world segment needs to be built to scale inside a single or multiple grid units which is then placed in your game world at an exact scale and position. This is especially important if your game depends on physics because then a small gap between the two spawned segments will suddenly become an invisible wall which your physics based simulated Rigidbody will bump into and just roll over 👀.

Fig. 2 Invisible wall collision 

To avoid this, you have to ensure, your world segments are built on a grid and at least the floor is at the exact height in your world across all the tiles or simply choose a convex/spherical collider. This is also why character controllers in unity have a capsule collider by default, (The more you know ❤).

Fig. 3 Avoid Invisible Walls

Pitfall #2 Spawning objects at runtime

The common approach now is to use an instantiate function which places a world segment at a certain position. This would however fill up memory unnecessarily after the protagonist passes through them never to be seen again.  Therefore, we need to detect which object has already passed and remove it. This can be done in three ways:

  1. The simplest way is to delete the object after a fixed amount of time after it has been spawned
  2. or place a collider at the end of a segment that can be triggered to delete the segment. 
  3. or if all tiles are of fixed length then just checking the position of the player at multiples of the fixed length, dividing by distance travelled from starting point and marking the specific tile from an array including reference to all spawned tiles.
So why is creating and destroying unique tiles bad?  This is because creating and deleting objects as many tutorials suggest really slows down your game. This is not only for endless runners but in any game, if you have a reusable item it is much better to recycle it. This process of recycling is known as pooling.


So instead of instantiating your entities at runtime from prefabs in your world builder script, you can build a world builder script that instantiate a fixed number of prefabs of each kind (should be the max at any one time for that entity) during game load at an unseen location with a reference for each in an array and then create two functions for spawning and destroying the object.  Call the spawn function from the world builder where you would use the code to instantiate. Call the destroy function from the world builder script where you would destroy the instantiated object in the above three cases.

In the spawn function, simply, shift the transform of an existing spawned object in front of the player or wherever it is required. This can be done by looping through an array of available spawned objects and then pushing the specific instance into another array so it is marked in use.

When it comes to removing the object, you can start a coroutine in the spawn function itself to call the destroy function  after a fixed amount of time. In the destroy function, we pop the reference of an instantiated object from the unavailable array and push it back into an available array. You can also place a collider at the end of a tile which calls the destroy function. Remember, all we are doing in a pooling script is to mark and unmark the objects available for use.

This brings the first part of our series to an end. In the next part, we will actually build a game that follows the above wisdom.


Stay tuned for more, until then, GLHF!

Comments

Popular posts from this blog

Top Android Encryption Apps

After I released my own android encryption app called Dexacrypt , I wanted to see what else was available on the market. Although, I thought my idea was unique there are already a large number of encryption apps on the market. Let's review some of them and rank them.  In this post, we will only look at message encryption apps and not advanced apps such as Surespot or SSE that provide file encryption or messaging. Meet the Contenders: Encrypt Messages And Text This app was last updated in November 2021 and has more than a 100,000 installs. Many reviews praise its simple UI and small size, however one user has specified that the latest version no longer works on Android 12. Secret Message - Encrypt/Decrypt Messages This app has a slightly larger size of 12 MB but only has 5000+ installs. The top review says and I quote, I am sorry but this is not as easy or self explanatory as it should be. You need to grab someone and hand them a phone and watch their expression. Ouch! maybe h...

Beware: Those who use chatGPT for their exams or work!

ChatGPT struggles with prime numbers! While trying to understand how the public private key cryptographic architecture works using chatGPT, I asked what is a coprime number after chatgpt explained its use in the said architecture. Here is the response in all its glory: Two numbers are said to be coprime (or relatively prime) if they have no common prime factors other than 1. In other words, their greatest common divisor (GCD) is 1. For example: 8 and 15 are coprime because their only common factor is 1. 14 and 15 are coprime because they share no common factors other than 1. 10 and 21 are not coprime because they both have 1 as a common factor. Looking at the first and then the last example which is supposed to be a counter-example as to what is not a coprime number, we can clearly see that chatgpt gives the same reason for each case i.e they only have 1 as a common factor. After further investigation, chatgpt replies: Apologies for the confusion. You're correct. 10 and 21 do not h...