In this tutorial we create a simple PushButton application.
To start things off we have a fairly standard MXML file, with a function called appComplete that is set to be called on startup. Before we do anything with Pushbutton we need to call the Global startup function.
protected function appComplete():void
{
Global.startup(this);
Now we need to create some entities that will allow us to display something on the screen.
With the more traditional inheritance design pattern these entities would be additional classes that extend some base class supplied by the engine to implement specific functionality. PushButton is a little different. Instead of creating a new class, an object that implements the IEntity interface is created by the engine, and components that implement specific functionality (like say the ability to draw something to the screen) are then added to entity.
You can think of inheritance as a stack of blocks, where each class adds a new block to the stack to add functionality. Composition can be thought of as an empty box, where each component being contained by the box adds some functionality.
So the big question is where do you place the code that creates the entity and then adds the components? It would be possible to create a new class and add this creation code to the constructor, but the whole notion of classes becomes irrelevant in a composition based system. In fact when you start loading entities from XML files (which will be shown in later tutorials) these classes would be discarded anyway. Instead we will place the code to create the entities in static functions in a class called EntityFactory.
For this minimal demo we need to create two entities. The first is a “Scene” entity that contains the managers required to place and draw other entities.
EntityFactory.createScene("scene");
The second is a “Player” entity, which for now just displays a dot on the screen.
EntityFactory.createPlayer("player", "scene");
}
As was mentioned earlier the EntityFactory is a class that contains static functions, each of which composes various entities.
package
{
import mx.core.*;
import com.pblabs.engine.core.*;
import com.pblabs.engine.entity.*;
import com.pblabs.rendering2D.*;
import com.pblabs.rendering2D.ui.*;
import flash.geom.Point;
public class EntityFactory
{
static protected const SCENE_SPATIAL_COMPONENT:String = "Spatial";
static protected const SCENE_RENDERER_COMPONENT:String = "Renderer";
The “Scene” entity composes an entity that includes the manager objects (i.e. those objects that need to be created once in an application) that are required to place and draw other entities. Let’s break down how an entity is composed.
First we need to create the entity object itself. This is the empty box into which additional components will be placed. The allocateEntity function is a global function in the com.pblabs.engine.core package.
static public function createScene(name:String):IEntity
{
var Scene:IEntity = allocateEntity();
Each entity needs to be initialised immediately after it is created. We supply a name that identifies this object within the PushButton system.
Scene.initialize(name);
Into this entity we place a BasicSpatialManager2D component. This component will be responsible for keep track of where everything is in the workld.
var Spatial:BasicSpatialManager2D = new BasicSpatialManager2D(); Scene.addComponent( Spatial, SCENE_SPATIAL_COMPONENT );
Next we create a Scene2DComponent component, which is a renderer that is responsible for drawing other entities to the screen.
var Renderer:Scene2DComponent = new Scene2DComponent();
The renderer needs to know where the entities have been placed – i.e. it needs have a reference to the spatial database component we created earlier.
Renderer.spatialDatabase = Spatial;
The renderer also needs a view to render the scene into. For this we created a SceneView object, which is used as the canvas to draw the objects that make up the scene.
var View:SceneView = new SceneView(); View.width = Application.application.width; View.height = Application.application.height; Renderer.sceneView = View;
The position that defines the centre of the world is defined. For most cases the origin [0,0] is makes the sense as the centre of the world.
Renderer.position = new Point(0,0);
It does not make sense to try and draw every entity to the scene. In fact this scene object itself is an example of an object that has no visual representation, and so it should not be drawn. In order to determine which objects should be drawn and which should not a mask is used. Here we specify that only those entities that identify themselves as “Renderable” objects will be drawn to the screen.
Renderer.renderMask = new ObjectType("Renderable");
Finally we add the renderer component to the entity, and return the fully composed entity back to the caller.
Scene.addComponent( Renderer, SCENE_RENDERER_COMPONENT ); return Scene; }
Creating the “Player” entity follows much the same process.
First we create and initialise the empty entity.
static public function createPlayer(name:String, scene:String):IEntity
{
var entity:IEntity = allocateEntity();
entity.initialize(name);
Next we create a SimpleSpatialComponent component, which will define how our entity is positioned in the world.
var Spatial:SimpleSpatialComponent = new SimpleSpatialComponent();
The purpose of the BasicSpatialManager2D component we added to the scene entity is to keep a track of all the spatial entities added to the scene. To make this spatial entity known to the BasicSpatialManager2D component we need to get a reference to the scene object and to the BasicSpatialManager2D component it contains.
In my opinion this is where the composition design breaks down a little. To get access to this component need two strings: the name of the entity and the name of the component held by the entity that we want to access. Accessing any object by a string introduces an opportunity for an error (like a simple misspelling) that can only be picked up by debugging the application at runtime instead of having the error picked up by the compiler. In this example we have limited this error by using constant string variables, but this option is not available when creating entities from an XML object.
That said it is not a huge deal, and in fact deserialising any object tree from a source like an XML file requires referencing objects by a string or some other id (regardless of the underlying design pattern used), but just be aware that if you mistype the name of an entity or the name of a component it holds you are not going to be warned about it at compile time.
So, here we get access to the BasicSpatialManager2D component held by the scene entity and assign it to the spatialManager property.
Spatial.spatialManager = NameManager.instance.lookupComponentByName(scene, SCENE_SPATIAL_COMPONENT) as ISpatialManager2D;
Next we define the spatial component to be “Renderable” (meaning it will be drawn by the scene), set it position and then its size.
Spatial.objectMask = new ObjectType("Renderable");
Spatial.position = new Point(0,0);
Spatial.size = new Point(50,50);
We then add the component to the player entity.
entity.addComponent( Spatial, "Spatial" );
The entity now has a position in space, but to be drawn it also needs a component that will draw something. For this we create a new SimpleShapeRenderComponent component.
var Render:SimpleShapeRenderComponent = new SimpleShapeRenderComponent();
In order to see something on the screen we will ask the SimpleShapeRenderComponent to drawn a circle.
Render.showCircle = true; Render.radius = 25;
The SimpleShapeRenderComponent needs to know where to draw the circle. The position of the entity (and therefore the position where we want to draw the circle) is held by the SimpleSpatialComponent component. Again we reference this component by a string.
Render.positionReference = new PropertyReference("@Spatial.position");
Finally we add the SimpleShapeRenderComponent to the entity, and return the fully composed entity back to the caller.
entity.addComponent( Render, "Render" ); return entity; } } }
This demo should give you a good idea of how PushButton uses composition to build entities using individual components to add specific functionality. We have touched on some of the basic positing and rendering components, but the real power in PushButton comes from creating your own components, which we will look at in the next tutorial.
Tracing the roots of computer programming or coding...
The title of this article for technical reasons can not contain the # sign. The correct name sh...
C++ is an object-oriented programming language developed by Bjarne Stroustrup......
We know there are lots of languages available at present like Visual Basic, Visual Basic.net an...
Idea a strange thing to get, but is very difficult to implement...
In this tutorial we add mouse interactivity to the scene....
In this tutorial we allow the view of the isometric scene to be moved with the mouse....
In this tutorial we show the height of an isometric object by adding a shadow....
In this tutorial we modify the appearance of the isometric cube at runtime....
In this tutorial we add some animated isometric boxes to the scene....