Platz Toolset: Difference between revisions

From Uzebox Wiki
Jump to navigation Jump to search
 
(18 intermediate revisions by the same user not shown)
Line 1: Line 1:
== About ==
== About ==


'''Platz''' is a platformer toolset for video mode 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:
'''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
* Loading and displaying level data
Line 12: Line 12:


Platz levels are stored as [[Function_Fill|Fill]] instructions and have on average roughly one tenth of the flash footprint of traditional [[Function_DrawMap|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.
Platz levels are stored as [[Function_Fill|Fill]] instructions and have on average roughly one tenth of the flash footprint of traditional [[Function_DrawMap|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.


== API ==
== API ==
Line 31: Line 30:
===== Mutators =====
===== Mutators =====


* [[Platz_Function_PlatzSetAnimatedBgDirectory|void PlatzSetAnimatedBgDirectory(const bgAnimIndex *bgad)]]
* [[Platz_Function_PlatzSetAnimatedBgTable|void PlatzSetAnimatedBgTable(const animation *a)]]
* [[Platz_Function_PlatzSetAnimatedBgTable|void PlatzSetAnimatedBgTable(const animation *a)]]
* [[Platz_Function_PlatzSetBgDirectory|void PlatzSetBgDirectory(const bgDirectory *bgd)]]
* [[Platz_Function_PlatzSetBgDirectory|void PlatzSetBgDirectory(const bgDirectory *bgd)]]
* [[Platz_Function_PlatzSetBoundingBoxDimensions|u8 PlatzSetBoundingBoxDimensions(platzActor *a, u8 wid, u8 hgt)]]
* [[Platz_Function_PlatzSetBoundingBoxDimensions|u8 PlatzSetBoundingBoxDimensions(platzActor *a, u8 wid, u8 hgt)]]
* [[Platz_Function_PlatzSetInnerBgTable|void PlatzSetInnerBgTable(const bgInner *bgi)]]
* [[Platz_Function_PlatzSetInnerBgTable|void PlatzSetInnerBgTable(const bgInner *bgi)]]
* [[Platz_Function_PlatzSetMapsTable|void PlatzSetMapsTable(const char **m)]]
* [[Platz_Function_PlatzSetMapsTable|void PlatzSetMapsTable(const char **m)]]
* [[Platz_Function_PlatzSetMovingPlatformDirectory|void PlatzSetMovingPlatformDirectory(const platformDirectory *pDir)]]
* [[Platz_Function_PlatzSetMovingPlatformDirectory|void PlatzSetMovingPlatformDirectory(const platformDirectory *pDir)]]
* [[Platz_Function_PlatzSetMovingPlatformTable|void PlatzSetMovingPlatformTable(const platform *p)]]
* [[Platz_Function_PlatzSetMovingPlatformTable|void PlatzSetMovingPlatformTable(const platform *p)]]
* [[Platz_Function_PlatzSetMovingPlatformTiles|void PlatzSetMovingPlatformTiles(u8 hTilesIndex, u8 vTilesIndex, u8 clrTile)]]
* [[Platz_Function_PlatzSetMovingPlatformTiles|void PlatzSetMovingPlatformTiles(u8 hTilesIndex, u8 vTilesIndex, u8 shTilesIndex, u8 svTilesIndex)]]
* [[Platz_Function_PlatzSetMutCallback|void PlatzSetMutCallback(mutCallback mcb)]]
* [[Platz_Function_PlatzSetMutCallback|void PlatzSetMutCallback(mutCallback mcb)]]
* [[Platz_Function_PlatzSetMutClassTable|void PlatzSetMutClassTable(const mutableClass *mc)]]
* [[Platz_Function_PlatzSetObjectTable|void PlatzSetObjectTable(const object *obj)]]
* [[Platz_Function_PlatzSetObjectTable|void PlatzSetObjectTable(const object *obj)]]
* [[Platz_Function_PlatzSetOuterBgTable|void PlatzSetOuterBgTable(const bgOuter *bgo)]]
* [[Platz_Function_PlatzSetOuterBgTable|void PlatzSetOuterBgTable(const bgOuter *bgo)]]
* [[Platz_Function_PlatzSetPatternDirectory|void PlatzSetPatternDirectory(const patternDirectory *pDir)]]
* [[Platz_Function_PlatzSetPatternTable|void PlatzSetPatternTable(const char *p)]]
* [[Platz_Function_PlatzSetQueryCallback|void PlatzSetQueryCallback(queryCallback qb)]]
* [[Platz_Function_PlatzSetQueryCallback|void PlatzSetQueryCallback(queryCallback qb)]]
* [[Platz_Function_PlatzSetTriggerCallback|void PlatzSetTriggerCallback(triggerCallback tcb)]]
* [[Platz_Function_PlatzSetTriggerCallback|void PlatzSetTriggerCallback(triggerCallback tcb)]]
Line 62: Line 59:
===== Core =====
===== Core =====
* [[Platz_Type_Animation|animation]]
* [[Platz_Type_Animation|animation]]
* [[Platz_Type_bgAnimIndex|bgAnimIndex]]
* [[Platz_Type_bgDirectory|bgDirectory]]
* [[Platz_Type_bgDirectory|bgDirectory]]
* [[Platz_Type_bgInner|bgInner]]
* [[Platz_Type_bgInner|bgInner]]
Line 67: Line 65:
* [[Platz_Type_object|object]]
* [[Platz_Type_object|object]]
* [[Platz_Type_mutableCallback|mutableCallback]]
* [[Platz_Type_mutableCallback|mutableCallback]]
* [[Platz_Type_mutableClass|mutableClass]]
* [[Platz_Type_patternDirectory|patternDirectory]]
* [[Platz_Type_patternDirectory|patternDirectory]]
* [[Platz_Type_platform|platform]]
* [[Platz_Type_platform|platform]]
Line 81: Line 80:
* [[Platz_Type_rect16|rect16]]
* [[Platz_Type_rect16|rect16]]
* [[Platz_Type_line16|line16]]
* [[Platz_Type_line16|line16]]


== Level data format ==
== Level data format ==
Line 96: Line 94:
[[Platz_Type_object|Objects]] are your typical [[Function_DrawMap|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 [[Platz_Type_object|object]] as a BG.
[[Platz_Type_object|Objects]] are your typical [[Function_DrawMap|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 [[Platz_Type_object|object]] as a BG.


===== Pattern directory =====
===== Maps Table =====
The [[Platz_Type_patternDirectory|pattern directory]] is a LUT for your patterns. Although the entire Platz data format relies on BG patterns, 1x1 patterns are not specifically mentioned, but rather taken for granted. The [[Platz_Type_patternDirectory|pattern directory]] exists for patterns of size more than one. It indexes into the [[#Patterns|patterns table]] so that patterns can be reused within different [[Platz_Type_bgInner|Inner BGs]] without having to repeat the flash cost for storing the pattern (which could potentially be large). When an [[Platz_Type_bgInner|Inner BG]] has a pattern, its tile entry acts as an index into the [[Platz_Type_patternDirectory|pattern directory]].
The [[Platz_Function_PlatzSetMapsTable|maps table]] contains all the maps that will appear anywhere within your Platz level. Platz will automatically repeat maps to fill their containing [[Platz_Type_bgInner|Inner BG]]. Maps displayed as [[Platz_Type_object|Objects]] will not repeat. Maps that are not a power of two can be slightly slower to draw and are not supported without defining [[#Build options|SLOW_BG_PATTERNS ]].
 
===== Patterns =====
The [[Platz_Function_PlatzSetPatternTable|pattern table]] is a char array containing all of the tiles describing all of the patterns that appear anywhere in your level. It's up to the [[Platz_Type_patternDirectory |pattern directory]] to determine which entries form specific patterns. Patterns will automatically repeat to fill their containing [[Platz_Type_bgInner|Inner BG]]. It is preferred by Platz for you to supply patterns that are a power of two - this affords a very cheap modulo that ''dramatically'' improves performance (especially for large patterns). However, it is possible to supply patterns of any size by altering the [[#Build options|Build options]] to include SLOW_BG_PATTERNS.


===== Platform directory =====
===== Platform directory =====
The [[Platz_Type_platformDirectory|platform directory]] is a LUT for your [[Platz_Type_platform|platforms]]. It indexes into your [[Platz_Function_PlatzSetMovingPlatformTable|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 options|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 two platforms per world slice.  
The [[Platz_Type_platformDirectory|platform directory]] is a LUT for your [[Platz_Type_platform|platforms]]. It indexes into your [[Platz_Function_PlatzSetMovingPlatformTable|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 options|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 =====
===== Platforms =====
Line 121: Line 116:
* [[Image:Platform_y_axis_mid.png|Y-axis mid]]
* [[Image:Platform_y_axis_mid.png|Y-axis mid]]
* [[Image:Platform_y_axis_btm.png|Y-axis bottom]]
* [[Image:Platform_y_axis_btm.png|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 =====
===== Background animations =====
[[Platz_Type_Animation|BG animations]] can be thought of as immobile sprites. They will appear to move, but only within their containing [[Platz_Type_bgInner|Inner BG]]. Their directory exists within the [[Platz_Type_bgDirectory|background directory]] and [[Platz_Type_bgOuter|Outer BG]] structures. The [[Platz_Type_bgDirectory|background directory]] contains the count for how many background animations appear in the slice, and the [[Platz_Type_bgOuter|Outer BGs]] further split this count into the appropriate containers. [[Platz_Type_Animation|BG animations]] are always the first elements in a slice's list of [[Platz_Type_bgOuter|Outer BGs]] and similarly for [[Platz_Type_bgInner|Inner BGs]]. This allows Platz to find and load them without needing to store indexes. A side-effect of this is that [[Platz_Type_Animation|BG animations]] that are not part of slice seam collision checks must be checked regardless. This is a leftover from early designs and may be replaced with a BG animation directory in future releases. When an [[Platz_Type_bgInner|Inner BG]] has a [[Platz_Type_Animation|BG animation]], its tile entry acts as an index into the [[Platz_Function_PlatzSetAnimatedBgTable|animated BG table]]. As with [[#Patterns|patterns]], [[Platz_Type_Animation|BG animations]] will automatically repeat to fill their containing [[Platz_Type_bgInner|Inner BG]].
[[Platz_Type_Animation|BG animations]] can be thought of as immobile sprites. They will appear to move, but only within their containing [[Platz_Type_bgInner|Inner BG]]. Each has an entry in the [[Platz_Function_PlatzSetAnimatedBgDirectory|Animated BG directory]]. When an [[Platz_Type_bgInner|Inner BG]] has a [[Platz_Type_Animation|BG animation]], its tile entry acts as an index into the [[Platz_Function_PlatzSetAnimatedBgTable|animated BG table]]. As with [[#Patterns|patterns]], [[Platz_Type_Animation|BG animations]] will automatically repeat to fill their containing [[Platz_Type_bgInner|Inner BG]].


===== Triggers =====
===== Triggers =====
[[Platz_Type_triggerCallback|Triggers]] are Platz's event notification system. They can be set to call your special event handling code upon firing. For a [[Platz_Type_triggerCallback|trigger]] to fire, the [[Platz_Type_platzActor|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.
[[Platz_Type_triggerCallback|Triggers]] are act exclusively as an event notification system. They can be set to call your special event handling code upon firing. For a [[Platz_Type_triggerCallback|trigger]] to fire, the [[Platz_Type_platzActor|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.


[[Platz_Type_triggerCallback|Triggers]] can be specified to be vertical or horizontally aligned and to fire in one of two different orientations:
[[Platz_Type_triggerCallback|Triggers]] can be specified to be vertical or horizontally aligned and to fire in one of two different orientations:
Line 140: Line 137:


A [[Platz_Type_triggerCallback|Trigger]] is considered an [[Platz_Type_bgOuter|Outer BG]], except the count acts as an orientation flag and the [[Platz_Type_bgInner|Inner BG]] index acts as a client-defined flag which can be used for responding appropriately to different events.
A [[Platz_Type_triggerCallback|Trigger]] is considered an [[Platz_Type_bgOuter|Outer BG]], except the count acts as an orientation flag and the [[Platz_Type_bgInner|Inner BG]] index acts as a client-defined flag which can be used for responding appropriately to different events.
===== Mutable Bgs =====
[[Platz_Type_mutableCallback|Mutable BGs]] are another event notification system within Platz. They're different to triggers in that they are a type of [[Platz_Type_bgInner|Inner BG]], so they can be drawn and animated. Their event is fired upon collision with an [[Platz_Type_platzActor|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 [[Platz_Type_bgInner|Inner BGs]] come in pairs and must be contiguous in memory, with the payload BG following the presentation BG. Both [[Platz_Type_bgInner|Inner BGs]] as well as the containing [[Platz_Type_bgOuter|Outer BG]] are passed to the [[Platz_Function_PlatzSetMutCallback|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 =====
[[Platz_Function_PlatzSetMutClassTable|Mutable classes]] are a cheap form of Mutable BG. They cost the same as a regular [[Platz_Type_bgInner|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.


===== Other =====
===== Other =====
* The first tile of your tileset should be your primary background color (what you wish to appear where nothing is specified).
* The first tile of your tileset should be your primary background color (what you wish to appear where nothing is specified).
* [[Platz_Type_platform|Platform]] paths will only repaint with the single tile supplied to them at initialization - no objects/BGs should appear on this path.
* [[Platz_Type_platform|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_Level_Editor|LePlatz]] for the easy and flexible way to construct your Platz levels.




== Level creation ==
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.
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.


Line 446: Line 452:


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 [http://uzebox.org/forums/viewtopic.php?f=6&t=527 Platz toolset thread] in the Uzebox community forums.
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 [http://uzebox.org/forums/viewtopic.php?f=6&t=527 Platz toolset thread] in the Uzebox community forums.


== BG flags ==
== BG flags ==
* BGA - Marks the [[#Inner backgrounds|Inner BG]] as [[#Background animations|animated]].
* BGC - Marks the [[#Outer backgrounds|Outer BG]] as collidable.
* BGC - Marks the [[#Outer backgrounds|Outer BG]] as collidable.
* BGI - Marks the [[#Outer backgrounds|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 backgrounds|Outer BG]] and [[#Inner backgrounds|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 backgrounds|Inner BG]] as a member of a Mutable Class. Mutable classes are cheaper forms of Mutable bgs. The containing [[#Outer backgrounds|Outer BG]] must be flagged as BGM for this flag to be considered in collisions.
* BGP - Marks the [[#Inner backgrounds|Inner BG]] as [[#Patterns|patterned]].
* BGP - Marks the [[#Inner backgrounds|Inner BG]] as [[#Patterns|patterned]].
* BGA - Marks the [[#Inner backgrounds|Inner BG]] as [[#Background animations|animated]].
* BGQ - Marks the [[#Outer backgrounds|Outer BG]] as queryable. Collision detection will consult a user-defined callback before processing/ignoring a collision.
* BGTH - Marks the [[#Outer backgrounds|Outer BG]] as a horizontally aligned [[#Triggers|trigger]].
* BGT - Marks the [[#Outer backgrounds|Outer BG]] as a [[#Triggers|trigger]]. Width-to-height ratio determines axial alignment of trigger.
* BGTV - Marks the [[#Outer backgrounds|Outer BG]] as a vertically aligned [[#Triggers|trigger]].
* BGI - Marks the [[#Outer backgrounds|Outer BG]] as invisible. This can assist with efficient rendering. Usually paired with BGT*.
 
It was initially intended for flags to be combined, but, currently, the only combination recognized is BGT*|BGI. This is subject to change as the Platz toolset matures.


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


== Typical usage ==
== Typical usage ==
Line 463: Line 469:
** [[Platz_Function_PlatzSetTriggerCallback|PlatzSetTriggerCallback]] if you have no [[#Triggers|triggers]].
** [[Platz_Function_PlatzSetTriggerCallback|PlatzSetTriggerCallback]] if you have no [[#Triggers|triggers]].
** [[Platz_Function_PlatzSetMovingPlatformTable|PlatzSetMovingPlatformTable]] or [[Platz_Function_PlatzSetMovingPlatformDirectory|PlatzSetMovingPlatformDirectory]] if you set [[#Build options|MAX_MOVING_PLATFORMS]] to 0 in the makefile.
** [[Platz_Function_PlatzSetMovingPlatformTable|PlatzSetMovingPlatformTable]] or [[Platz_Function_PlatzSetMovingPlatformDirectory|PlatzSetMovingPlatformDirectory]] if you set [[#Build options|MAX_MOVING_PLATFORMS]] to 0 in the makefile.
** PlatzSetAnimatedBgTable if you set [[#Build options|MAX_ANIMATED_BGS]] to 0 in the makefile.
** [[Platz_Function_PlatzSetAnimatedBgDirectory|PlatzSetAnimatedBgDirectory]] or [[Platz_Function_PlatzSetAnimatedBgTable|PlatzSetAnimatedBgTable]] if you set [[#Build options|MAX_ANIMATED_BGS]] to 0 in the makefile.
** [[Platz_Function_PlatzSetMutCallback|PlatzSetMutCallback]] or [[Platz_Function_PlatzSetMutClassTable|PlatzSetMutClassTable]] if you don't have any Mutable BGs.
** [[Platz_Function_PlatzSetQueryCallback|PlatzSetQueryCallback]] if you don't wish to override collision detection in any circumstances.
* Initialize Platz [[#Core|core]].
* Initialize Platz [[#Core|core]].
* [[Platz_Function_ PlatzMoveToSlice|Move to starting position]].
* [[Platz_Function_ PlatzMoveToSlice|Move to starting position]].
Line 544: Line 552:


== Build options ==
== Build options ==
* MAX_MOVING_PLATFORMS - The maximum number of [[#Platforms|moving platforms]] that Platz will manage per slice. Set to 0 to save ram and cycles.
* MAX_MOVING_PLATFORMS - The maximum number of [[#Platforms|moving platforms]] that Platz will manage per slice. Set to 0 to save flash, ram and cycles.
* MAX_ANIMATED_BGS - The maximum number of [[#Background animations|animated BGs]] that Platz will manage per slice. Set to 0 to save ram and cycles.
* MAX_ANIMATED_BGS - The maximum number of [[#Background animations|animated BGs]] that Platz will manage per slice. Set to 0 to save ram and cycles.
* MUTABLE_BGS - Includes supporting code for [[#Mutable_Bgs|Mutable BGs]].
* PLATZ_SLIM - saves roughly 1k of flash at the cost of minor graphical compromises. Set to zero to disable (enabled by default).
* 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|patterns]] and [[#Background animations|animated BGs]] whose dimensions are not a power of 2. This is a minor performance loss since v1.1.
* SLOW_BG_PATTERNS - Platz will manage [[#Patterns|patterns]] and [[#Background animations|animated BGs]] whose dimensions are not a power of 2. This is a minor performance loss since v1.1.
Line 558: Line 567:
== Sources ==
== Sources ==
[http://code.google.com/p/uzebox-paul/source/browse/#svn/trunk/tools/platz SVN Sources]
[http://code.google.com/p/uzebox-paul/source/browse/#svn/trunk/tools/platz SVN Sources]
[http://code.google.com/p/uzebox-paul/source/browse/#svn/branches/tools/platz-alpha SVN Dev Branch]


[http://code.google.com/p/uzebox-paul/downloads/list Hex+Kernel+Source Pkg]
[http://code.google.com/p/uzebox-paul/downloads/list Hex+Kernel+Source Pkg]

Latest revision as of 05:03, 7 February 2010

About

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.

API

Functions

Core
Accessors
Mutators
Utilities

Types

Core
Utilities

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

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

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

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

Y-axis

  • 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

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.

Other
  • 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 = {
    TILE_STONE_TOP_LT,TILE_STONE_TOP_RT,TILE_STONE_BTM_LT,TILE_STONE_BTM_RT	// Pattern 0 - Stone
};

We then reference this entry in our pattern directory:

const patternDirectory pgmPatDir[] PROGMEM = {
    {2,2,0}
};
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 = {
    {0,1}
};
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={
    108,109,
    110,111,
    112,113,
    114,115
};
const char animWaterfallBtm[2 * 16] PROGMEM={
    116,117,
    118,119,
    120,121,
     17, 17,
    122,123,
    124,125,
    126,127,
     17, 17,
    128,129,
    130,131,
    132,133,
     17, 17,
    134,135,
    124,125,
    126,127,
     17, 17
};
const animation bgAnimations[] PROGMEM = {
    {2,2,1,4,0,0,8,animWaterfallTop},
    {8,2,4,4,0,0,8,animWaterfallBtm}
};

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 = {
    {{13,3},mapPlant},
    {{16,1},mapCloud},
    {{18,25},mapWeedSml},     // Slice 0 (3,3) (count,total)
    {{0,1},mapPalm},
    {{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 = {
    {BGC,1,0,0,{0,12,14,28}},
    {0,2,1,0,{12,32,15,28}},
    {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 = {
    {BGC,1,0,0,{0,12,14,28}},
    {0,2,1,0,{12,32,15,28}},
    {BGTH|BGI,ORI_LRUD,TRIG_WATER,0,{12,32,14,17}}  // Slice 0 (3,3)
    {BGC,10,3,0,{0,20,8,28}},
    {BGTV|BGI,ORI_LRUD,TRIG_WFALL0,0,{3,6,0,7}},
    {BGTV|BGI,ORI_LRUD,TRIG_WFALL1,0,{17,20,0,11}},
    {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 = {
    {BGC,1,0,0,{0,12,14,28}},
    {0,2,1,0,{12,32,15,28}},
    {BGTH|BGI,ORI_LRUD,TRIG_WATER,0,{12,32,14,17}}  // Slice 0 (3,3)
    {BGC,10,3,0,{0,20,8,28}},
    {BGTV|BGI,ORI_LRUD,TRIG_WFALL0,0,{3,6,0,7}},
    {BGTV|BGI,ORI_LRUD,TRIG_WFALL1,0,{17,20,0,11}},
    {BGC,7,13,0,{20,32,11,28}},                         // Slice 1 (4,7)
    {BGC,18,20,2,{0,32,11,28}},						
    {BGTV|BGI,ORI_LRUD,TRIG_WFALL2,0,{3,6,0,11}},		
    {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 = {
    {BGC,1,0,0,{0,8,0,4}},
    {BGC,1,1,0,{0,4,10,22}},
    {BGC,1,2,0,{8,12,0,8}},
    {BGC,1,3,0,{4,12,14,22}},
    {BGTH|BGI,ORI_LRUD,TRIG_WATER,0,{12,24,22,25}},
    {BGC,1,4,0,{12,24,0,2}},
    {0,1,5,1,{12,24,21,22}},
    {0,1,6,1,{0,32,22,28}},
    {BGC,1,7,0,{24,32,0,8}},
    {BGC,1,8,0,{24,32,14,22}}
};


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_WAVE,{12,32,15,16}},
    {0,TILE_WATER,{12,32,16,28}}           Slice 0 (3,3)
};


Slice 1

Inner BGs for Slice 1

const bgInner pgmBgsInner[] PROGMEM = {
    {BGP,0,{0,12,14,28}},
    {0,TILE_WAVE,{12,32,15,16}},
    {0,TILE_WATER,{12,32,16,28}},          Slice 0 (3,3)
    {0,TILE_GRASS_LT,{0,1,8,9}},
    {0,TILE_GRASS,{1,19,8,9}},
    {0,TILE_GRASS_RT,{19,20,8,9}},
    {0,TILE_GND_LT,{0,1,9,15}},
    {0,TILE_GND_RT,{19,20,9,11}},
    {0,TILE_GND_WAVE_LT,{0,1,15,16}},
    {0,TILE_GND,{1,19,9,28}},
    {0,TILE_GRASS_GND_LT,{19,20,11,12}},
    {0,TILE_GND_WATER_LT,{0,1,16,28}},
    {0,TILE_GND,{19,20,12,28}},
    {0,TILE_GRASS,{20,32,11,12}},
    {0,TILE_GND,{20,32,12,24}},
    {0,TILE_GND,{20,25,24,25}},
    {0,TILE_GND_SHARP_BTM,{25,32,24,25}},
    {0,TILE_GND,{20,24,25,28}},
    {0,TILE_GND_SHARP_RT,{24,25,25,28}},
    {0,TILE_WATER,{25,32,25,28}}           Slice 1 (17,20)
};


Slice 2

Inner BGs for Slice 2

const bgInner pgmBgsInner[] PROGMEM = {
    {BGP,0,{0,12,14,28}},
    {0,TILE_WAVE,{12,32,15,16}},
    {0,TILE_WATER,{12,32,16,28}},          Slice 0 (3,3)
    {0,TILE_GRASS_LT,{0,1,8,9}},
    {0,TILE_GRASS,{1,19,8,9}},
    {0,TILE_GRASS_RT,{19,20,8,9}},
    {0,TILE_GND_LT,{0,1,9,15}},
    {0,TILE_GND_RT,{19,20,9,11}},
    {0,TILE_GND_WAVE_LT,{0,1,15,16}},
    {0,TILE_GND,{1,19,9,28}},
    {0,TILE_GRASS_GND_LT,{19,20,11,12}},
    {0,TILE_GND_WATER_LT,{0,1,16,28}},
    {0,TILE_GND,{19,20,12,28}},
    {0,TILE_GRASS,{20,32,11,12}},
    {0,TILE_GND,{20,32,12,24}},
    {0,TILE_GND,{20,25,24,25}},
    {0,TILE_GND_SHARP_BTM,{25,32,24,25}},
    {0,TILE_GND,{20,24,25,28}},
    {0,TILE_GND_SHARP_RT,{24,25,25,28}},
    {0,TILE_WATER,{25,32,25,28}},          Slice 1 (17,20)
    {BGA,0,{4,20,13,21}},
    {BGA,1,{4,20,21,25}},
    {0,TILE_GRASS,{0,32,11,12}},
    {0,TILE_GND,{0,4,12,13}},
    {0,TILE_GND_SHARP_BTM,{4,20,12,13}},
    {0,TILE_GND,{20,32,12,13}},
    {0,TILE_GND,{0,3,13,24}},
    {0,TILE_GND_SHARP_RT,{3,4,13,24}},
    {0,TILE_GND_SHARP_LT,{20,21,13,24}},
    {0,TILE_GND,{21,32,13,24}},
    {0,TILE_GND_SHARP_BTM,{0,3,24,25}},
    {0,TILE_GND_SHARP_CNR_RT,{3,4,24,25}},
    {0,TILE_GND_SHARP_CNR_LT,{20,21,24,25}},
    {0,TILE_GND_SHARP_BTM,{21,30,24,25}},
    {0,TILE_GND,{30,32,24,25}},
    {0,TILE_WATER,{0,30,25,28}},
    {0,TILE_GND_SHARP_LT,{30,31,25,28}},
    {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
    InitMusicPlayer(patches);
    SetMasterVolume(0xb0);
    SetTileTable(tileset);
    SetSpritesTileTable(spriteset);
    SetSpriteVisibility(true);
     
    // Init platz pointers
    PlatzSetTriggerCallback(ActivateTrigger);
    PlatzSetMovingPlatformTable(pgmPlatforms);
    PlatzSetMovingPlatformDirectory(pgmPlatformDir);
    PlatzSetAnimatedBgTable(bgAnimations);
    PlatzSetPatternTable(patterns);
    PlatzSetPatternDirectory(pgmPatDir);
    PlatzSetObjectTable(pgmObjects);
    PlatzSetInnerBgTable(pgmBgsInner);
    PlatzSetOuterBgTable(pgmBgsOuter);
    PlatzSetBgDirectory(pgmBgDir);
     
    // Init platz scene
    PlatzSetMovingPlatformTiles(158,136,TILE_SKY);
    PlatzInit(&a,3);
    PlatzMoveToSlice(&a,0);
     
    while(1) {
        if (GetVsyncFlag()) {
            ClearVsyncFlag();
             
            /*
             *  Your game logic here
             */
             
            if (xVel != a.vx.vel)
                PlatzSetVelocity(&a.vx,xVel,&a.trLoc.x);
            if (yVel != a.vy.vel)
                PlatzSetVelocity(&a.vy,yVel,&a.trLoc.y);
             
            collFlag = PlatzMove(&a);
             
            /*
             *  React to collFlag here (maybe animate or end jump sequence etc)
             */
             
            MoveSprite(MY_SPRITE,a.sprx-a.bbx,a.loc.y-a.bby+1,MY_SPRITE_WID,MY_SPRITE_HGT);
            PlatzTick();
        }
    }
}

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

Sources

SVN Sources

Hex+Kernel+Source Pkg