Cleanly Mixing Enums and Integer Indices in haXe

I started programming in C# and Enums are handled quite differently in that language. The first time I started using Enums in haXe I got slightly enraged but with the help of the IRC channel users and some fine tuning of my own I was able to come up with a nice elegant solution to the problem. Maybe some other noobs life can be made easier now. This is not a problem that should ever cause any kind of rage ^^

Note that this does not touch on the much more advanced Enum functions that haXe has to offer as described here: Enums & More on Enums.

The Problem

While writing my random dungeon generator I came across a small problem. I wanted to keep game specific mechanics separate from the dungeon gen logic as to allow maximum flexibility. Due to this constraint the dungeon generator has no concept of tile types (terrain etc) but holds all data as simple Integers.

However I would very much like to use enums in my tile definitions on the game logic side. It is a natural, easily read and clean way of handling the issue with the added benefit of being easy to refactor.

Due to the dungeon generator using Integers and the game using Enums a conflict arises. At first it may look like a switch statement will be needed to take care of the issue.. But we don’t need no stinking switch statement. That’s just more code, slower and also can end up being a royal pain to refactor. (Believe me the reason I’m writing this is because I was  to stupid to see the following solution right away)

Solution

The problem is easily avoided by using Type.indexEnum() in a way that allows the user to use the Enums and makes the compiler deal with the Integers. I know that makes no sense whatsoever so here is the code:

Tile Definitions:

// Tile type information is stored
// in a structure
typedef TileDef =
{
	var name : String;
	var color : UInt;
	// Etc...
}

// We use an enum for readabilty
enum TileType
{
	ROCK;
	DIRT;
	WALL;
	FLOOR;
	WATER;
	// Etc...
}

// The individual structures containing
// tile data are stored in a TypedDictionary
var tileLookUp : TypedDictionary;

// We define what makes a tile type and
// add that info to the dictionary
function tileDefs() {

	tileLookUp = new TypedDictionary();
	var newTileDef : TileDef;

	newTileDef = { name : "Rock Wall" , color : 0x8B5742 };
	tileLookUp.set(Type.enumIndex(ROCK), newTileDef);

	newTileDef = { name : "Dirt Floor" , color : 0xC2B280 };
	tileLookUp.set(Type.enumIndex(DIRT), newTileDef);

	// And so on...
}

Function that uses them:

public function setTile(x:Int, y:Int, tileID:Int) 	{

	colorCell(x, y, tileLookUp.get(tileID).color);
}

Calling the function:


setTile(14,12,Type.enumIndex(DIRT));

Explanation

The very simple magic here is using Integers as keys and setting them with the index of the Enum element instead of the Enum Element itself. The reason this works is because the compiler is the one who has to deal with the integer indexing. The user just pays the very small price of using “Type.enumIndex()”  which is essentially the same as calling the Enum directly.

If the need arises the code can be refactored without a hitch. Enum elements can be added at any position without the need to rewrite code anywhere else due to the index being read at compile time and used at runtime.  The user need only work with the much more easy to manage Enums.

Leave a Reply