Fall Fury: Part 5 - Creating Levels

Sign in to queue


Creating Levels

One of the goals set when developing FallFury was making the game extensible in regards to playable levels. Furthermore, I thought that it would make sense from the development and testing perspective to have levels as a completely separate entity that can be modified as necessary. For example, when a new power-up was introduced, I wanted to add an extra line in a level file and test it out. This was ultimately achieved by creating an XML-based level engine and in this article I will describe the level structure and design process.

Check out the video for this article at https://channel9.msdn.com/Series/FallFury/Part-5-Creating-Levels.  For a complete, offline version of this series, you may download a nicely formatted PDF of all the articles.

The First Steps

When I started working on the level engine concept, I began designing the potential XML file structure for the level and ended up with the following requirements:

  • Level Type Identifier – As different levels have different backgrounds and sound themes, there should be a way to mark a level type. There are currently four level types: dream, nightmare, space, and magic bean.
  • The Starting Character Descriptor – When the game starts, the teddy bear has some initial, basic properties, such as maximum health level, horizontal position, and velocity.
  • A Collection of Obstacles – For each level, obstacles are positioned differently, and it’s important to specify that. For some obstacles it might be desirable to disable the damage infliction component, while for others it might be good to maximize the damage caused by colliding with them. Also, there are multiple textures associated with different obstacle types, so I wanted to specify the obstacles to render regardless of the selected level type.
  • A Collection of Monsters – Obstacles are not the only component that can damage the bear during gameplay. There are also monsters that can pop up and shoot at the main character. Similar to the bear, monsters represent a living entity and have some specific properties, such as the initial health, damage, starting position, velocity, and type.
  • Buttons – These are the bonus point boosters in FallFury. The player collects as many of those as possible, and each of them should be individually positioned to form either a trail or a shape.
  • Power-Ups – With the basic set of abilities, the bear is able to get some bonuses such as a cape that will speed-up his descent or a bubble that will protect him from incoming shells.

The first build of the level engine integrated into FallFuryused percentage-based relative values to position elements on the screen. Although this seemed like a good idea at the time, it became problematic because

  • It required the level to be a fixed size, which restricted element addition and level extension.
  • It caused problems with obstacles that needed to be scaled and therefore had a non-standard size.
  • Small modifications were harder to make because minimal adjustments would throw off the relative position.

So, I switched to a pixel-based conditioning in which each position is relative to zero. With this in place, levels can be infinitely long (within the context of the machine’s rendering and memory capabilities)and extra elements can be more seamlessly added.

Additionally, levels need to be packaged together in individual sets, normally grouped by themes, without restriction. This is achieved with the help of an extra XML file,called core.xml, which keeps track of level tiers, and acts as a container that allows the developer to name and easily enable or disable specific levels .

The structure for the core.xml file looks like this:

  <tier name="GO, GO, TEDDY">
    <level name="mind travels" file="GoGoTeddy\mind.xml"></level>
    <level name="falling in" file="Nightmare\full_pilot.xml"></level>
    <level name="frontlines" file="Nightmare\the_beginning.xml"></level>
    <level name="the chase" file="Nightmare\chasing_monsters.xml"></level>
  <tier name="SECRET GARDEN">
    <level name="bean stalking" file="Garden\bean_stalking.xml"/>
    <level name="thorn apart" file="Garden\thorn_apart.xml"/>
  <!--<tier name="Obstacle ***TEST***">
    <level name="Nightmare 0" file="test\Obstacle\nightmare\0.xml" />
    <level name="Nightmare 1" file="test\Obstacle\nightmare\1.xml" />
    <level name="Bean 0" file="test\Obstacle\bean\0.xml" />
    <level name="Bean 1" file="test\Obstacle\bean\1.xml" />
    <level name="Dream 0" file="test\Obstacle\dream\0.xml" />
    <level name="Dream 1" file="test\Obstacle\dream\1.xml" />
  <!--<tier name="Death ***TEST***">
    <level name="Monster 0" file="test\death\0.xml" />
  <!--<tier name="Monster ***TEST***">
    <level name="0" file="test\Monsters\0.xml" />
    <level name="1" file="test\Monsters\1.xml" />
    <level name="2" file="test\Monsters\2.xml" />
    <level name="3" file="test\Monsters\3.xml" />
    <level name="4" file="test\Monsters\4.xml" />
    <level name="5" file="test\Monsters\5.xml" />
    <level name="6" file="test\Monsters\6.xml" />
    <level name="7" file="test\Monsters\7.xml" />
    <level name="8" file="test\Monsters\8.xml" />
    <level name="9" file="test\Monsters\9.xml" />
    <level name="10" file="test\Monsters\10.xml" />
  <!--<tier name="MEDALS *****TEST******">
    <level name="gold" file="test\Medals\gold.xml"></level>
    <level name="silver" file="test\Medals\silver.xml"></level>
    <level name="bronze" file="test\Medals\bronze.xml"></level>
  <tier name="Buttons ***TEST***">
    <level name="1" file="test\Buttons\single.xml" />
    <level name="Lots" file="test\Buttons\multiple.xml" />
  <tier name="Obstacles ***TEST***">
    <level name="Cape" file="test\PowerUps\0.xml" />

Tiers that are commented out are ignored and the included levels aren’t on the game list. Also, the paths indicated for each file attribute—for each individual tier—are relative to the game folder itself. There is no limit on the number of subfolders that can be included in the path. The above structure will render this level set:


The Level XML

Let’s now take a look at the layout of the level descriptor XML file:

<?xml version="1.0" encoding="utf-8" ?>
<level type="0">
  <meta score="0" buttonPrice="10"></meta>
  <bear maxHealth="100" startPosition="300" velocity="8.0" damage="11" criticalDamage="20" defaultAmmo="100" />
    <obstacle type="1" x="119" y="2300" inflictsDamage="true" healthDamage="5" rotation="3.14" scale="1" />
    <obstacle type="3" x="534.5" y="3000" inflictsDamage="true" healthDamage="5" rotation="0" scale="1" />
    <obstacle type="3" x="534.5" y="3300" inflictsDamage="true" healthDamage="5" rotation="0" scale="1" />
    <obstacle type="1" x="119" y="4200" inflictsDamage="true" healthDamage="5" rotation="3.14" scale="1" />
    <obstacle type="2" x="546" y="5000" inflictsDamage="true" healthDamage="5" rotation="0" scale="1" />
    <obstacle type="1" x="119" y="5800" inflictsDamage="true" healthDamage="5" rotation="3.14" scale="1" />
    <obstacle type="2" x="546" y="6600" inflictsDamage="true" healthDamage="5" rotation="0" scale="1" />
    <monster lifetime="3000" scale=".2" velocityX="2" velocityY="2" type="0" x="460" y="19900" maxHealth="80" bonus="100" lives="0" damage="10" criticalDamage="8" defaultAmmo="50" />
    <monster lifetime="3000" scale=".2" velocityX="2" velocityY="2" type="1" x="460" y="25000" maxHealth="80" bonus="100" lives="0" damage="10" criticalDamage="8" defaultAmmo="50" />
    <monster lifetime="3000" scale=".2" velocityX="2" velocityY="2" type="2" x="460" y="34500" maxHealth="80" bonus="100" lives="0" damage="10" criticalDamage="8" defaultAmmo="50" />
    <monster lifetime="6000" scale=".4" velocityX="2" velocityY="2" type="3" x="460" y="41400" maxHealth="180" bonus="100" lives="0" damage="17" criticalDamage="8" defaultAmmo="50" />
    <button x="300" y="800" />
    <button x="360" y="800" />
    <button x="300" y="860" />
    <button x="360" y="860" />
    <button x="300" y="920" />
    <button x="360" y="920" />
    <button x="300" y="980" />
    <button x="360" y="980" />
    <powerup category="1" type="4" x="140" y="9200" effect="3" lifespan="4"></powerup>
    <powerup category="1" type="3" x="480" y="19800" effect="10" lifespan="6"></powerup>
    <powerup category="1" type="0" x="480" y="27500" effect="10" lifespan="6"></powerup>
    <powerup category="1" type="1" x="100" y="34000" effect="10" lifespan="6"></powerup>
    <powerup category="1" type="0" x="100" y="41200" effect="10" lifespan="6"></powerup>

The opening level tag carries a type attribute. This is level theme flag. It can be set to one of the three four values:

  • 0 – The Nightmare Theme
  • 1 – The Magic Bean Theme
  • 2 – The Dream Theme
  • 3 – The Space Theme

You can see the design differences in the images below:




Magic Bean






Remember, that obstacles and the level theme itself do not influence much other than the background and soundboard.

Once the type is specified, the meta tag brings up the score and buttonPrice attributes. If you for some reason want to create a level including an initial score, you can specify it here. And because buttons are fixed bonus assets that are all created equal, each of them carries a given bonus point weight. The score based on the collected buttons is calculated at the end of the game and relies on the value specified in the meta tag.


Next comes the obstacle collection, which is represented by the obstacles tag. This tag is required even if there are no obstacles on a given level. Simply use <obstacles /> as necessary. Each child node represents an instance of an obstacle that can be choosen from the following enum:

enum class ObstacleType
    OT_CLOUD = 0,
    OT_BEAN_A = 4,
    OT_BEAN_B = 5,
    OT_BEAN_C = 6,
    OT_BEAN_D = 7,
    OT_BEAN_E = 8,
    OT_SPACE_COMET_A = 10,
    OT_SPACE_COMET_B = 11,
    OT_SPACE_UFO = 13,
    OT_SPACE_BALL = 14

Here is the complete table showing the appearance of each of them:













































No matter how the obstacles are positioned, they will either be located in the visible area or displaced outside the viewport and not displayed. The ultimate position is taken from the obstacle size and is relative to the center of the texture. For example, if an obstacle texture is 400- pixels wide, the X-relative position should be set to 200. If the position differs from the starting one, however, the obstacle texture is cut to include the area that fits in the 768 pixel wide playable zone visible. There are no restrictions regarding the Y position.

To help in level creation, some obstacles have pre-defined left and right margins. For example:

  • OT_BEAN_A: 269.5 (Left), 498.5 (right, with 3.14 rotation)
  • OT_BEAN_B: 128.5 (left), 638.5 (right, with 3.14 rotation)
  • OT_BEAN_C: 172 (left), 596 (right, with 3.14 rotation)
  • OT_BEAN_D: 188.5 (left), 579.5 (right, with 3.14 rotation)
  • OT_BEAN_E: 206.5 (left), 561.5 (right, with 3.14 rotation)

The inflictsDamage attribute determines whether the obstacle harms the main character. If it is set to false, the character will still make the sound of colliding with it but will not lose any health points. The primary use for this attribute is level testing.If it is set to true, the character will loose the amount of health points indicated by the healthDamage attribute.

The rotation and scale attributes can be used to flip and resize the texture as needed. Rotation is measured in radians, and the scale is a normalized value in which 1.0 represents 100% of the scale.


As with obstacles, the monsters node should never be omitted from the file and should at least contain a placeholder: <monsters />. Unlike obstacles, however, monsters are dynamic and do not have fixed positions. Moreover, monsters have limited active time during gameplay. The first attribute,lifetime, determines the length of the fall during which the monster will be visible in the viewport. With the y attribute as the Y-based position at which the monster appears, at the y+lifetime position the monster simply flies away if not killed.

The scale attribute carries the same purpose as the one for the obstacle—normalized texture size relative to the size of the original image file. As such, the level designer does not have to worry about linking the width and height of the monster when resizing and can instead use a percentage-like value to scale the monster up or down, simultaneously modifying both the width and the height with zero stretching.

Nextup are velocityX and velocityY. These two attributes are used to set the motion velocity when the monster is already visible. Instead of being a static shooting entity, the enemy moves on a randomized zig-zag path at the bottom of the screen. The horizontal and vertical displacement—in pixels, per update cycle—is individually set through the values carried by the above-mentioned attributes. If necessary, this functionality can be disabled in the code-behind by assigning a fixed value for the vertical and horizontal movement for all monsters that are being loaded on a given level.

The monster type is an integer value that is translated in a value from the following enum (located in MonsterType.h):

enum class MonsterType

Here is a table that shows the texture associated with each identifier:


































Each monster has three separate textures associated with it. The three textures are cycled inside the update loop for each monster entity when the monster becomes visible, creating the movement effect:


Each monster currently shoots only one type of ammo: a red plasma ball. Be aware, however, that there is a preprogrammed condition in which the last monster in the XML file collection is automatically considered the final boss. This means the scale, maxHealth and lifetime properties must be manually adjusted to reflect the effect. Without doing so, the last monster will, regardless of the XML setting, switch in-game to a triple fireball shot that inflicts three times the damage indicated by the damage attribute:


Each monster can have limited ammo as set by the defaultAmmo attribute. In the case that the ammo is exhausted before the monster expires, the monster will continue its motion at the bottom of the screen without inflicting direct damage to the main character.


These are the least complex entities and only carry an X and a Y position. Given those coordinates, relative to the left margin of the visible area, a button texture is rendered:


Once picked-up, the button counter is increased by one and the meta-score incremented by the value set in the meta tag at the beginning of the level XML as long as the feature is activated in the code-behind.


To make the game more fun, there are bonus elements that can be picked up by the bear in order to enhance its performance or protection. These elements are declared in the <powerups/> collection. First and foremost, it is important to declare whether the power-up is positive or negative. In the current version of FallFury, only positive power-ups are included. Nonetheless, the harness for negative ones is already integrated in the parser. Therefore, the category attribute should be set to 1 if the power-up has a positive effect and 0 for a negative effect. This value will only have an effect over the sound played when the bonus is collected.

The power-up type can be one of the following (enum located in PoweupType.h):

enum class PowerupType
    HEALTH = 0,
    HELMET = 1,
    PARACHUTE = 2,
    BUBBLE = 3,
    CAPE = 4,
    AXE = 5,
    BOOMERANG = 6,
    HAMMER = 7,
    KNIFE = 8,
    PLASMA_BALL = 9,
    CIRCLE = 10


The table below shows the power-up texture appearance. Behaviors are already defined in the game and influenced by only the effect and lifespan (seconds) attributes:


Restores the character health, incremented by the value in effect. The lifespan attribute is ignored.



Adds a helmet to the bear, setting the maximum health to the effect value. Active for the duration of lifespan.



Slows down the fall of the bear, setting the descent velocity to the effect value. Active for the duration of lifespan.



Wraps the character in a protective bubble, setting the maximum health to the value of the effect attribute. Active for the duration of lifespan.



Accelerates the descent by multiplying the velocity by the value of effect. Active for the duration of lifespan.



Sets the current character weapon to an axe. The damage is determined by the effect attribute and lifespan is ignored.



Sets the current character weapon to a boomerang. The damage is determined by the effect attribute and lifespan is ignored.



Sets the current character weapon to a hammer. The damage is determined by the effect attribute and lifespan is ignored.



Sets the current character weapon to a knife. The damage is determined by the effect attribute and lifespan is ignored.



Sets the current character weapon to a plasma ball. The damage is determined by the effect attribute and lifespan is ignored.


CIRCLE is a helper power-up that has no effect on the bear and is instead used as an additional texture overlay along with any other power-up in order to create a pulsating circle effect.


FallFury ships with a dozen of sample levels that showcase all of the elements described in the article. At the moment, a level editor is in the works, but it isn’t too complicated to build XML files manually. To do so, you need to consider the pixel-based locations and ensure that they’re all in the visible area—the game engine will automatically handle all other displacements and adjustments.

The Discussion

Add Your 2 Cents