Platz Toolset

From Uzebox Wiki
Jump to: navigation, search


Platz is a platformer toolset for video modes 2 and 3. It handles most of the tedious tasks common to side-scrollers and allows you to focus on your game logic. More specifically, Platz will manage:

  • Loading and displaying level data
  • Player/level collision detection
  • Moving platforms
  • Animated backgrounds
  • Patterned backgrounds
  • Event notification

Platz levels are stored as Fill instructions and have on average roughly one tenth of the flash footprint of traditional maps. This affords huge levels with the potential for up to 255 unique screens (world slices in Platz terminology) of level data, any of which may be repeated multiple times for no extra flash outlay.






Level data format

Background directory

The background directory is like a file header for your level data. Each entry summarizes the contents of a world slice and indicates where more specific data can be found. The bgDirectory structure encapsulates this concept and can be referred to for further details regarding specific elements.

Outer backgrounds

Outer BGs can be thought of as containers for Inner BGs. Their purpose is to increase Platz's performance by drastically reducing the cycles required to perform collision detection. Determining where an Outer BG should start and end is usually obvious, but there can be subtleties to the process - these will be explored further in Level creation. Both Outer and Inner BGs must be rectangular.

Inner backgrounds

Inner BGs cannot exist without an Outer BG to exist within. They describe how to display different portions of the Outer BG and are usually much more numerous than their containers. Inner BGs will contribute the most to the flash count of your level. Some Inner BGs are relatively much more expensive than others. The general rule is that edges, ledges and joins can contribute significantly to your Inner BG count. You can usually determine where your Inner BGs start and end by looking for vertically and horizontally adjacent sections of equivalent textures. Don't fret too much about your Inner BG count - the Platz data format is usually very efficient regardless, when it comes to displaying typical platformer aesthetics.


Objects are your typical maps and are used by Platz to display items that do not exhibit particularly regular patterns. These could include things like clouds, trees, plants, enemies etc. Naturally, this qualification will vary based on the make-up of the object. In some cases it may be more efficient to represent an object as a BG.

Maps Table

The maps table contains all the maps that will appear anywhere within your Platz level. Platz will automatically repeat maps to fill their containing Inner BG. Maps displayed as Objects will not repeat. Maps that are not a power of two can be slightly slower to draw and are not supported without defining SLOW_BG_PATTERNS .

Platform directory

The platform directory is a LUT for your platforms. It indexes into your moving platforms table and determines how many entries to retrieve for a particular slice. You can adjust the number of platforms that may appear in each slice by editing the Build option MAX_MOVING_PLATFORMS. However, each extra platform will require 16 bytes of ram and incur a modest cycle cost. This option defaults to zero platforms per world slice in order to save flash.


Platforms are the only other physically mobile element of the Platz framework, alongside the actor. They can move along either axis, but this axis must be set at design time. Individual platforms can move along different axes and have different velocities, however, this velocity must be a factor of 32. Platforms and their movement must be defined within a single world slice.

Platforms must be placed in an initial position that is within their movement bounds or risk being immobile. It should also be noted that Platz does not check platforms for situations where they may "squash" the actor with another platform or an Outer BG. Collisions are also not checked for across slice boundaries, so placing platforms closer than half the width of the actor's sprite to a slice's horizontal boundary could lead to unpredictable movement. Horizontally moving platforms should be tile-aligned along the Y-axis, and vertically moving platforms should be tile-aligned along the X-axis.

The easiest way to create your own platform tiles is to search for "Platforms begin" in the demo data files and modify all tiles from this point on to display as you see fit. If you're creating your tiles from scratch, each axis will need 22 tiles (the square tile common to both axes is not reused by the current build of Platz) drawn similar to the examples below:


  • X-axis left + square
  • X-axis mid
  • X-axis right


  • Y-axis top + square
  • Y-axis mid
  • Y-axis bottom

By using stepped platforms (instead of smooth platforms), each axis only requires a single tile. Stepped platforms move in tile increments. A game may use a mixture of stepped and smooth platforms.

Background animations

BG animations can be thought of as immobile sprites. They will appear to move, but only within their containing Inner BG. Each has an entry in the Animated BG directory. When an Inner BG has a BG animation, its tile entry acts as an index into the animated BG table. As with patterns, BG animations will automatically repeat to fill their containing Inner BG.


Triggers are act exclusively as an event notification system. They can be set to call your special event handling code upon firing. For a trigger to fire, the actor's trigger location must intersect the trigger region. For this reason, a trigger region should be specified to be large enough to capture this event.

Triggers can be specified to be vertical or horizontally aligned and to fire in one of two different orientations:

  • ORI_LRUD (Left/Right/Up/Down)
  • ORI_RLDU (Right/Left/Down/Up)

Platz Trigger Orientations

This ensures that the event will fire in a predictable manner regardless of the direction of approach.

A Trigger is considered an Outer BG, except the count acts as an orientation flag and the Inner BG index acts as a client-defined flag which can be used for responding appropriately to different events.

Mutable Bgs

Mutable BGs are another event notification system within Platz. They're different to triggers in that they are a type of Inner BG, so they can be drawn and animated. Their event is fired upon collision with an actor; prior to being drawn at the edge of the view port; and prior to a new frame being drawn when the BG is animated. These special Inner BGs come in pairs and must be contiguous in memory, with the payload BG following the presentation BG. Both Inner BGs as well as the containing Outer BG are passed to the callback. This allows you to store identification and state information regarding the Mutable BG pair and to do anything from changing its presentation; canceling drawing completely; altering animation speed; ignoring collisions; or reacting to collisions in some special way.

Mutable Classes

Mutable classes are a cheap form of Mutable BG. They cost the same as a regular Inner BG in the amortized sense. Mutable classes are likely to be more commonly used than Mutable Bgs. Situations where the reaction to events generated by the BG, and the presentation of the BG are common, lend themselves to utilizing Mutable classes. An example would be the rings that Sonic collects - they are always the same dimensions; always have the same animation; and always add one to your count.

  • The first tile of your tileset should be your primary background color (what you wish to appear where nothing is specified).
  • Platform paths will only repaint with the single tile (one for smooth platforms; one for stepped) supplied to them at initialization - no objects/BGs should appear on this path.

Level creation

Please see LePlatz for the easy and flexible way to construct your Platz levels.

The best way to describe Platz level creation is through an example. We will convert the following level consisting of three world slices (3x256x224 pixels) into Platz's level data format.

Platz level section (3 slices)

Step 1

We firstly define the patterns that will appear in our slices. In this case, we only have one multi-tile pattern - the light-colored blocks. Each consists of the four tiles below:

  • Top left
  • Top right
  • Bottom left
  • Bottom right

We make entries in our patterns table for them like so:

const char patterns[] PROGMEM = {

We then reference this entry in our pattern directory:

const patternDirectory pgmPatDir[] PROGMEM = {
Step 2

Next we define any platforms that appear in our slices. We have a single, vertical one in the first slice from the left that will take the player up to ground level after avoiding the water. Note that we use pixel-level precision for platforms as they should not appear on the very edge of slices and therefore do not suffer from overflow. We define it like so:

const platform pgmPlatforms[] PROGMEM = {
    {56,104,AXIS_Y,2,{184,224,96,112}}	   // Slice 0

And reference it in our platform directory:

const platformDirectory pgmPlatformDir[] PROGMEM = {
Step 3

Now we define BG animations. Although we appear to have one, we in fact have two animations joined together to appear as a single waterfall. This is required because patterns in Platz should be uniform. For the waterfall to be a single pattern, it would require a huge waste of space. Instead, it is formed from a combination of the following images:

  • Top of Waterfall Animation
  • Bottom of Waterfall Animation

Each of these images' dimensions are a power of two. To examine the performance hit you take by defining SLOW_BG_PATTERNS in the Build options, rebuild the Platz demo and navigate to one of the waterfalls - you'll notice significant slowdown, and this is why it's discouraged. However, in some circumstances, it's nice to have the option. These images are converted to maps via Tile Studio (or your tile editor of choice) and we reference the maps in our animation structure, along with our other waterfall attributes. Each of the waterfall animations has four frames.

const char animWaterfallTop[2 * 4] PROGMEM={
const char animWaterfallBtm[2 * 16] PROGMEM={
     17, 17,
     17, 17,
     17, 17,
     17, 17
const animation bgAnimations[] PROGMEM = {

Now the Inner BG's tile attribute acts as an index into the BG animation structure, as it is free from having to define a tile due to the animation.

Step 4

We'll now define the objects seen in our slices. These are maps created by Tile Studio. They appear as:

  • A plant, a cloud, and a small weed in slice 0 for a count of 3
  • Two palm trees in slice 1 for a count of 2
  • A plant in slice 2 for a count of 1

Coordinates are tile-based as opposed to the pixel-based coordinates we used for platforms, and refer to the top-left corner of the map.

const object pgmObjects[] PROGMEM = {
    {{18,25},mapWeedSml},     // Slice 0 (3,3) (count,total)
    {{28,5},mapPalm},         // Slice 1 (2,5)
    {{29,10},mapPlant}        // Slice 2 (1,6)

I recommend keeping the (count,total) up to date for assisting with background directory entries.

Step 5

It's important to define our Outer backgrounds before the Inner backgrounds; not only because they set hard boundaries on the Inner BGs, but also because it's much easier to fill out the coordinates of the Inner BGs when you just have to reduce the Outer BG coordinates to fit.

One of the main goals with defining Outer BGs is to try to minimize collision checks on slice boundaries. This is a potential bottleneck for Platz, so we attempt to minimize the impact at level design time. Other than that, we try to group as much of the slice into each Outer BG as possible. We should also not group sections that we wish to collide against with sections we wish to pass through, as these will all be treated similarly within the one Outer BG. Given these caveats, let's give it a try. As with Inner BGs, coordinates are tile-based.

Slice 0

Outer BGs for Slice 0

Although the two identified looks complete, there is an invisible BG we need to define for this slice - the water entry/exit trigger. We now only have one BG to be tested for the left boundary collision, and one for the right - a very efficient slice. The trigger does not need to be included in boundary tests as it is not possible to collide with it when crossing a boundary. Typically, as long as an Outer BG does not occupy the first or final column of a slice, it does not need to be tested for boundary collisions. In some cases (such as this one), the combined geometry of neighboring slices can provide exceptions to this rule. There's no major harm done in unnecessarily including an Outer BG in boundary collision tests, but the goal is efficiency. Here's the code:

const bgOuter pgmBgsOuter[] PROGMEM = {
    {BGTH|BGI,ORI_LRUD,TRIG_WATER,0,{12,32,14,17}}  // Slice 0 (3,3)

From this example, it may seem like there's no real point to Inner BGs. However, this slice is a best case kind of scenario. The next two slices are closer to worst case scenarios, and will help to justify the purpose of Outer BGs. Now to further explain the code:

  • BGC: This is a flag that indicates the BG's type. It can be 0|BGC|BGT*|BGI. These are explained in BG flags.
  • 1: Indicates that this Outer BG contains only a single Inner BG.
  • 0: Index into Inner BG table
  • 0: No. of BG animations in this Outer BG.
  • {0,12,14,28}: A rect describing the BG's position within the slice and dimensions.

The second Outer BG contains two other points of interest:

Slice 1

Outer BGs for Slice 1

const bgOuter pgmBgsOuter[] PROGMEM = {
    {BGTH|BGI,ORI_LRUD,TRIG_WATER,0,{12,32,14,17}}  // Slice 0 (3,3)
    {BGC,7,13,0,{20,32,11,28}}                         // Slice 1 (4,7)

Here we have the two main collidable BGs and two more vertical triggers for use with ramping up/down the waterfall sound effect. We ensure the BG that will be tested for boundary collisions on the left side is the first entry. Due to both a begin and count attribute in the BG directory for the right side boundary collision, we can place it anywhere, with the caveat that its elements should be contiguous to avoid unnecessary tests.

Slice 2

Outer BGs for Slice 2

const bgOuter pgmBgsOuter[] PROGMEM = {
    {BGTH|BGI,ORI_LRUD,TRIG_WATER,0,{12,32,14,17}}  // Slice 0 (3,3)
    {BGC,7,13,0,{20,32,11,28}},                         // Slice 1 (4,7)
    {BGTV|BGI,ORI_RLDU,TRIG_WFALL2,0,{19,22,0,11}}      // Slice 2 (3,10)

The one main collidable BG in slice 2 contains two animated BGs, as indicated in its entry. These will be the first two entries in its Inner BGs so that Platz can find them. We reverse the orientation of the trigger on the right side of the waterfall so that it undoes the work of its counterpart on the left-side.

Extra example

Outer BGs for Extra Example

const bgOuter pgmBgsOuter[] PROGMEM = {

The extra example slice ends up with two left and right-side boundary collision checks, which is very economical despite the large number of Outer BGs. The one oddity is the extra BG needed for the wave above the water. This cannot be grouped with the water due to the aforementioned constraint that BGs must be rectangular.

Step 6

Now that we have our Outer BGs defined, we can populate them with their respective Inner BGs. You'll note that we have already filled in the Inner BG count attribute of our Outer BG entries. If this is something you can do on the fly, as I did above, that should save you some time. Otherwise, leave that attribute blank until you complete this step, and then go back and fill them in (including the index).

Inner BGs are subject to the same rectangular constraint as Outer BGs. This sometimes forces you to create very small Inner BGs that may seem wasteful. However, it is necessary, and can be minimized through thoughtful level design. If you have a repeating group of tiles that are taking a lot of room, then consider grouping them into a large Inner BG and creating a pattern. This option is not always appropriate. The basic goal when creating Inner BGs is to group as much of a single tile or pattern together within a rectangle as possible.

Slice 0

Inner BGs for Slice 0

const bgInner pgmBgsInner[] PROGMEM = {
    {BGP,0,{0,12,14,28}},                 // NB: Tile acts as patterns index when type == BGP
    {0,TILE_WATER,{12,32,16,28}}           Slice 0 (3,3)

Slice 1

Inner BGs for Slice 1

const bgInner pgmBgsInner[] PROGMEM = {
    {0,TILE_WATER,{12,32,16,28}},          Slice 0 (3,3)
    {0,TILE_WATER,{25,32,25,28}}           Slice 1 (17,20)

Slice 2

Inner BGs for Slice 2

const bgInner pgmBgsInner[] PROGMEM = {
    {0,TILE_WATER,{12,32,16,28}},          Slice 0 (3,3)
    {0,TILE_WATER,{25,32,25,28}},          Slice 1 (17,20)
    {0,TILE_GND,{31,32,25,28}}             Slice 2 (18,38)

You'll have to trust me that there's 18 Inner BGs in there - two of them being animated BGs. Note how the animated BGs are listed first within their Outer BG's collection.

Step 7

The final step is to summarize all of the previous steps into our BG directory so that Platz can load and display them appropriately. Much of this information can be gleaned from the running tally we kept alongside our Inner and Outer BGs.

const bgDirectory pgmBgDir[] PROGMEM = {
    {0,3,0,3,1,2,1,0,0},		// Slice 0
    {3,2,3,4,1,3,1,0,PF_ZERO},		// Slice 1
    {5,1,7,3,1,0,1,2,PF_ZERO}		// Slice 2

There are a couple of things to note here. Firstly, offsets and indices accumulate from previous elements; PF_ZERO is reserved to indicate the absence of any platforms in a slice; and BG animations count refers to the number of Inner BG animations in the slice. Other attributes are best explained by reviewing the background directory type.

Platz now has all the information it needs to display and interact with our level. If you have further queries about Platz level creation, please submit them to the Platz toolset thread in the Uzebox community forums.

BG flags

  • BGA - Marks the Inner BG as animated.
  • BGC - Marks the Outer BG as collidable.
  • BGI - Marks the Outer BG as invisible. This can assist with efficient rendering. Usually paired with BGT. Can also be used as invisible wall if paired with BGC.
  • BGM - Marks the Outer BG and Inner BG as Mutable bgs. When either an actor collides with the bg, or when the bg must be painted, a user-defined function is called to determine how to proceed and do further processing.
  • BGMC - Marks the Inner BG as a member of a Mutable Class. Mutable classes are cheaper forms of Mutable bgs. The containing Outer BG must be flagged as BGM for this flag to be considered in collisions.
  • BGP - Marks the Inner BG as patterned.
  • BGQ - Marks the Outer BG as queryable. Collision detection will consult a user-defined callback before processing/ignoring a collision.
  • BGT - Marks the Outer BG as a trigger. Width-to-height ratio determines axial alignment of trigger.

While all flags may theoretically be combined, some combinations do not make sense and will be ignored.

Typical usage

Code sample
void ChangePlayerSprite(platzActor *a, u8 widInPixels, u8 hgtInPixels) {
    if (PlatzSetBoundingBoxDimensions(a,newWid,newHgt)) {
         // Go ahead with sprite size change
void ActivateTrigger(u8 tile, u8 type, char trig) {
    switch(tile) {
         // Insert trigger handling code here
int main() {
    char xVel, yVel;
    platzActor a;
    // Init kernel
    // Init platz pointers
    // Init platz scene
    while(1) {
        if (GetVsyncFlag()) {
             *  Your game logic here
            if (xVel != a.vx.vel)
            if (yVel != a.vy.vel)
            collFlag = PlatzMove(&a);
             *  React to collFlag here (maybe animate or end jump sequence etc)

Build options

  • MAX_MOVING_PLATFORMS - The maximum number of moving platforms that Platz will manage per slice. Set to 0 to save flash, ram and cycles.
  • MAX_ANIMATED_BGS - The maximum number of animated BGs that Platz will manage per slice. Set to 0 to save ram and cycles.
  • MUTABLE_BGS - Includes supporting code for Mutable BGs.
  • PLATZ_SLIM - saves roughly 1k of flash at the cost of minor graphical compromises. Set to zero to disable (enabled by default).
  • SLOW_BG_PATTERNS - Platz will manage patterns and animated BGs whose dimensions are not a power of 2. This is a minor performance loss since v1.1.
  • SS_OFFSET_Y - the offset in tiles from the top of the screen that your Platz screenSection begins (for VIDEO_MODE=2). Defaults to 0.
  • VIEWPORT_SLACK - Defines at what distance from the center the camera begins to track the actor. This should be small enough so as to not allow your player to wander offscreen.

Future plans

  • NPC collisions (cycles permitting)
  • Projectile collisions
  • Trigger system expansion


SVN Sources

Hex+Kernel+Source Pkg