OpenFL - Creating the Hero

on tutorials rpg

A role-playing game cannot exist without a user controlled character.

posts/creating_the_hero/hero.png

A RPG is full of many monsters, npcs and interactive objects. We need a way to hold all of the definitions and easily create any number of them when needed. So similar to the Tilesheet and TileData classes. Lets create an EntityStore and EntityData class. The EntityStore will hold all the entity datas in the game.

public function loadEntityDatas(){
    _entityDatas.push(new EntityData());

    var cloth:EntityData = new EntityData();
    cloth.name = "Cloth";

    var clothBitmapData = Assets.getBitmapData("assets/images/entities/cloth.png");
    var yTiles:Int = 12;
    var tileHeight:Int = Math.floor(clothBitmapData.height / yTiles);

    var point:Point = new Point(0, 0);
    var rect:Rectangle = new Rectangle(0, 0, GameObject.tileSize, tileHeight);

    cloth.bitmapData = new BitmapData(GameObject.tileSize, tileHeight);
    cloth.bitmapData.copyPixels(clothBitmapData, rect, point);

    _entityDatas.push(cloth);
}

This creates one empty entity data and an other called cloth which will be our hero. The cloth.png image is a sprite sheet with a variety of directions and animations. Right now only the first sprite will be used. The yTiles is the number of tiles the sprite sheet has in the the y direction. This is used to find the height of the sprite tiles. This is needed because entities do not have a static height like normal tiles and it can be greater than the tile size.

Next the Entity class has to be created. This will create the hero instance with our choosen sprite. The Entity class simply holds a bitmap and extends the GameObject class.

Generic base object

The GameObject is a new base class which Tile and Entity extend from.

class GameObject {
    public static var tileSize:Int;
    private static var idCount:Int;

    public var xt(get, set):Int;
    public var yt(get, set):Int;

    public var x(get, set):Float;
    public var y(get, set):Float;

    public var id(get, null):Float;

    private var _x:Float;
    private var _y:Float;

    private var _id:Int;
}

It gives each instance a unique id and implements x / y getters and setters. Finally it implementes xt / yt getters and setters which are short for xTile and yTile. They will convert tile coordinates into world space and the getters will convert world coordinates back into tile coordinates like so.

public function set_xt(value:Int) {
    x = value * tileSize;
    return Math.floor(x);
}

public function get_xt():Int {
    return Math.floor(x / tileSize);
}

The purpose of the GameObject is to provide a coordinate interface for all map objects. If you notice it does not hold a bitmap because not all map objects display anything, ie teleporters, traps.

Now back to the Entity class, because entities can have heights larger than tiles. An entity needs to be positioned higher to stay on its tile.

override private function yChange(value:Float){
    bitmap.y = value - bitmap.height + GameObject.tileSize;
}

This is a special hook which listens for y coordinate change events and positions the entity's bitmap correctly.

posts/creating_the_hero/hero_height.png

With all that, the hero entity instance can be created.

heroPortal = new Portal(EntityStore.CLOTH, 2, 2);

heroEntity = new Entity();
heroEntity.entityData = entityStore.getEntityData(heroPortal.id);
heroEntity.xt = heroPortal.xt;
heroEntity.yt = heroPortal.yt;

map.addChild(heroEntity.bitmap);

The Portal class is a simple value-object which holds xt, yt, and an id which is used to identify an entityData definition. Portals will be used more often during map creation, it can be used to place entities, items, events and any game object.

The rest is quite simple, a new entity is created with the portal and added to the map.

Next tutorial: Movement