Skip to content

Instantly share code, notes, and snippets.

@01010111
Last active November 20, 2019 15:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 01010111/ad017dbdd453e8f2d85b273b59ca861e to your computer and use it in GitHub Desktop.
Save 01010111/ad017dbdd453e8f2d85b273b59ca861e to your computer and use it in GitHub Desktop.
OGMO Editor 3 Flixel integration using zerolib-flixel

Integrating OGMO Editor 3 in HaxeFlixel

Using OGMO files in HaxeFlixel is quick and easy! By using typedefs and haxe.Json.parse() you can load your level's data with very little hassle.

This example uses my zerolib-flixel library, but all the code for what you need is listed below - just make sure you update the references if you use these files instead of using zerolib-flixel!

package states;
import flixel.FlxG;
import flixel.FlxObject;
import flixel.FlxSprite;
import flixel.tile.FlxTilemap;
import flixel.FlxState;
// We want to use these utilities as extensions!
using zero.utilities.OgmoUtils;
using zero.flixel.utilities.FlxOgmoUtils;
class PlayState extends FlxState
{
var level:FlxTilemap = new FlxTilemap();
var my_entity:MyEntity;
override function create() {
// First we use get_ogmo_package() to grab a handy reference to our project and level data
var ogmo = FlxOgmoUtils.get_ogmo_package('assets/data/my_ogmo_project.ogmo', 'assets/data/my_ogmo_level.json');
// Then we load our tilemap using FlxOgmoUtils.load_tilemap() - since we're `using` FlxOgmoUtils we can call this function with our FlxTilemap!
level.load_tilemap(ogmo, 'assets/images/tilesets/');
add(level);
// We can also add entities by calling load_entities() on our entity layer
ogmo.level.get_entity_layer('entities').load_entities(entity_loader);
// We can also load decals from a decal layer!
add(ogmo.level.get_decal_layer('decals').get_decal_group('assets/images/decals/'));
}
/**
* This is an example of a function to load entities with,
* it takes in an EntityData object and uses it to create our game's entities
* @param e EntityData contains all the relevant info we need to create entities in our game!
*/
function entity_loader(e:EntityData) {
// I like to use a switch statement and check the entity name to determine what entity to create
switch (e.name) {
case "My Entity": add(my_entity = new MyEntity(e.x, e.y));
}
}
override function update(e:Float) {
FlxG.collide(level, my_entity);
super.update(e);
}
}
/**
* A Basic Sprite to show entity loading
*/
class MyEntity extends FlxSprite {
public function new(x:Float, y:Float) {
super(x, y);
makeGraphic(16, 16, 0xFFFF004D);
acceleration.y = 600;
}
override function update(elapsed:Float) {
velocity.x = 0;
if (FlxG.keys.pressed.LEFT) velocity.x -= 100;
if (FlxG.keys.pressed.RIGHT) velocity.x += 100;
if (isTouching(FlxObject.FLOOR) && FlxG.keys.justPressed.SPACE) velocity.y = -200;
super.update(elapsed);
}
}
package zero.utilities;
using haxe.Json;
using zero.utilities.OgmoUtils;
/**
* A group of Utility functions for working with OGMO files (level .json and project .ogmo files) in haxe
*/
class OgmoUtils
{
// region PARSING
/**
* Parse OGMO Editor level .json text
* @param json
* @return LevelData
*/
public static function parse_level_json(json:String):LevelData
{
return cast json.parse();
}
/**
* Parse OGMO Editor Project .ogmo text
* @param json
* @return ProjectData
*/
public static function parse_project_json(json:String):ProjectData
{
return cast json.parse();
} // endregion
// region LAYERS
/**
* Get Tile Layer data matching a given name
* @param data
* @param name
* @return TileLayer
*/
public static function get_tile_layer(data:LevelData, name:String):TileLayer
{
for (layer in data.layers) if (layer.name == name) return cast layer;
return null;
}
/**
* Get Grid Layer data matching a given name
* @param data
* @param name
* @return TileLayer
*/
public static function get_grid_layer(data:LevelData, name:String):TileLayer
{
for (layer in data.layers) if (layer.name == name) return cast layer;
return null;
}
/**
* Get Entity Layer data matching a given name
* @param data
* @param name
* @return EntityLayer
*/
public static function get_entity_layer(data:LevelData, name:String):EntityLayer
{
for (layer in data.layers) if (layer.name == name) return cast layer;
return null;
}
/**
* Get Decal Layer data matching a given name
* @param data
* @param name
* @return DecalLayer
*/
public static function get_decal_layer(data:LevelData, name:String):DecalLayer
{
for (layer in data.layers) if (layer.name == name) return cast layer;
return null;
} // endregion
// region DATA
/**
* Get matching Layer data from a given name
* @param data
* @param name
* @return ProjectLayerData
*/
public static function get_layer_data(data:ProjectData, name:String):ProjectLayerData
{
for (layer in data.layers) if (layer.name == name) return layer;
return null;
}
/**
* Get matching Tileset data from a given name
* @param data
* @param name
* @return ProjectTilesetData
*/
public static function get_tileset_data(data:ProjectData, name:String):ProjectTilesetData
{
for (tileset in data.tilesets) if (tileset.label == name) return tileset;
return null;
}
/**
* Get matching Entity data from a given name
* @param data
* @param name
* @return ProjectEntityData
*/
public static function get_entity_data(data:ProjectData, name:String):ProjectEntityData
{
for (entity in data.entities) if (entity.name == name) return entity;
return null;
} // endregion
// region LOADERS
/**
* Perform a function using all entities in a given layer
* @param layer
* @param fn
*/
public static function load_entities(layer:EntityLayer, fn:EntityData -> Void)
{
for (entity in layer.entities) fn(entity);
}
/**
* Perform a function using all decals in a given layer
* @param layer
* @param fn
*/
public static function load_decals(layer:DecalLayer, fn:DecalData -> Void)
{
for (decal in layer.decals) fn(decal);
} // endregion
}
// region TYPEDEFS
// Parsed .OGMO Project data
@:dox(hide)
typedef ProjectData = {
name:String,
levelPaths:Array<String>,
backgroundColor:String,
gridColor:String,
anglesRadians:Bool,
directoryDepth:Int,
levelDefaultSize:{ x:Int, y:Int },
levelMinSize:{ x:Int, y:Int },
levelMaxSize:{ x:Int, y:Int },
levelVaues:Array<Dynamic>,
defaultExportMode:String,
entityTags:Array<String>,
layers:Array<ProjectLayerData>,
entities:Array<ProjectEntityData>,
tilesets:Array<ProjectTilesetData>,
}
// Project Layer
@:dox(hide)
typedef ProjectLayerData = {
definition:String,
name:String,
gridSize:{ x:Int, y:Int },
exportID:String,
?requiredTags:Array<String>,
?excludedTags:Array<String>,
?exportMode:Int,
?arrayMode:Int,
?defaultTileset:String,
?folder:String,
?includeImageSequence:Bool,
?scaleable:Bool,
?rotatable:Bool,
?values:Array<Dynamic>,
?legend:Dynamic,
}
// Project Entity
@:dox(hide)
typedef ProjectEntityData = {
exportID:String,
name:String,
limit:Int,
size:{ x:Int, y:Int },
origin:{ x:Int, y:Int },
originAnchored:Bool,
shape:{ label:String, points:Array<{ x:Int, y:Int }> },
color:String,
tileX:Bool,
tileY:Bool,
tileSize:{ x:Int, y:Int },
resizeableX:Bool,
resizeableY:Bool,
rotatable:Bool,
rotationDegrees:Int,
canFlipX:Bool,
canFlipY:Bool,
canSetColor:Bool,
hasNodes:Bool,
nodeLimit:Int,
nodeDisplay:Int,
nodeGhost:Bool,
tags:Array<String>,
values:Array<Dynamic>,
}
// Project Tileset
@:dox(hide)
typedef ProjectTilesetData = {
label:String,
path:String,
image:String,
tileWidth:Int,
tileHeight:Int,
tileSeparationX:Int,
tileSeparationY:Int,
}
// Parsed .JSON Level data
@:dox(hide)
typedef LevelData = {
width:Int,
height:Int,
offsetX:Int,
offsetY:Int,
layers:Array<LayerData>,
?values:Dynamic,
}
// Level Layer data
@:dox(hide)
typedef LayerData = {
name:String,
_eid:String,
offsetX:Int,
offsetY:Int,
gridCellWidth:Int,
gridCellHeight:Int,
gridCellsX:Int,
gridCellsY:Int,
?entities:Array<EntityData>,
?decals:Array<DecalData>,
?tileset:String,
?data:Array<Int>,
?data2D:Array<Array<Int>>,
?dataCSV:String,
?exportMode:Int,
?arrayMode:Int,
}
// Tile subset of LayerData
@:dox(hide)
typedef TileLayer = {
name:String,
_eid:String,
offsetX:Int,
offsetY:Int,
gridCellWidth:Int,
gridCellHeight:Int,
gridCellsX:Int,
gridCellsY:Int,
tileset:String,
exportMode:Int,
arrayMode:Int,
?data:Array<Int>,
?data2D:Array<Array<Int>>,
?dataCSV:String,
}
// Grid subset of LayerData
@:dox(hide)
typedef GridLayer = {
name:String,
_eid:String,
offsetX:Int,
offsetY:Int,
gridCellWidth:Int,
gridCellHeight:Int,
gridCellsX:Int,
gridCellsY:Int,
arrayMode:Int,
?grid:Array<String>,
?grid2D:Array<Array<String>>,
}
// Entity subset of LayerData
@:dox(hide)
typedef EntityLayer = {
name:String,
_eid:String,
offsetX:Int,
offsetY:Int,
gridCellWidth:Int,
gridCellHeight:Int,
gridCellsX:Int,
gridCellsY:Int,
entities:Array<EntityData>,
}
// Individual Entity data
@:dox(hide)
typedef EntityData = {
name:String,
id:Int,
_eid:String,
x:Int,
y:Int,
?width:Int,
?height:Int,
?originX:Int,
?originY:Int,
?rotation:Float,
?flippedX:Bool,
?flippedY:Bool,
?nodes:Array<{x:Float, y:Float}>,
?values:Dynamic,
}
// Decal subset of LayerData
@:dox(hide)
typedef DecalLayer = {
name:String,
_eid:String,
offsetX:Int,
offsetY:Int,
gridCellWidth:Int,
gridCellHeight:Int,
gridCellsX:Int,
gridCellsY:Int,
decals:Array<DecalData>,
}
// Individual Decal data
@:dox(hide)
typedef DecalData = {
x:Int,
y:Int,
texture:String,
?scaleX:Float,
?scaleY:Float,
?rotation:Float,
}
// endregion
package zero.flixel.utilities;
import flixel.FlxSprite;
import flixel.group.FlxGroup;
import flixel.tile.FlxTilemap;
using openfl.Assets;
using zero.utilities.OgmoUtils;
using zero.flixel.utilities.FlxOgmoUtils;
/**
* A group of Utility functions for working with OGMO files (level .json and project .ogmo files) in haxeflixel
*/
class FlxOgmoUtils
{
/**
* Returns a handy object containing OgmoProjectData and OgmoLevelData
* @param project_path
* @param level_path
* @return OgmoPackage
*/
public static function get_ogmo_package(project_path:String, level_path:String):OgmoPackage
{
return {
project: project_path.getText().parse_project_json(),
level: level_path.getText().parse_level_json()
}
}
/**
* Loads a tilemap
* @param tilemap the tilemap to load into
* @param data an OgmoPackage containing the project and level data
* @param tileset_path The path to the directory containing your tileset images
* @param tile_layer The name of your tile layer
*/
public static function load_tilemap(tilemap:FlxTilemap, data:OgmoPackage, tileset_path:String, tile_layer:String = 'tiles')
{
if (tileset_path.charAt(tileset_path.length - 1) != '/') tileset_path += '/';
var layer = data.level.get_tile_layer(tile_layer);
var tileset = data.project.get_tileset_data(layer.tileset);
switch layer.get_export_mode() {
case CSV: tilemap.loadMapFromCSV(layer.dataCSV, tileset.get_tileset_path(tileset_path), tileset.tileWidth, tileset.tileHeight);
case ARRAY: tilemap.loadMapFromArray(layer.data, layer.gridCellsX, layer.gridCellsY, tileset.get_tileset_path(tileset_path), tileset.tileWidth, tileset.tileHeight);
case ARRAY2D: tilemap.loadMapFrom2DArray(layer.data2D, tileset.get_tileset_path(tileset_path), tileset.tileWidth, tileset.tileHeight);
}
return tilemap;
}
/**
* Returns a group of decals from a DecalLayer
* @param layer The DecalLayer to load decals from
* @param path The path to the directory containing your decal images
* @param radians Whether or not your project exports angles in radians
* @return FlxGroup
*/
public static function get_decal_group(layer:DecalLayer, path:String, radians:Bool = true):FlxGroup
{
if (path.charAt(path.length - 1) != '/') path += '/';
var g = new FlxGroup();
var decal_loader = function(d:DecalData) {
var s = new FlxSprite(d.x, d.y, d.get_decals_path(path));
s.offset.set(s.width/2, s.height/2);
if (d.scaleX != null) s.scale.x = d.scaleX;
if (d.scaleY != null) s.scale.y = d.scaleY;
if (d.rotation != null) s.angle = radians ? d.rotation * 180/Math.PI : d.rotation;
g.add(s);
}
layer.load_decals(decal_loader);
return g;
}
static function get_tileset_path(data:ProjectTilesetData, path:String):String
{
return path + data.path.split('/').pop();
}
static function get_export_mode(layer:TileLayer):ETileExportMode
{
if (layer.exportMode == 1) return CSV;
else if (layer.arrayMode == 0) return ARRAY;
else return ARRAY2D;
}
static function get_decals_path(data:DecalData, path:String):String
{
return path + data.texture;
}
}
@dox:hide()
typedef OgmoPackage = {
project:ProjectData,
level:LevelData
}
@dox:hide()
enum ETileExportMode
{
CSV;
ARRAY;
ARRAY2D;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment