Our flash game designer tools let you create your own online game in a flash!    TEST IT…

The PBE Resource Provider Model explained

As of r485 the Pushbutton Game Engine (PBE) has implemented a Resource Provider Model to handle the loading and creating of resources. This gives us some nice possibilities like loading resources ourselves or generating our resources in memory.

This post will explain about the Resource Provider Model and will show how we can create our own resource provider by implementing the IResourceProvider interface.

We will create a resource provider that will create resources ‘on the fly’ as they are requested by the ResourceManager.

We will also create a resource provider by subclassing the ResourceProviderBase and we will ‘fill’ that ResourceProvider with some dynamicly generated graphics.

See this tutorial in action
Download the sources of this tutorial

1. The Resource Provider Model

With the resource provider model implemented, the ResourceManager can have access to multiple resource providers. These resource providers are classes that implement the IResourceProvider interface and are registered with the ResourceManager using the function ResourceManager. registerResourceProvider(..).

When a resource is requested by the engine using the function ResourceManager. instance.load(..) , the ResourceManager checks with each provider if it can provide the requested resource. If a resource provider can provide the resource the ResourceManager will request that resource from the provider and caches this resource for future retrieval.

Before we had this Resource Provider Model, a Resource object had to ‘load’ itself when requested. With the Resource Provider Model implemented, the providers themselves are responsible for ‘loading’ or ‘creating’ the resources. This loading/creating can take place at the start of the game, as requested or any time really …

By implementing de IResourceProvider interface we can write our own classes that can provide resources to the ResourceManager. We could render these resources in memory, or load them from disk ourselves.

2. The Resource Provider Classes

You will find the resource provider classes in the library :

src\com\pblabs\engine\resource\provider

  • IResourceProvider
    This interface has to be implemented by a class so it can act as a resource provider.

  • ResourceProviderBase
    This class can be subclassed to create your own resource provider class

  • BulkLoaderResourceProvider
    This class can be subclassed or used to load resources. It uses BulkLoader to load resourcs. Multi phase loading is supported.
    ( this will be explained in another blog post )

  • EmbeddedResourceProvider
    This (singleton) class is used internally to provide the embedded resources that were specified using the ResourceBundle class or ResourceBinding class

  • FallbackResourceProvider
    This (singleton) class is used internally to act as a resource loader fallback if no resource provider can provide a requested resource. It uses BulkLoader to load the requested resource

3. The IResourceProvider interface

    public interface IResourceProvider
    {
        /**
         * This method is called when the ResourceManager gets a load request
         * for a resource and will check all known ResourceProviders if it has
         * the specific resource
         */
        function isResourceKnown(uri:String, type:Class):Boolean;

        /**
         * This method is called when the ResourceManager requests a known
         * resource from a ResourceProvider
         */
        function getResource(uri:String, type:Class, forceReload:Boolean = false):Resource;
    }

The function isResourceKnown(uri:String, type:Class):Boolean will return a value of true if the resource provider has access to the requested resource with the specific uri and of that specific type.

The uri:String is usally the url or filename of the resource but could also be some internal format you choose yourself when you are generating your resources in memory.

The type:Class can by any of the Resource Class types like : ImageResource, XMLResource, SWFResource, MP3Resource and DataResource

The function getResource( uri : String, type : Class, forceReload : Boolean = false ) :Resource; will provide the requested resource.

4. Implementing the IResourceProvider interface

See this tutorial in action
Download the sources of this tutorial

In the code sample with this tutorial I implemented the IResourceProvider interface on my main application class so that the main application becomes a resource provider as well.

   [SWF(width="400", height="400", frameRate="32")]
   public class SampleDynamicResourceProvider extends Sprite implements IResourceProvider
   {
       ...
   }

I register this resource provider with the ResourceManager in the application class constructor , after I have initialized the PBEngine using the function Global.startup(this)

      public function SampleDynamicResourceProvider()
      {
         // Start up PBE
         Global.startup(this);
         // register our Dynamic Resource Provider
         ResourceManager.instance.registerResourceProvider(this);
         ...
      }

Our dynamic (render on the fly) resource provider will catch all resources of the ImageResource type that are requested using the format ‘@circle(width,height,color)’.

   	  public function isResourceKnown(uri:String, type:Class):Boolean
   	  {
   	  	// capture only @circle(..) resource source requests
		if (uri.toLowerCase().indexOf("@circle(")==0)
		  return true;

		// otherwise we dont know the requested resource
		return false;
   	  }

It will create the ImageResource by rendering a Bitmap with the specified width and height drawing a coloured circle on it. It will create this resource as it is requested (on the fly) by the ResourceManager.

   	  public function getResource(uri:String, type:Class, forceReload:Boolean = false):Resource
   	  {
   	  	// split the params of the '@circle(params)' source to an params:Array
	 	var sparams:String = uri.split("(")[1];
	 	sparams = sparams.split(")")[0];
	 	var params:Array = sparams.split(",");

	 	// convert params to the right types
	 	var width:int = int(params[0]);
	 	var height:int = int(params[1]);
	 	var color:uint = uint(params[2]);

	 	// create a Sprite object
	 	var sprite:Sprite = new Sprite();

	 	// draw a filled circle with a thick black line
	 	sprite.graphics.beginFill(color,1);
	 	sprite.graphics.lineStyle(2,0x000000);
	 	sprite.graphics.drawCircle(width/2,height/2,(width/2)-2);
	 	sprite.graphics.endFill();

	 	// draw this sprite onto a BitmapData object
	 	var bitmapData:BitmapData = new BitmapData(width,height,true,0);
	 	bitmapData.draw(sprite);

	 	// create an ImageResource
	 	var resource:ImageResource = new ImageResource();

	 	// set the image resource filename
	 	resource.filename = uri;

	 	// initialize this ImageResource using the BitmapData object
	 	resource.initialize(new Bitmap(bitmapData));

	 	// return the resource to the ResourceManager
	 	return resource;
   	  }

We can now create sprite entities that use SpriteRenderComponent where this @circle(..) will be provided as the loadFromImage property.

         createSprite(0,0,"@circle(75,75,0x00cc00)");
         createSprite(-20,-20,"@circle(35,35,0x0000cc)");
         createSprite(20,20,"@circle(50,50,0xcc0000)");

5. Subclassing the ResourceProviderBase

See this tutorial in action
Download the sources of this tutorial

The ResourceProviderBase is a nice class we can derrive from to render or load resources ‘on beforehand’ and store them so that the ResourceManager can access them using this resource provider.

When we create this Resource Provider class in our application’s constructor, the resources are created and stored within the resource provider.

      public function SampleDynamicResourceProvider()
      {
         // Start up PBE
         Global.startup(this);                                                

         // register our Dynamic Resource Provider
         ResourceManager.instance.registerResourceProvider(this);

         // create our SampleResourceProvider
         new SampleResourceProvider();
         ...
       }

If we subclass the ResourceProviderBase and call the super(); from within our constructor, the provider is auto-registered with the ResourceManager.

	public class SampleResourceProvider extends ResourceProviderBase
	{
		public function SampleResourceProvider()
		{
			// call the constructor of the ResourceProviderBase so this
			// provider is registered with the ResourceManager
			super();

			// create the resources of this resource provider
			createResources();
		}
                 ...
             }

Using the function addResource(src:String, type:Class, resource:Resource) we can add our own resources to this resource provider and the ResourceManager has access to them.

		/**
		 * This method will create a resource and add it to this
		 * ResourceProvider
		 */
		private function createResource(src:String ,color:uint):void
		{
		 	// create a Sprite object
		 	var sprite:Sprite = new Sprite();

		 	// draw a filled circle with a thick black line
		 	sprite.graphics.beginFill(color,1);
		 	sprite.graphics.lineStyle(2,0x000000);
		 	sprite.graphics.drawRect(0,0,150,150);
		 	sprite.graphics.endFill();

		 	// draw this sprite onto a BitmapData object
		 	var bitmapData:BitmapData = new BitmapData(150,150,true,0);
		 	bitmapData.draw(sprite);

		 	// create an ImageResource
		 	var resource:ImageResource = new ImageResource();

		 	// set the image resource filename
		 	resource.filename = src;

		 	// initialize this ImageResource using the BitmapData object
		 	resource.initialize(new Bitmap(bitmapData));

		 	// add the resource to this ResourceProvider
		 	addResource(src, ImageResource, resource);		 		 			 	 		 	 	

		}

		/**
		 * This method will create all resources this
		 * resource provider 'knows'
		 */
		private function createResources():void
		{
			createResource("yellow",0xffff00);
			createResource("blue",0x0000ff);
			createResource("white",0xffffff);
			createResource("green",0x00ff00);
			createResource("red",0xff0000);
		}		

	}

We can request the colored rectangles ‘yellow, blue, white, green and red’ using this resource provider.

         createSprite(-100,-100,"blue");
         createSprite(100,100,"red");
         createSprite(100,-100,"green");
         createSprite(-100,100,"yellow");
         createSprite(0,0,"white");

See this tutorial in action
Download the sources of this tutorial

Tags: ,

2 Responses to “The PBE Resource Provider Model explained”

  1. Ben Garney says:

    Great writeup, Martijn!

  2. Shiki says:

    Nice post! I could definitely make use of the IResourceProvider. Thanks for this very nice explanation.

Leave a Reply

Spam Protection by WP-SpamFree