Quick Start: Part 2

Include tags

Although at the moment you’ve only got a single resource, eventually you’re going to have lots of different resources. Keeping them within one file can be messy, so it’s often best to split them into different files. To include one resource file from another, use the ‘include’ tag:

 
<resources>
  <include path="tanks.xml" />
</resources>

Remember that the ‘tanks.xml’ file should also have a top-level tag.

Parent resources

Often in games we want to define a basic enemy (or item, or behaviour, etc.) and have several variants of this with minor tweeks. Parent resources mean you don’t have to duplicate the common values between these resources. For example, if we had a basic tank:

 
class Tank extends AutoResource
{
  float moveSpeed;
  float rotateSpeed;
  float health;
  float damage;
  String image;
}

We can define a base tank and several variants on it:

 
  <TankTemplate name="basic.tank"
    moveSpeed="3.0"
    turnSpeed="2.0"
    health="100"
    damage="10"
    image="basicTank.png"
  />
 
  <TankTemplate name="fast.tank" parent="basic.tank"
    moveSpeed="10"
    image="fastTank.png"
  />
 
  <TankTemplate name="heavy.tank" parent="basic.tank"
    health="200"
    damage="30"
    image="heavyTank.png"
  />

Parent resources must be defined before they are referenced in a child resource. For best results they should be in the same file as all child resources (so that parent and children get reparsed at the same time).

Decoders

Writing your own resource types is great, but sometimes you want to use a 3rd party type (such as java.awt.Point) which you can’t modify yourself. Instead you can write a decoder to add Point support.

Decoders are classes with a static ‘decode’ method which accepts a String (or xml Element) and returns the decoded object:

 
// Xml attribute decoder
public static Type decode(String str)
 
// Xml element decoder
public static Point decode(org.w3c.dom.Element e)

‘Type’ is not a generic parameter but the concrete type you wish to decode. A simple java.awt.Point decoder would look like this:

 
package yourgame;
 
import java.awt.Point;
 
public class PointDecoder
{
	/** Decodes xml attributes into java.awt.Point objects of the form "(x, y)"
	 *  eg. <ResourceType name="bob" position="(10, 20)" />
	 */
	public static Point decode(String str)
	{
		str = str.trim();
 
		if (str.charAt(0) != '(')
			return null;
 
		if (str.charAt(str.length()-1) != ')')
			return null;
 
		str = str.substring(1, str.length()-1);
 
		String[] t = str.split(",");
		if (t.length == 2)
		{
			int x = Integer.parseInt(t[0].trim());
			int y = Integer.parseInt(t[1].trim());
 
			return new Point(x, y);
		}
		else
			return null;
	}
}

Once you’ve written your decoder, you need to register it in your resources xml with the ‘decoder’ tag:

 
  <decoder class="yourgame.PointDecoder" />

Element decoders work the same way, except that they accept an ‘Element’ argument, and the syntax to use them in a resource is different:

 
  <ResourceType name="bob">
    <bounds> <!-- member variable name -->
      <Rectangle x="1" y="2" width="3" height="4" />  <!-- Element to decode -->
    </bounds>
  </ResourceType>

Background Loading

So far we’ve used ResourcePool.parse() and ResourceHandle.forceCreate(), which will work just fine but are blocking calls and do all of their work in the main thread. For non-blocking behaviour (for example, to display an animation while loading) usage is slightly different.

Instead of ResourcePool.parse(), use ResourcePool.backgroundParse to parse in a background thread:

 
ResourcePool resources; = Resources.createPool("Data", Resources.DecoderGroup.CORE, true);
resources.backgroundParse("resources.xml");

ResourceHandle.forceCreate forces a resource to be fully created straight away, however if it is not currently created this will block as any remaining creation is done. Instead you can request a resource be created in a background thread with ResourcePool.requestCreate():

 
  // At init
  ResourceHandle<TankTemplate> tankHandle;
  tankHandle = resources.requestCreate(TankTemplate.class, "player.tank");
 
  // Every frame
  if (tankHandle.getState() == ResourceHandle.State.CREATED)
    System.out.println("player.tank ready for use");

One method is to requestCreate() all resources required for the next stage/map, and show a loading screen until they all report that they are fully created before continuing.