The level generation API is the under-construction API in the glib.world package. This package has five top-level classes that handle each level as well as information about the sprite’s position in the level. The classes are:

  • Info: A set of booleans giving information about a sprite.
  • Tile: The building block of the world.
  • TileCollision: An enumeration that indicates the properties of the tile.
  • TileMap: A mapping of characters to tiles to help speedy generation of levels.
  • World: The representation of the level.

The building block of each level is a tile. Consider the following image from Metroid: Zero Mission.

Tiles in Zero Mission

An image from Metroid: Zero Mission. Note the tiles, with an orange border

The tiles ave an orange border. This images show ‘null tiles’: Tiles with no image that allow the background to be seen. The location of tiles is specified with a tile map. A Tile map for the above image could be:

….f…..f……
….p…..p……
….mm…mm……
….mm…mm……
……………..
….mmmmmmm……
rrrmmmmmmmmmmmmmm

The first thing you will notice is that the tile map does not seem to ‘fit’ the level. This is because of the variable width. The letters ‘m’ and ‘f’ have different widths, and the period is very narrow compared to them. Each character is mapped by the tile map to an individual tile: ‘f’ to a carved face, ‘m’ to a brick of metal, ‘r’ to a rock, ‘p’ to a pedestal, and ‘.’ to a null tile.

Tiles may be TileCollision.PASSABLE, meaning they are bits of scenery (null tiles, for example); or TileCollision.PLATFORM, indicating they are solid and stop the player in his tracks. The Tile class has the following constructors:

  • Tile(): A null tile, this tile has no image
  • Tile(File, TileCollision): A tile with specified collision and image.

Tile objects have public properties tileImage (of type BufferedImage) and collision (of type TileCollision). Tile maps are specified by the TileMap class. TileMap has the following constructors:

  • TileMap(): A TileMap with no Tiles
  • TileMap(File): Reads a TileMap from the specified file.Directly using Utils.loadTileMap is preferred.

TileMaps can be stored in a file with the following format:

character image URL
character:image URL
character: image URL

The accepted delimiters between characters and URLs are a space, a colon, and a colon followed by a space. The tile map for the above image could be:

f: images/brinstar/face.png
p: images/brinstar/pedestal.png
m images/brinstar/metal.png
r:images/brinstar/rock.png

Tiles generated are, by default, PASSABLE. TileMaps have the following methods:

  • setTile(char,BufferedImage): Creates a PASSABLE tile with the specified image and sets it to the character.
  • setTile(char,Tile): Sets the tile to the specified character.
  • getTile(char): Gets the tile associated with the given character.
  • setDefaultTile(Tile t)/getDefaultTile(): Set or get a tile to be used if the TileMap reads an unregistered character.
  • SetSpriteTile(SpriteTile)/getSpriteTile: Set or get a SpriteTile object (see next section).
  • placeTile(char,int,int): Gets the tile associated with the given character. This method is used by GLib to place sprites (see next section).

Internally, TileMap uses a HashMap<Character,Tile>.

TileMaps also allow sprites to be placed using the SpriteTile interface. SpriteTile contains only one method, placeTile(char,glib.utils.Vector). This method is used as follows:

  1.   The World object calls TileMap’s placeTile method with a character.
  2. If a SpriteTile object is installed, it is queried for the tile.
  3. If the SpriteTile object knows the character, it returns the tile at the given place, and places a Sprite (the Vector location corresponds to the upper-left corner of the tile). If it does not know the character, it returns null.
  4. If there is no SpriteTile, or the SpriteTile returned null; getTile is called to place a Tile. The default tile (if installed) is used if getTile is null.

GLib is designed to handle nulls very well. Instead of throwing NullPointerExceptions, GLib tries to use a sensible default behaviour as far as possible. Null is an accepted value for a Tile, and Tiles with value null are skipped over -as though they were transparent PASSABLE tiles.

Complete levels are specified by World objects. Each object maintains a set of Tiles in a Tile[][] array. World objects are responsible for maintaining the tiles and drawing them to the screen. Games are drawn in the following manner:

  1. First, a rectangle of the Screen object’s background color is drawn. By default, this is white. If the backgroundColor property is null, this is skipped.
  2. A background image, if it exists, is drawn
  3. If it exists, The tiles in the World object are drawn.
  4. The game object’s preDraw() method is called
  5. All sprites are rendered. Sprites are added to the game in lists, using the screen’s add(List<? extends Sprite>) method. Lists added first are drawn first, and sprites earlier in the list are drawn earlier.

It’s possible to add empty lists, so that bullets, bombs, and such can be dynamically added to and removed from drawing. GLib normally handles nulls very well -it may default to a reasonable behavior, or just skip the affected steps. Nulls are also handled equally well here, null lists and null sprites being simply passed over. Keep in mind though, that sending nulls is a bad coding practice -they’re a time bomb waiting to go off. Use empty lists instead.

World also allows a sprite to know about its surroundings. Sprites are informed of it before they are updated, using the tell() method. This uses the Info class, which we learn about now.

The Info class is really a struct, with four boolean variables. All four are public, and tell a sprite about it’s surroundings. They are:

  • shouldStopUp
  • shouldStopDown
  • shouldStopLeft
  • shouldStopRight

Each variable tells a sprite if it is about to collide with a tile in the specified direction. If your sprite has a PlayerEventHandler object associated with it, then it goes a step further and informs it to stop moving in that direction. Sprites may also be bouncing sprites, indicating that when they collide with a non-PASSABLE tile, they are to bounce off. A future update will allow sprites to destroy themselves on contact, simplifying beams, missiles, and other such weaponry.

The methods of World are:

  • left(): Shifts the world to the right. This is because, due to parallax, if a player moves to the right, the world  shifts to the left.
  • right(): Shifts the world to the left.
  • up(): Shifts the world downwards.
  • down(): Shifts the world upwards.
  • getInfo(Sprite s): Returns an Info object about the sprite’s location. This method is currently buggy, and is continuously being fixed and tweaked.
  • setScreenDimensions(int,int): set the width and height. Automatically called by Screen.

This concludes the level generation API. Keep in mind that this is still incomplete, and liable to change. This is also the last of the basic tutorials. These tutorials are written to set a base framework on which further tutorials will build up on. Further tutorials will show how to build a simple game, and extend the basic classes of GLib. These will lead up to the final set, which will showcase a basic platformer game.