Showing posts with label reference. Show all posts
Showing posts with label reference. Show all posts

Thursday, January 2, 2014

LIME 4 Data File Formats

One thing that I've had to reference repeatedly in developing LIME 4 is the file format for opening and saving map data files.  I figure that if I, the creator, can't remember it, then my users probably won't either.  Therefore, even though this information is in the API documentation, I'm going to post it here too.

Just as in previous versions of LIME, the data is separated into multiple files.  However, the content and structure of the files has changed to be more flexible and force fewer assumptions upon level designers.

Both file types are tab-delimited as specified by the constant MHMapFileInfo.MAP_FILE_DELIMITER.

The file types are as follows:

File TypeExtensionDescription
Game World Metadata.LIMESummary data required to open, initialize, modify, and save game world data in a format recognized by LIME and MHFramework.  This is the file type given to MHWorldLoader.loadGameWorld() and also the type that is opened by LIME's File | Open command.
Tile Map.LTMA file containing the data for a single tile map, which may stand alone or as a layer in a layered tile map. This is the file type given to MHWorldLoader.loadTileMap() and also the type expected in the file name properties of a .LIME file.

Game World Metadata (.LIME) File Format

  • Map width (columns) : int
  • Map height (rows) : int
  • Tile width (pixels) : int
  • Tile height (pixels) : int
  • Tile set ID : String
  • Floor map file name : String
  • Floor details file name : String
  • Wall map file name : String
  • Wall details file name : String

Tile Map (.LTM) File Format

  • Number of columns : int
  • Number of rows : int
  • Tile ID grid : int[][]

Friday, September 27, 2013

Old vs. New Tile Map Systems

After some thought experiments and pen-and-paper prototypes, I'm ready to commit to the new tile map data design for MHFramework 3. I'm content that I've found a solution that satisfies the goals of functionality, usability, performance, and supportability. Plus it will allow me to maintain the qualities that I didn't want to lose from the previous versions of LIME, and in fact, will improve upon some of them.

Differences From Previous Versions

Other than having a whole new set of layers, there are quite a few differences in the new design, involving the data structures and algorithms both.

Reversed Relationships in the Data Structure

The old system consisted of a matrix of MHMapCell objects. A map cell held an array of actors such that there was zero or one actor for each layer. So, technically, the map wasn't layered, but the map cells were.

Conceptually, the new tile map consists of two coarsely-plotted pairs of layers (a pair for floors and a pair for walls), each with a sparsely populated, semi-transparent overlay layer for adding decorations and other composite effects. The benefits to this change are countless -- performance, memory efficiency, flexibility, more intuitive optimizations, and more.

So the old system was essentially a matrix of arrays while the new system is an array of matrices.

Actors Are Not Tiles

Unlike the previous iterations, actors are not actually stored in the tile grid, but the class will still keep a list of them for rendering, collision detection, and persistence purposes.

Furthermore, although actors are no longer treated as tiles, tiles can still be actors. We can still have floor switches, teleporter pads, flowing water, blinking runway lights, and so on. The difference is that now they're stored in the actor list rather than a tile grid.  To load these things from map data files, I'll be renaming MHObjectFactory to the more specific name MHActorFactory to better reflect its true purpose.

More Sophisticated Rendering Algorithm

The new rendering process will go something like this.
  1. Lay down the section of the floor layer that is visible to the camera.
  2. If a layer of floor decals is present, apply them in a separate pass.
  3. Put all visible actors and wall tiles in a list and sort them on the y values of their base anchor points.
  4. Draw every element in the sorted list.  For each wall tile encountered, check for a decal and render it if present.

New Collision Rules and Terrain Height Variations

In the old system, collision detection was straightforward.  If the wall layer in a given map cell was occupied, then it was an obstacle. Though admirably simple and adequate for rectangular tile maps, it's insufficient for representing 2.5D phenomena like projectiles flying over tables or variations in the height of terrains. Therefore, the new collision detection logic for isometric maps needed to be much more sophisticated.

First, the relevant values are either initialized or calculated.
  • Actor climb = the maximum difference in terrain height between map cells that an actor can traverse.
  • Actor altitude = the actor's height from the ground when falling, jumping, flying, etc.
  • Actor elevation = map cell height + actor's altitude.
  • Obstacle height = height of image - base tile height.
Then, for all potential obstacles, a collision occurs when:
  1. The obstacle is a wall and the actor's short-range look-ahead vector entered its map cell OR
  2. The actor's and the obstacle's collision geometries intersect AND
  3. The actor's elevation plus its climbing ability is below the obstacle's height.


Table of Tile Map Layer Properties

One of the major goals I had for this redesign was to keep the reusability of the tile grid for essentially all tile map types, be they isometric or rectangular, top-down or side-scrolling, diamond or staggered. To this end, the layer ID constants have synonyms to help keep it simple for developers using the engine.

LayerSynonymCollidableInterlaced
FLOORBACKGROUNDNoNo
FLOOR_DECALSBACKGROUND_DECALSNoNo
WALLSFOREGROUNDYesYes
WALL_DECALSFOREGROUND_DECALSNo

Tuesday, February 19, 2013

Getting Started With MHFramework 3

Though still in the early stages of development, MHFramework 3 is vastly different from its predecessors in a variety of ways.  However, those prior versions had certain strengths that I desperately want to maintain as we go forward with the engine's redesign.  One of those strengths is the simplicity of the initial setup.

One of the highest priority design goals of MHF3 is cross-platform portability between Android and PC-based platforms.  With this in mind to help guide my design decisions, the initial setup for both platforms follows a simple, three-step process, with only a slight modification to the Android version:
  1. Create at least one screen.  This is done by inheriting from the engine's MHScreen class. (More on this in a future post.)
  2. Define your display settings by initializing an MHVideoSettings object.
  3. Pass those things into the engine along with the window in which your game app will run.  This is accomplished with a call to MHFramework.run().

Here's a PC-compatible example of a main class that accomplishes these things.

import javax.swing.JFrame;

import com.mhframework.MHFramework;
import com.mhframework.MHScreen;
import com.mhframework.MHVideoSettings;


public class PlatformTestPCWindow
{
    public static void main(String[] args)
    {
        // Step 1:  The screen.
        MHScreen startingScreen = new TestScreen();
        
        // Step 2:  The video settings.
        MHVideoSettings displaySettings = new MHVideoSettings();
        displaySettings.displayWidth = 800;
        displaySettings.displayHeight = 480;

        // Step 3:  Run it!
        MHFramework.run(new JFrame(), startingScreen, displaySettings);
    }
}

The Android version takes a very similar approach, but with a few additional rules:
  1. The main class must inherit from the engine's MHAndroidActivity class, which is a specialization of Android's basic Activity class that adds additional support for MHF3's multithreading requirements. 
  2. Rather than perform those steps in main, your program must override the Activity.onCreate() method. 
  3. Since Android's orientation can be specified as portrait or landscape, this must be specified here as well.  
    • Future versions may simply add the orientation constant as a field in MHVideoSettings and default it to landscape.  This way, the Android version will use the exact same three steps with no additional requirements.

import android.content.pm.ActivityInfo;
import android.os.Bundle;

import com.mhframework.MHFramework;
import com.mhframework.MHScreen;
import com.mhframework.MHVideoSettings;
import com.mhframework.platform.android.MHAndroidActivity;

public class PlatformTestAndroid extends MHAndroidActivity
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        // Initialize Android-specific properties.
        super.onCreate(savedInstanceState);
        this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        
        // Step 1:  The screen.
        MHScreen startingScreen = new TestScreen();
        
        // Step 2:  The video settings.
        MHVideoSettings displaySettings = new MHVideoSettings();
        displaySettings.displayWidth = 800;
        displaySettings.displayHeight = 480;

        // Step 3:  Run it!
        MHFramework.run(this, startingScreen, displaySettings);
    }
}


Monday, March 21, 2011

Tile Image File Naming Conventions

This post is for primarily for reference. Level designers need to know what to do with the files created by the FTT and WTT (Floor Tile Transformer and Wall Tile Transformer, respectively). Specifically, they'll need to know how to rename the files so that they'll be picked up by LIME when creating the maps for the various levels in the game. That is the purpose of this reference.

Here's a reference explaining the format and meaning of the tile image file names.

Elements:
Layer
Tile Set Number
Tile Number
Animation Frame Number
File Extension
Valid Values:
F, L, I, O, W, D, C00-99000-99900-99.png, .gif
Notes:
F = Floor,
L = Floor Detail,
I = Item,
O = Obstacle,
W = Wall,
D = Wall Detail,
C = Ceiling
2 digits3 digits2 digits

Example: F0100400.gif