sprite placement in new game.

I wrote earlier about wanting to have certain sprites (enemies, locked doors, etc), have state that is persistent in a number of levels – screen-local (respawning when leaving/entering a room), map-local (enemies don’t respawn tiill you leave a dungeon and re-enter), and global (bosses stay dead, unlocked doors stay open!)

I kind of figured out a way to deal with this.  I never sucked it up to figure out some stuff with the wonderful DAME exporter (an awesome map editor for flixel/flashpunk/etc games) and its lua exporter business…but then I did, sort of, at least enough to make it kind of do what I wanted.

Every map I make is split into grids, because that’s how I want the camera to work. I also only want to load sprites on a certain grid. Currently when I export the sprites from DAME, they end up all under one XML <level> node. This is fine, but on a big map when I want to load certain sprites for a grid, I’d have to calculate every single object’s grid x and y coordinates!! Although that would probably work fine, that’s not as nice. So, I did the following:

After embedding the XML from DAME into my game, I iterate through its <level> nodes (remember, level nodes just correspond to contiguous “areas” in my game – perhaps a floor of a dungeon, someone’s house, etc.). I create a new XML (one that will be serialized/saved and later checked to determine state of a room) object, and create a new <level> node. For every object (enemy, door, etc) in the <level> node of the DAME XML, I convert its x and y coordinates into grid-coordinates, so [0,screen_width) -> 0, [screen_width,2*screenwidth) -> 1, etc. I check if I’ve already added a <grid> node to my new <level> node, if so, I append the object to the grid node, otherwise, make a new grid node, append it to the level node, and append the object to the grid node.

Conceptually I guess this wasn’t too unwieldy, but it took a little time to figure out the syntax and what not.

This DAME-generated XML:

<root>
	<level name="Dungeon_Test">
		<Slime x="96" y="32" p="1" alive="true" />
		<Slime x="128" y="32" p="1" alive="true" />
		<Slime x="80" y="32" p="1" alive="true" />
		<Slime x="176" y="224" p="1" alive="true" />
		<Slime x="224" y="368" p="1" alive="true" />
		<Slime x="80" y="256" p="1" alive="true" />
		<Slime x="16" y="336" p="1" alive="true" />
		<Slime x="32" y="352" p="1" alive="true" />
	</level>
	<level name="Area_X">
		<Slime x="80" y="80" p="1" alive="true" />
		<Slime x="0." y="32" p="1" alive="true" />
		<Slime x="16" y="112" p="1" alive="true" />
		<Slime x="48" y="32" p="1" alive="true" />
		<Slime x="48" y="80" p="1" alive="true" />
	</level>
</root>

is transformed to this XML (which will end up being serialized and used in the game):

<root>
  <level name="Dungeon_Test">
    <grid grid_x="0" grid_y="0">
      <Slime x="96" y="32" p="1" alive="true"/>
      <Slime x="128" y="32" p="1" alive="true"/>
      <Slime x="80" y="32" p="1" alive="true"/>
    </grid>
    <grid grid_x="1" grid_y="1">
      <Slime x="176" y="224" p="1" alive="true"/>
    </grid>
    <grid grid_x="1" grid_y="2">
      <Slime x="224" y="368" p="1" alive="true"/>
    </grid>
    <grid grid_x="0" grid_y="1">
      <Slime x="80" y="256" p="1" alive="true"/>
    </grid>
    <grid grid_x="0" grid_y="2">
      <Slime x="16" y="336" p="1" alive="true"/>
      <Slime x="32" y="352" p="1" alive="true"/>
    </grid>
  </level>
  <level name="Area_X">
    <grid grid_x="0" grid_y="0">
      <Slime x="80" y="80" p="1" alive="true"/>
      <Slime x="0." y="32" p="1" alive="true"/>
      <Slime x="16" y="112" p="1" alive="true"/>
      <Slime x="48" y="32" p="1" alive="true"/>
      <Slime x="48" y="80" p="1" alive="true"/>
    </grid>
  </level>
</root>

By this chunk of AS3 code (FYI, there are some static thingies from me playing around calling this function from elsewhere, also saveXML needs to be referenced globally)


[Embed (source =  '../xml/Seen.xml', mimeType = "application/octet-stream")] public static const EmbedXML:Class;
public static var embedXML:XML = new XML(new EmbedXML);
public static var saveXML:XML = <root> </root>;

public static function embed2saveXML():void {

    var savelevel:XML; //Will be a level node for our saveXML tree
    var o:XML; //Generic object XML
    var level:XML; //For each "level" (house/dungeon/whatever)
    var grid:XML; //Represents a "grid"
    var grid_exists:Boolean; // Set to true when an existing grid is found
                             // while iterating through some level's grids
    var name:String;
    var x:int; var grid_x:int;
    var y:int; var grid_y:int;

    //Every level corresponds to a floor of a dungeon,
    //a house, the world map, etc.
    for each (level in embedXML.level) {
        savelevel = <level/>;
        savelevel.@name = level.@name;
        // These are all the DAME objects.
        for each (o in level.*) {
            //convert XY into Grid X,Y.
            x = parseInt(o.@x);
            y = parseInt(o.@y) + HEADER_HEIGHT;
            grid_x = x / Registry.SCREEN_WIDTH_IN_PIXELS;
            grid_y = y / Registry.SCREEN_HEIGHT_IN_PIXELS; 

            // Append the object "o" to the grid node if it already exists.
            grid_exists = false;
            for each (grid in savelevel.grid) {
                if (grid.@grid_x == grid_x.toString() && grid.@grid_y == grid_y.toString()) {
                    grid.appendChild(o);
                    grid_exists = true;
                    break;
                }
            }
            // Otherwise, create a new grid node and append "o" to it.
            if (!grid_exists) {
                grid = <grid/>
                grid.@grid_x = grid_x.toString();
                grid.@grid_y = grid_y.toString();
                grid.appendChild(o);
                savelevel.appendChild(grid);
            }
        }
        //Finally, append the transformed level node to the serialized XML.
        saveXML.appendChild(savelevel);
    }
}

Is there a better way to do this? Probably! But this works…it seems. Of course, more attributes will have to be added and what not to deal with state, but this is a good base for that.