Difficulties loading maps from XML


(Tareq) #1

Hello everyone, this is my first post (unfortuantely it had to be something that I’m having difficulties in >.<)

Anywho, I’m not too experienced with FlashPunk so do forgive my ignorance over some things. I wanted to make a small RPG game but didn’t know where to start. So I searched through the web and found a blog that teaches how to basic RPG. I am basically on the second part of the tutorial, which is loading in maps: The RPG Tutorial I’m following.

What I’ve noticed is that this person, at the time of writing the tutorial, was using an older version of OGMO (Version 1.01?). I thought it wouldn’t matter since I can still export XML Coord in the newer version. What the tutorial is basically doing is to have Entities to read in their own XML coordinates and then place in game; essentially, I have Ground entity (collision is done here as well), Tree entity, and Houses Entity. All 3 of which also handle tiles.

Now this is how I want my map to look like:

Instead I, all my tiles are loaded on top of each other on the top left corner (would show pic, but I can neither load a picture or post another link of it). Basically, the tiles are being iterated through, and it seems like it’s all being placed in the same coordinates (I had it traced to see whether it’s even tiling them at all)

So here’s the code that I wrote (from tutorial). Pretty much the same except that I had to place an “@” on the parameter “map.@width” and “map.@height” (in the constructor, graphic = tilemap bit) otherwise I get an error saying invalid BitString.

package entities 
{
import net.flashpunk.*;
import net.flashpunk.graphics.*;
import net.flashpunk.masks.Grid;


// This class has 2 tasks:
// 1) Read the ground layer data from the OEL file and use it to fill the tile map
// 2) Read the grid layer data from the OEL file and use it to gill the mask property
public class Ground extends Entity 
{
	// defining the diminesion of tiles and grids
	// It's possible to have a grid with smaller grids than tiles for better collisions (not covered here for simiplicity sake)
	private const TILE_WIDTH:Number = 48;
	private const TILE_HEIGHT:Number = 48;
	private const RECT_WIDTH:Number = 48;
	private const RECT_HEIGHT:Number = 48;
	
	// Set the tiles.png to class, stored in a constant
	[Embed(source = "../assets/gfx/tiles.png")]
	private const TILE_SET:Class;
	
	// Tile data and grid data
	public var tileMap:Tilemap; 
	public var grid:Grid;
	
	public function Ground(map:XML) // "map" is a parameter/ map oel that we'll pass on when it's called from another class
	{
		// label for collision detection (the layer that's a grid-type)
		type = "solid";
		
		
		//setting the graphic property of the entity super class
		graphic = tileMap = new Tilemap(TILE_SET, map.@width, map.@height, TILE_WIDTH, TILE_HEIGHT);
		trace (map.@width + " " + map.@height)
		// Fill tilmap with content
		for each (var tile:XML in map.ground[0].tile)
		{
			tileMap.setTile(tile.@x / TILE_WIDTH,
							tile.@y / TILE_HEIGHT,
							tileMap.getIndex(tile.@tx / TILE_WIDTH, tile.@ty / TILE_HEIGHT)
							);
		}
		
		// setting the mask propert of the Entity super class
		// No tilemap needed, used for collision
		mask = grid = new Grid(map.@width, map.@height, RECT_WIDTH, RECT_HEIGHT);
		
		// fill the tilemap with the content from xml
		for each (var solid:XML in map.solid[0].rect)
		{
			grid.setRect(solid.@x / RECT_WIDTH,
						 solid.@y / RECT_HEIGHT,
						 solid.@w / RECT_WIDTH,
						 solid.@h / RECT_HEIGHT
						 );
		}
		
		
	}
	
}

This is the XML file I’m trying to load from: http://pastebin.com/Z4rqKPSX

There is a little difference between my oel and the tutorial’s oel although I wouldn’t think it would matter as much (You may need to downlaod the source code of the tutorial for this particular problem). I understand that there is probably a better way to load in maps, but since this is a continous tutorial I’m following (an old one at that) I thought I could stick with it and then later change it to make it a bit more up to date. I can add the oel provided by the tutorial and use that, it’ll work without a problem, but I’m not sure why I can’t use my own oel’s.

Here’s the tutorial’s oel file: http://pastebin.com/9GtVe0vR

Thank you


(Zachary Lewis) #2

I made some edits to your post to clean it up a bit.


(Tareq) #3

Thank you, I see you’ve added the image (at least, I think you did o.O )


(Nicole Brauer) #4

I only had a quick look over your code, so I might be wrong, but I think this is the problem:

    for each (var tile:XML in map.ground[0].tile)
    {
        tileMap.setTile(tile.@x / TILE_WIDTH,
                        tile.@y / TILE_HEIGHT,
    ...

Remove “/ TILE_WIDTH” and “/TILE_HEIGHT”. (You might also need to remove them in the line below where you do “tileMap.getIndex”)

You don’t need to divide through the tile width and height, since in the XML file the x and y positions are already an index value (e.g. your have grid coordinates instead of actualy screen coordinates, that’s the difference between the ".oel"s you mentioned).

I hope this helps, sorry if it didn’t.

(btw: Hey everyone! Glad to see a new forum up and running again)


(Alex Larioza) #5

Your Ogmo file is using tile positions (row, column) rather than coordinate positions (x,y). So you don’t need to divide the positions by the tile width/height:

tileMap.setTile(tile.@x, tile.@y, tileMap.getIndex(tile.@tx / TILE_WIDTH, tile.@ty / TILE_HEIGHT));

I’d also change the export mode of the tile layer to IDs as its easier to deal with. You can do so by going to Project > Edit Project then on the Layers tab, change Export Mode to XML (IDs). Then you can do the following:

 tileMap.setTile(tile.@x, tile.@y, tile.@id);

EDIT: @VoEC beat me to it!


(Tareq) #6

FANTASTIC! Mostly because I removed the division by TILE_WIDTH/HEIGHT before I came here, thought what would happen if I did xD

Thank you guys.

But another problem >.<

The House isn’t being placed in the right place. My code is exactly the same as the one in the tutorial:

package entities 

{ import flash.geom.Point; import net.flashpunk.Entity; import net.flashpunk.graphics.*;

public class House extends Entity
{
	private const HOUSE_WIDTH:int = 48;
	private const HOUSE_HEIGHT:int = 48;
	
	[Embed(source = "../assets/gfx/house.png")] // Need an image of house to later populate an array
	private const HOUSE: Class;
	
	//Used to store the house's index within the houses[] array
	// which will ne in the Game class
	public var index; int;
	
	public function House(_index:int, position:Point) 
	{
		//label for collision detection for house
		type = "house";
		
		// initialising the position and index parameters
		index = _index;
		x = position.x;
		y = position.y;
		
		 
		// setting the graphics property for the Entity super class
		graphic = new Image(HOUSE);
		
		// Define the collision boundaries of the image
		setHitbox(HOUSE_WIDTH, HOUSE_HEIGHT);
	}
	
}

I’m going to try to do that for-loop that’s in for Ground and Trees to see if it works. will be back in a moment

edit: Nope that didn’t work. I think it has something to do with that how I’m trying to make an instance of it, maybe I’m giving in the coordinates wrong…

EDIT AGAIN: I’ve noticed that the tutorial has IDs, so I’m exporting the house layer to XML ID. However, in doing so the coordinates doesn’t seem right; hxxp://pastebin.com/E5hUTvBX

compared to the tutorials: http://pastebin.com/XPqKu6C1

Why is it that my coordinates are so small when my house is placed pretty far down? I’d assume it’s placing it as if it was the column and row but, why is it doing this?


(Alex Larioza) #7

Can you post the code where you are adding the house to the world?


(Tareq) #8
// new packages are to be place in a subfolder with the same name
// which will then be accessed from Main.as via "Import" statement

package worlds
{
import entities.Player;
import entities.Ground;
import entities.Trees;
import entities.House;

import flash.geom.Point;
import net.flashpunk.World;
import flash.utils.ByteArray;

public class Game extends World
{
	// embed the map and store in variable
	[Embed(source = "../assets/maps/outdoors_map_01.oel", mimeType = "application/octet-stream")]
	private static const OUTDOORS_MAP_01: Class;
	
	public var player:Player
	public var ground:Ground;
	public var trees:Trees;
	public var houses:Array = new Array();
	
	public function Game()
	{
		//Create player instance and set to (10,10)
		player = new Player(new Point(10, 10));
		
		// Call function that loads the map
		loadMap();
	}
	
	// Objective: Instantiate all Entities and add them in order
	public function loadMap():void 
	{
		// helper variables
		var o:XML; // used for loop
		var i:int; // used for loop
		
		//Obtain an XML Instance[Embed(source="../assets/maps/outdoors_map_01.oel", mimeType="application/octet-stream")]
		var bytes:ByteArray = new OUTDOORS_MAP_01;
		var xml:XML = new XML(bytes.readUTFBytes(bytes.length)); // Used to parse byte array from OUTDOORS_MAP_01
		
		//Build tilemap
		ground = new Ground(xml);
		add(ground);
		
		//load player
		add(player);
		
		// Load trees
		trees = new Trees(xml)
		add(trees);
		
		// Load houses
		
		if (xml.houses) //If there is a xml tag called houses
		{
			i = 0
			for each (o in xml.houses.tile)
			{
				var house:House = new House(i, new Point(o.@x, o.@y), xml);
				houses.push(house);
				add(house);
				i++;
			}
		}
		
	}
	
}

It’s the for loop at the end


The House class:

package entities 
{
import flash.geom.Point;
import net.flashpunk.Entity;
import net.flashpunk.graphics.*;

public class House extends Entity
{
	private const HOUSE_WIDTH:int = 48;
	private const HOUSE_HEIGHT:int = 48;
	
	[Embed(source = "../assets/gfx/house.png")] // Need an image of house to later populate an array
	private const HOUSE: Class;
	
	//Used to store the house's index within the houses[] array
	// which will ne in the Game class
	public var index; int;
	
	public function House(_index:int, position:Point, map:XML) 
	{
		//label for collision detection for house
		type = "house";
		
		// initialising the position and index parameters
		index = _index;
		x = position.x;
		y = position.y;
		
		// setting the graphics property for the Entity super class
		graphic = new Image(HOUSE);
		
		// Define the collision boundaries of the image
		setHitbox(HOUSE_WIDTH, HOUSE_HEIGHT);
	}
	
}

}


(Nicole Brauer) #9

Yes, that is correct. What you have in your xml is the column and row of the house, not the x and y value.

So in order to have the house at the correct position either export the house layer to XML not as id but as coordinates (Co-ords) (Like in the tutorial’s oel file).

Or you can do this:

x = position.x * [YOUR_TILE_WIDTH];
y = position.y * [YOUR_TILE_HEIGHT];

(Should be both 48?)

This would scale the row/column coordinate back up to a screen coordinate that an entity can use.


(Tareq) #10

:smiley: Thank you! Thank you! Thank you! Thank you! (better stop before I get reported for spamming).

Although, I’m still confused to why I have to multiply it whereas the tutorial got away with it otherwise :s Nonetheless that worked, I hope the next few won’t be as tricky


(Nicole Brauer) #11

No problem : )

It worked in the tutorial because they exportet their XML values as coordinates (The actual position of a tile/entity on the screen) instead of ids (The row and column of the tile/entity on the tilemap grid) like you did.

You can change the way your XML vaules export like @SHiLLySiT explained:

Project > Edit Project then on the Layers tab, change Export Mode to XML (IDs) / XML (Co-ords).


(Alex Larioza) #12

@VoEC Just to add: I generally have tile layers export as columns/rows and entity layers export as x/y. Makes more sense that way when you go to parse the .oel files.