Friday, November 29, 2013

How I developed my procedural level generation system for my HTML5 runner game (Construct 2)

Hi everyone, in this article I will explain very quickly the basic idea that I came up with in order to generate whole levels in a controlled and progessive method, for my first html5 mobile game called "Moto Runner," (aimed at Android, iOS, Windows Phone 8, Tizen and as many mobile device platforms as possible.)

UPDATE January 17th 2014: I wrote a simplified tutorial on Scirra.com's tutorials: Procedural Level Generation Using Global Variables and Collisions and included the CAPX file, test it out! : ) 

Below is a screenshot of my opened project in Construct 2: 

Notable elements:
  • PlayerBox: the blue square box near the center left (it has a platformer behaviour)
  • SeqTrigger: the red or orange high rectangle spanning almost the whole game screen height: it has a bullet behaiour, 
  • The three platform frames: frame 2, 0 and 1, which form the solid object on which the platformer character will run and jump.

Tip: Click images to enlarge them.
Image#1: My Construct 2 first html5 video game project opened (*.capx.)


The following are the Global Variables for the game, you'll find descriptions for most of them, I deleted many of the ones I created before, so only a few of these are no longer used, but most still are. 
Image #2 - Global variables event sheet - Construct 2 project



The Opening Bal!
I chose that name because it's really there that everything started!

Basically; here's what happens in the game:
- The platforms scroll as bullets towards the left.
- Playerbox is simulating pressing right, in order to run on the platform solids toward the right.
- SeqTrigger (orange rectangle) which has a bullet behaviour, is set invisible, and runs in opposite direction towards the PlayerBox (-I'm actually using a Spriter animation for the PlayerBox, not displayed yet here-)

When SeqTrigger (intended for Sequence Trigger) collides with PlayerBox: a value of 1 is added to the SequenceOrder Global Variable. This variable will decide which pre-organized spawning sequence will happen. And the actual Spawning Sequence is controlled by another global variable called SpawnSequence.

So: SequenceOrder is like a slot to organise orders (can be considered like just numbers) and SpawnSequence is like the value that calls a spawning of a particular number of objects, in this case the solid object on which playerbox runs, and those objects are created by the System.

I had to add a number of variables to control exactly all the conditions that will let the main global variables change their values, like spawnmax, and spawncount (see descriptions in the Global Variables event sheet, in Image #2.)

All the rest then is controlled by the "Series" Global Variable.

Each series contains as much "SequenceOrder"s as you want.

In my case for this runner game, I am using about a maximum of 22 or 23 sequenceorders per series, and about 3 series per level (layout) for now, just so I keep track of what I'm doing, but otherwise, you could use just one single Series with as many sequenceorders as you want.

Image #3

In the SpawnSequence of "Single Platform": I mean a succession of 3 instances of a solid object, using the three frames 0, 1 and 2 (see Image #1 at the bottom.)
Image #4

A double platform is simply like the single one, except it has two central instances (widest frame) in the middle, and has the two other frames (which I called edges) on the borders.

The following are the SpawnSequence groups I used so far are: single, double, triple, quadruple, quintuple, and decuple (10.) Image #5 shows an example of Double platform solid, involving 4 instances of the same solid object, just 3 frames as follows:
Image #5



An example of series: it actually goes down until SequenceOrder 23 or 24 (see the following and last Image #6 at the bottom.)
I will certainly update this article as this first version is typed in a rush, and I may even make a series to brake down all the steps, so that it can be easier to understand.
If you have any question then please don't hesitate!
Image #6