Actors – Sprites with Brains

Introduction

Going back to comparison in the scenes introduction section, actors play a pivotal role in our scenes, each actor having its own unique role and visual appearance. Actors are the building block of the game (game objects), they provide the actual unique functionality and visuals that make up the game as a whole, rather like each actor plays his / her role in a movie.

They can provide any type of functionality from a simple bullet fleeting across the screen to something as complex as a dynamic machine that modifies its behaviour and appearance based upon data streamed from a web server.

An Actor represents a game object that can be added to Scenes for processing and display. You can add logic to the actor via its update() method and or by attaching an onTick event handler. The base Actor has the following features:

Creating Actors

Actors are created by creating an instance of a b5.Actor object or any of the actor types mentioned above then adding that instance to a Scene or another Actor. Lets take a quick look at an example:

1

2

varactor=newb5.Actor();// Create instance of Actor

scene.addActor(actor);// Add actor to scene to be processed and drawn

Of course this actor will do absolutely nothing as it has no visual component assigned. Lets take a look at how to create actors of different types.

Creating an Arc Actor

An arc actor represents a circular shaped game object, an example showing how to create one is shown below:

1

2

3

4

5

6

7

8

9

varactor=newb5.ArcActor();// Create instance

actor.x=100;// Set x axis position

actor.y=0;// Set x axis position

actor.fill_style="#00ffff";// Set fill style

actor.start_angle=0;// Set start angle

actor.end_angle=2*Math.PI;// Set end angle

actor.radius=50;// Set radius

actor.filled=true;// Set filled

scene.addActor(actor);// Add actor to scene to be processed and drawn

In the above code we first of all create an instance of ArcActor, set some values to the actor such as position, size, start and end radius etc.. then we add it to the scene to be processed.

Creating a Rectangular Actor

A rectangular actor represents a rectangular shaped game object, an example showing how to create one is shown below:

1

2

3

4

5

6

7

varactor=newb5.RectActor();// Create instance

actor.fill_style="#40ff4f";// Set fill style

actor.filled=true;// Set filled

actor.w=100;// Set drawn width

actor.h=100;// Set drawn height

actor.corner_radius=10;// Set corner radius (this is a rounded ract)

scene.addActor(actor);// Add actor to scene for processing and drawing

Creating a Label Actor

A label actor represents a game object that displays a string of text, an example showing how to create one is shown below:

1

2

3

4

5

6

7

varactor=newb5.LabelActor();

actor.font="16pt Calibri";// Set font

actor.text_align="center";// Set horizontal alignment

actor.text_baseline="middle";// Set vertical alignment

actor.fill_style="#ffffff";// Set fill style

actor.text="Hello World";// Set some text

scene.addActor(actor);// Add to scene for processing and drawing

Creating a Polygon Actor

A polygon actor represents a game object that displays a shape, an example showing how to create one is shown below:

1

2

3

4

5

6

varactor=newb5.PolygonActor();

actor.name="polygon1";// Set actors name

actor.points=[0,-50,50,50,-50,50];// Set shape

actor.fill_style="#804fff";// Set fill style

actor.filled=true;// Set filled

scene.addActor(actor);// Add to scene for processing and drawing

Creating a Bitmap Actor

Lets take a look at creating a slightly more complex actor, one with a bitmap attached:

1

2

3

4

5

6

7

8

9

// Create an actor

varactor=newb5.Actor();

actor.x=100;

actor.y=100;

actor.w=200;

actor.h=200;

scene.addActor(actor);// Add to scene

// Create and attach a bitmap

act.bitmap=newb5.Bitmap("background","images/background.jpg",true);

Whilst in the above example we create a bitmap and assign it to the actor directly, its better practice to create the bitmap then add it to either the scenes resources or apps global resources so that it may be managed and re-used.

Creating a Tile Map Actor

A tilemap actor represents a game object that displays an object that is built up out of tiles, an example showing how to create one is shown below:

1

2

3

4

5

6

7

8

9

10

varmap=newb5.MapActor();// Create instance of actor

map.map_width=100;// Set map width in cells

map.map_height=100;// Set map height in cells

map.display_width=16;// Set how many cells to display on x axis

map.display_height=16;// Set how many cells to display on y axis

map.generateTiles(32,64,64,256);// Generate the tile set

map.bitmap=newb5.Bitmap("tiles","testmap.png",true);// Set tile set bitmap

Actors can be destroyed by calling their b5.Actor.destroy() method, this will remove them from their scene and destroy all physics joints, fixtures and so forth that are attached to them. You can also destroy and actor by calling Scene.removeActor().

Note that when an actor is created its onCreate() method will be called to allow any post creation tasks to be carried out (Booty5 game editor only). When an actor is destroyed its onDestroy() method will be called so that any pre destruction tasks can be carried out.

You can see an example of the creation of different types of actors in the shapes demo.

Processing and Visibility

Actors are processed when they are part of a scene or some other actor and their active property is set to true, if marked as not active then it and all of its child actors will not be updated. It can be a good idea to deactivate actors when they are not in use, especially if you have a large number of them within a scene.

Actors are rendered when their visible property is set to true. If marked as not visible then the actor and all of its children will not be rendered.

Note that each time the actor is updated (each game frame and as long as it is active) its onTick() method will be called, e.g.:

1

2

3

actor,oTick=function(dt){

// Do something (dt is time passed since last updated)

};

Its generally here where you will add your actor logic to give your actor its unique functionality, unless of course you plan on deriving your own actor type from one of the existing types and implementing the update() method.

Transforms

All actor types have various properties that can be modified to change the position, rotation and scale of the actor and all of its children. These properties are listed below

x – X position in scene

y – Y position in scene

ox – X origin

oy – Y origin

absolute_origin – If true then ox and oy are taken as absolute coordinates, if false then ox and oy are taken as percentage of width and height

rotation – Rotation in radians

scale_x – X scale

scale_y – Y scale

depth – Z depth (3D depth), 0 represents no depth

An actors internal visual transform will only be re-calculated when properties such as position, scale and rotation changes, this is an optimisation to cut down on unnecessary processing. Changing these properties after actor creation should be done via the associated propertiy setters such as _x, _y (see Actor Setters for a full list).to ensure that the internal transform is updated. Alternatively you can set b5.Actor.transform_dirty to true to force the internal transform to be updated. Note that when an actors transform is dirtied, all of its children’s transforms will also be dirtied.

Note that when setting an actors origin, there are two ways in which the origin properties can be interpreted. If absolute_origin is set to true then the origin will be taken as absolute coordinates. if however it is set to false then the coordinates will be taken as percentage of actor width and height values, so for example an ox value of 0.5 and an actor width of 100 will result in a final x origin value of 50.

Child Hierarchies

Its often very useful when creating game objects to build them out of parts, for example, in the Leapo game, the frog player is built up out of multiple parts. We have the frogs main body, which has a head attached, the head also has two eyes attached to it. This enables me to change the head independent of the body and the eyes independent of the head. However, if the head rotates then I want the eyes to rotate with it. The hierarchical system ensures that changes to the parent are propagated to its children, ensuring children obey the same transforms and opacity settings as their parent.

Each actor maintains its own list of children. To make an actor a child of another, simply call parent_actor.addActor(child). This will add the child to the parents hierarchy, e.g.:

1

2

3

4

varactor1=newb5.Actor();

varactor2=newb5.Actor();

actor1.addActor(actor2);

scene.addActor(actor1);

To remove a child from the parent simply call child.parent.removeActor(child).

To search an hierarchy for an actor call parent.findActor(“actors name”, recursive). Note that if recursive is true then the entire actor hierarchy will be searched for the named actor.

Child and Self Clipping

An actor can clip its children as well as itself against its extents or a supplied clip shape. To enable clipping of children set b5.Actor.clip_children to true. To enable clipping against itself set b5.Actor.self_clip to true. Without a clip shape defined the actor will be clipped against the natural shape of the actor, for example if the actor is an ArcActor then the clipping region will be the circle area that is generated by the actor. For rectangular clipping regions a clip margin (defined by b5.Actor.clip_margin which is an array of left,top,right, bottom) can be used to shrink or expand the clipping region. If a clipping shape is defined (b5.Actor.clip_shape) then the supplied shape will be used to clip. Note that clipping can be slow on some devices, so you use it sparingly and should test thoroughly.

Lets take a look at how to set up an actor that clips its children:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

// Create an actor that will clip its children

varactor=newb5.ArcActor();

actor.fill_style="#000000";

actor.radius=50;

actor.filled=true;

actor.clip_children=true;

scene.addActor(actor);

// Create a child actor that will be clipped by its parent

varlabel=newb5.LabelActor();

label.font="30pt Calibri";

label.fill_style="#ffffff";

label.text="Hello World";

actor.addActor(label);

In the above example we create a circle actor that contains text reading “Hello World”. Note how the text is clipped against the circle extents of the parent actor.

Now lets take a look at a self clipping example:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

// Create a clip shape

varshape=newb5.Shape();

shape.type=b5.Shape.TypePolygon;

shape.vertices=[0,-20,20,20,-20,20];

// Create an actor that will clip against the clip shape

varactor=newb5.RectActor();

actor.fill_style="#000000";

actor.w=100;

actor.h=100;

actor.filled=true;

actor.self_clip=true;

actor.clip_shape=shape;

scene.addActor(actor);

In the above example we create a triangular polygon shape then create a rectangular actor and assign it is the clipping shape, we also mark the actor as self clipping which clips the actor against its own clip shape.

Layering

As with scenes, actors can also be visually sorted using layers. Each game object has its own layer number, actors on the same layer will be rendered in the order in which they were created. Actors are sorted local to their parent, so all actors that have the scene as a parent are sorted against each other, whilst all actors in a child tree will be sorted against other actors on the same tree level.

Note that you should always set the layer via the Actor._layer property setter to ensure that layers get re-sorted. A good example of dynamically sorted actors can be seen in the

Opacity

Actors have an opacity level (b5.Actor.opacity) that ranges from 0 and 1 which determines how opaque / transparent it its child actors are. Child actors can opt to not be affected by their parents opacity by setting b5.Actor.use_parent_opacity to false.

Note that within the game editor the opacity values ranges from 0 to 255, instead of 0 to 1 and is the 4th parameter of the actors Colour and Selected Colour property.

Filling and Outlines

All shape and text based actors can be rendered as filled or outlined. You can change the filled state of an actor by setting its filled property to true for filled or false for outlined.

Filled actors will use the fill_style property to decide how to render the fill style. Outlined actors will use the stroke_style property to decide how to render the outline. A stoke_thickness can also be specified that specifies how thick to render the outline.

A good example of filled and outlined shapes can be seen in the shapes demo.

Docking

Its often useful to be able to arrange parts of a games user interface around the edges of a scene to ensure that they are positioned consistently across different sized displays. Booty5 enables this using docking.

Docking allows you to dock actors to the edges of a scene so that regardless of how the scene is scaled, docked actors will remain where you expect them to be.

You can dock an actor on the x and y axis by setting its b5.Actor.dock_x and b5.Actor.dock_y property to one of the following:

b5.Actor.Dock_None

b5.Actor.Dock_Top

b5.Actor.Dock_Bottom

b5.Actor.Dock_Left

b5.Actor.Dock_Right

When an actor is docked it can be adjusted using a margin. b5.Actor.margin specifies an array of margin values (left, right, top, bottom).

In addition to docking against the scene, actors can be docked against the edges of parent actors that are marked as using a virtual canvas. Note that the virtual actor must be a child of the parent for it to dock.

Lets take a quick look at an example that shows how to dock an actor to the top of the scene:

1

2

3

4

5

6

7

8

9

// Create an actor that is docked against top of scene

varactor=newb5.RectActor();

actor.fill_style="#0000ff";

actor.w=100;

actor.h=100;

actor.filled=true;

actor.dock_y=1;

actor.margin=[0,0,20,0];

scene.addActor(actor);

Bitmap Animation

Actors can display animating bitmaps out of the box. Animation is achieved by displaying different rectangular areas of a larger image, this image is often called an image atlas (see ImageAtalas).An ImageAtlas is basically a sprite atlas (or sprite sheet) which is a large image that contains multiple sub images. Each sub image can be identified using a rectangular area to specify where it is located in the larger main image. Bitmap animation is achieved by displaying different areas of the main sprite atlas over time, changing the area of the bitmap that is shown.

Lets take a look at how to create a game object that shows a bitmap animation:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

// Create an actor

varactor=newb5.Actor();

actor.x=100;

actor.y=100;

actor.w=200;

actor.h=200;

scene.addActor(actor);// Add to scene

// Create an image atlas from a bitmap image ten assign as the actors atlas

Adding Physics

All actors of all types can be easily turned into physics objects. To turn an actor into one that supports physics you can need to initialise the actors Box2D physics body then add a fixture to allow collision, e.g.:

When we call initBody() we pass 3 parameters, the first is the type of body, in this case “dynamic” which means the object can move around the physics world. The second and third tell the physics engine if the body uses fixed rotation and can move very fast respectively, in both cases we opt to turn those features off.

Once the actor has a physics body we can add a fixture. A fixture is a shape that describes the physical shape of the actor and how it reacts to other actors in the simulation. In this case we use a simple box shape that is the same size as the actor. We could pass in additional options to addFixture() such as density, friction, restitution etc..

Note that an actor should not be added to a scene that does not support physics.

Its possible to detect if an actor is under control of physics by checking b5.Actor.body, if not null then the actor is under control of Box2D physics.

Physics materials

Physics materials are represented by the Material class and are used to store physical material parameters for the Box2D engine. A Material can be supplied as an option to b5.addFixture() when creating fixtures, e.g.:

Physics joints enable you to connect physical bodies together in a variety of ways. The following types of physical joints are currently supported:

Weld joint – This is a joint that simply attaches two objects together, when one object moves the other is dragged with it

Distance joint – A distance joint limits the distance of two bodies and attempts to keep them the same distance apart, damping can also be applied

Revolute joint – A revolute joint forces two bodies to share a common anchor point. It has a single degree of freedom and the angle between the two bodies can be limited. In addition a motor can also be applied to the joint

Prismatic joint – A prismatic joint limits movement between the two bodies by translation (rotation is prevented). The translational distance between the two joints can be limited. In addition a motor can also be applied to the joint

Pulley joint – A pulley joint can be used to create a pulley system between two bodies so that when one body rises the other will fall

Wheel joint – A wheel joint restricts one body to the line on another body and can be used to create suspension springs. A motor can also be applied to the joint

Mouse joint – The mouse joint can be used to move physical bodies towards a location

Joints can be created by calling b5.Actor.addJoint(options), where options includes information about the specific joint that should be added.

For more details regarding initBody(), addFixture() and addJoint() see the Actor Method reference.

Lets take a look at a quick example of creating a joint that joins two actors:

When two actors that are under the control of the physics system start to collide or stop colliding then their onCollisionStart(contact) and onCollisionEnd(contact) event handlers are called (if specified). This gives you the opportunity to determine when, where and how collisions took place. Lets take a look at a quick example that shows two actors interacting during collision:

In the above example we create a floor actor and dynamic actor, we assign the onCollisionStart() event handler which will be called when actor1 hits something. You can find out the two colliding actors by checking the user data assigned to the body, which happens to the the actor that contains it.

A number if different collision flags can be set on a per object basis which affects how object interacts with other objects. For example you can allow certain object to collide with one type of object but not another. The following flags are available:

collision_category – The category bits describe what type of collision object the actor is

collision_mask – The mask bits describe what type of other collision objects this actor can collide with

collision_group – The group index flag can be used to override category and mask, but we generally do not need to use it and usually set it to 0 for all actors.

To set these flags, pass them to the options parameter of Actor.addFixture().

Applying force and torque

To apply force to a body you need to call ApplyForce() on the actors body, e.g.:

1

2

varb2Vec2=Box2D.Common.Math.b2Vec2;

actor.body.ApplyForce(newb2Vec2(fx,fy),pos);

Where fx, fy represents the force to apply and pos the physics body position in Box2D world coordinates to apply the force at. You can get the world position of a body as follows:

1

varpos=actor.body.GetWorldPoint(newb2Vec2(0,0));

If you want to calculate a position that is offset from the body then you can pass the offset to GetWorldPoint(), e.g.:

1

2

varws=actor.scene.world_scale;

varpos=actor.body.GetWorldPoint(newb2Vec2(dx/ws,dy/ws));

Note that we scale the offset dx,dy by the physics world scale allowing us to specify the offset in scene coordinates

To apply torque (turning force) to an actors body we can call ApplyTorque() on the actors body, e.g.:

1

actor.body.ApplyTorque(torque);

Changing velocity and applying impulses

To set an actors velocity directly you can call SetLinearVelocity() and SetAngularVelocity() on the actors physics body, e.g.:

1

2

3

varb2Vec2=Box2D.Common.Math.b2Vec2;

actor.body.SetLinearVelocity(newb2Vec2(vx,vy));

actor.body.SetAngularVelocity(vr);

Here we set the linear velocity to vx,vy and the angular velocity to vr directly.

Note that setting the velocity directly will overwrite the current velocity, if instead you want to apply a new velocity then you should use impulse instead.

To apply impulse to an actors body you should call ApplyImpulse() on the actors body, e.g.:

1

2

varb2Vec2=Box2D.Common.Math.b2Vec2;

actor.body.ApplyImpulse(newb2Vec2(fx,fy),pos);

As with ApplyForce the impulse can be applied at a specific point on the body.

None Box2D physics

When actors are not under control of the Box2D physics system they have their own linear / angular / depth velocity (vx, vy, vr, vd) and linear / angular / depth velocity damping (vx_damping, vy_damping, vr_damping, vd_damping). This enables you to move objects around under velocity without the need for a full physics simulation, however collision and collision response will not automatically be taken care of for you, you will need to do this yourself by checking for overlap between actors.

Note that when an actor is under control of the Box2D physics system and you find that you need to apply the actors current velocities to the physics system then you can call b5.Actor.updateToPhysics() to force the changes to be written back to the physics system, this will also awaken the actors body if asleep.

Scene extents

When an actor has b5.Actor.wrap_position enabled, if it goes beyond the parent scenes extents then it will wrap back around at the opposite edge.

Animating

Actors can be animated using timelines, a timeline is a collection of Animations. A timeline can target just about any property of an actor. Actors can carry multiple animations that can be played back at the same time, as well as paused and restarted. The actors timeline manager b5.Actor.timelines is a TimelineManager which allows you to add, remove and find existing animation timelines.

Lets take a look at a quick example of creating an animation timeline that animates a property of an actor:

1

2

3

4

// Create a timeline that targets the x property of my_object with 4 key frames spaced out every 5

my_object.timelines.add(timeline);// Add to timeline manager to be processed

In the above code we create a timeline with an animation that animates the x coordinate of the actor object. We add the timeline to the actors timeline manager to ensure that it is processed each frame.

Besides bitmap animation and timeline animations, its possible to use velocity to set off simple animations. For example, by setting the b5.Actor vr (rotation velocity) you can set it spinning at a specific speed.

Note that when an animation is finished playing it will automatically be destroyed and cleaned up unless its destroy property is set to false.

Input Events

All actors that are defined as touchable will receive touch input events as long as the scene that contains them is the focus or secondary focus scene. An actor is defined as touchable when the Actor.touchable property is set to true. When the app looks to determine which actor has potentially been touched the fewer actors it has to check the better, so this is a simple optimisation which enables only those actors that need to be checked for touch to be checked, whilst the rest can be comfortably ignored.

Actors can receive the following touch events:

onTapped(touch_pos) – Called when tapped / clicked

onBeginTouch(touch_pos) – Called when user is touching

onEndTouch(touch_pos) – Called when user stops being touching

onLostTouchFocus(touch_pos) – Called when actor loses touch focus, that is when the user drags their finger off the object but does not lift their finger from the screen

onMoveTouch(touch_pos) – Called when a touch is moved over the game object

Lets take a look at a quick example:

1

2

3

4

5

6

7

8

9

10

11

12

13

varactor=newb5.ArcActor();

actor.name="actor1";

actor.fill_style="#0000ff";

actor.radius=100;

actor.filled=true;

actor.touchable=true;

scene.addActor(actor);

actor.onBeginTouch=function(touch_pos){

console.log("Started touching actor "+this.name);

};

actor.onEndTouch=function(touch_pos){

console.log("Stopped touching actor "+this.name);

};

Note that in order for a child actor to receive input events its parent must also be touchable, otherwise touch events will not be passed down the chain.

In the case of overlapping actors, only the top most actor will receive the touch event. You can change this behaviour by allowing touch events from child actors to be passed back up to their parents by setting b5.Actor.bubbling to true, the default behaviour is to not pass events up to parents. Event bubbling is useful especially when creating user interface components. For example, in the list menu demo, the buttons that are contained within the scrolling menu actor are marked as bubbling to enable touch events to be passed to the container which in turn allows the user to scroll the list around whilst still touching child buttons.

Lets take a quick look at an example of event bubbling:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

varactor=newb5.ArcActor();

actor.name="actor1";

actor.fill_style="#0000ff";

actor.radius=100;

actor.filled=true;

actor.touchable=true;

scene.addActor(actor);

actor.onBeginTouch=function(touch_pos){

console.log("Started touching actor "+this.name);

};

actor.onEndTouch=function(touch_pos){

console.log("Stopped touching actor "+this.name);

};

varchild1=newb5.ArcActor();

child1.name="child1";

child1.fill_style="#00ffff";

child1.radius=50;

child1.filled=true;

child1.touchable=true;

child1.bubbling=true;

actor.addActor(child1);

child1.onBeginTouch=function(touch_pos){

console.log("Started touching child actor "+this.name);

};

child1.onEndTouch=function(touch_pos){

console.log("Stopped touching child actor "+this.name);

};

You will notice that if you click the cyan coloured circle both touch event handlers for actor and child1 will be called.

Depth

Actors can have 3D depth using the b5.Actor.depth property.For values of greater than 0, the actor will be projected into the screen using the centre of the scene as the projection origin. This is ideal for creating effects such as parallax scrolling where objects in the background move more slowly and appear smaller than objects in the foreground. The parallax scrolling and planets demos show good examples of using depth.

Orphans

An orphan is an actor that sits inside another actors child hierarchy but does not obey its visual transform. This is useful in areas of game play where you need to generate game objects that are attached to the actor but do not follow it. To turn an actor into an orphaned actor simple set its b5.Actor.orphaned property to true.

Virtual Canvas

Actors can be made to act like a scrollable container for their children. This can be done by converting the actor into a virtual canvas actor, which gives the actor a virtual area that the user can scroll the children around in. This type of functionality is perfect for various types of user interface elements such as grids and lists.

When an actor has been made virtual using b5.Actor.makeVirtual(), or by setting true for virtual to the Actor constructor the following properties become available:

scroll_pos_x – Canvas scroll X position

scroll_pos_y – Canvas scroll Y position

scroll_vx – Canvas scroll X velocity

scroll_vy – Canvas scroll Y velocity

scroll_range – Scrollable range of canvas (left, top, width, height)

prev_scroll_pos_x – Previous canvas scroll X position

prev_scroll_pos_y – Previous canvas scroll Y position

Lets take a quick look at a virtual canvas actor example:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

varactor=newb5.RectActor();

actor.name="actor1";

actor.fill_style="#0000ff";

actor.w=400;

actor.h=400;

actor.filled=true;

actor.touchable=true;

scene.addActor(actor);

actor.makeVirtual();

actor.scroll_range=[-150,-150,300,300];

varchild1=newb5.ArcActor();

child1.name="child1";

child1.fill_style="#00ffff";

child1.radius=50;

child1.filled=true;

child1.touchable=true;

child1.bubbling=true;

actor.addActor(child1);

In the above example actor acts as a parent for child1, actor has been converted to a virtual canvas actor which can now scroll its content around. Note that we set the scroll_range after the actor has been made virtual and that the child actor uses bubbling to ensure that touch events are passed up to the actor parent.

In addition to the virtual scrolling area, virtual actors also allow child actors to be docked around their edges using b5.Actor.dock_x and b5.Actor.dock_y.

Shadows and Composite Operations

Actors can be made to render a drop shadow around their edges by setting b5.Actor.shadow to true. When shadowing is enabled the following properties can be used to adjust how the shadow appears:

shadow_x, shadow_y – Shadow position offset

shadow_blur – Amount to blur shadow

shadow_colour- Colour of shadow (e.g #ffffff)

Lets take a quick look at an example of how to use shadows:

1

2

3

4

5

6

7

8

9

10

11

varactor=newb5.RectActor();

actor.fill_style="#0000ff";

actor.w=200;

actor.h=200;

actor.filled=true;

actor.shadow=true;

actor.shadow_x=20;

actor.shadow_y=20;

actor.shadow_blur=2;

actor.shadow_colour="#000000";

scene.addActor(actor);

Shadows should be used sparingly as they can be quite slow to render on some devices

Actors can be rendered using a variety of different composite operations by setting b5.Actor.composite_op to one of the following:

source-over- displays the source image over the destination image (default)

source-atop – displays the source image on top of the destination image. The part of the source image that is outside the destination image is not shown

source-in – displays the source image in to the destination image. Only the part of the source image that is INSIDE the destination image is shown, and the destination image is transparent

source-out – displays the source image out of the destination image. Only the part of the source image that is OUTSIDE the destination image is shown, and the destination image is transparent

destination-over – displays the destination image over the source image
destination-atop – displays the destination image on top of the source image. The part of the destination image that is outside the source image is not shown

destination-in – displays the destination image in to the source image. Only the part of the destination image that is INSIDE the source image is shown, and the source image is transparent

destination-out – displays the destination image out of the source image. Only the part of the destination image that is OUTSIDE the source image is shown, and the source image is transparent

lighter – displays the source image + the destination image

copy – displays the source image. The destination image is ignored

xor – the source image is combined by using an exclusive OR with the destination image

Lets take a quick look at an example of how to use composite operations:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

varactor1=newb5.RectActor();

actor1.fill_style="#0000ff";

actor1.w=200;

actor1.h=200;

actor1.filled=true;

scene.addActor(actor1);

varactor2=newb5.RectActor();

actor2.fill_style="#ff0000";

actor2.x=100;

actor2.y=100;

actor2.w=200;

actor2.h=200;

actor2.filled=true;

actor2.composite_op="lighter";

scene.addActor(actor2);

Caching Rendering for Speed

Whilst HTML5 has come along leaps and bounds, it still has speed issues on some mobile devices. I have found that most of these bottle necks are due to rendering shapes, gradient fills and text. To combat this problem caching is built into the actor system. When an actor is marked as cached it is rendered to an off screen HTML5 canvas. When the actor is drawn at a later stage the pre-rendered canvas is drawn instead. This means that gradient fills and shape renders are only done a single time. To mark an actor as cached simply set b5.Actor.cache to true, the next time it is drawn it will be cached. The only downside to this is that once cached you lose some control over the actor, for example when you cache a label you can no longer change the text without firstly destroying the old cache and causing the actor to be re-rendered to the canvas.

Lets take a quick look at an example of how to cache an actor:

1

2

3

4

5

6

7

8

varactor=newb5.LabelActor();

actor.w=300;

actor.h=100;

actor.font="30pt Calibri";

actor.fill_style="#000000";

actor.text="Hello World";

actor.cache=true;

scene.addActor(actor);

In the above example, setting the actors cache to true has caused the actor to be cached. Note however that if you do not set the width and height of the actor to a large enough size then the actors content will be clipped. For example, if you change the width of the above actor to 100 you will see that only the central portion of the text will be displayed.

We can take caching one step further using merged caching. Merged caching is the process of merging multiple actors into the same cache, saving on extra memory required for all those off screen canvases. Child actors can be marked as merged via b5.Actor.merge_cache, this causes them to be rendered into a parent cache if one is available. However, when a child actor is merged into its parents cache you can no longer change its position, scale, rotation or opacity.

Tagging

Its sometimes useful to be able to group actors together using some kind of common tag. All actors contain the tag property which is a string that can be used to tag a group of actors that are somehow related. For example, all actors are bullets.

The scene class contains the b5.Scene.removeActorsByTag(tag_name) method which enables you to remove a collection of actors that all have the same tag. This is very useful for removing a complete group of game objects from the scene. For example, if you want to clear up all bullets in a space shooter, tag them all with “bullet” then call scene. removeActorsByTag(“bullet”) to remove them all at the same time.

Ignoring the Camera

By default all game objects will move in relation to the scenes camera. Whilst this is a nice feature, its not always what we want. For example, if you have a number of game objects that are part of the HUD, you will want them to stay still when the camera moves. By setting b5.Actor.ignore_camera to true these actors will not move with the camera.

Particle Systems

A particle system is a special sort of actor that can handle the generation / re-generation of particle actors. To use a particle system actor you create an instance of b5.ParticleActor then create and add individual actor particles, specifying a life span (the amount of time the particle exists), a spawn delay (the amount of time to wait before spawning the particle) and the total number of times the particle can be reborn. When a particle system has no particles left alive it will be destroyed. A ParticleActor is derived from an Actor and inherits all of its properties, functions and so forth from its parent, so it can be moved around, rotated, placed under the control of physics etc..

Lets take a quick look at an example that shows how to create a particle actor:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

// Create particles actor

varparticles=newb5.ParticleActor();

scene.addActor(particles);

// Create and add 50 particles

for(vart=0;t&lt;50;t++)

{

varparticle=newb5.ArcActor();

particle.atlas=scene.findResource("lives","brush");

particle.radius=50;

particle.fill_style="#ffff00";

particle.vx=Math.random()*100-50;

particle.vy=-200;

particle.vo=-2;

particle.vsx=-1;

particle.vsy=-1;

particles.addParticle(particle,1,1,t *0.05);

}

A number of utility methods within the ParticleActor class are available for creating different types of effects easier:

Lets take a quick look at an example that shows how to create an explosion one of the utility methods:

1

2

3

4

5

6

7

8

9

// Create explosion

varparticles=newb5.ParticleActor();

scene.addActor(particles);

particles.generateExplosion(10,b5.ArcActor,1,200,1,10,1,{

fill_style:"#ffa0e0",

radius:30,

vsx:1.5,

vsy:1.5,

});

The last property passed to generateExplosion() is a properties list that will be transferred to all generated particles.

Tiled Maps

Tile maps are an age old solution to storing large sprawling environments on memory constrained devices which stretches back to the first 8-bit computer games. Instead of storing one huge image the image is built up of small evenly sized images (tiles) that are used to rebuild the image by displaying those tiles in a grid arrangement.

Booty5 supports tiled maps via the b5.MapActor. The MapActor supports the following features:

Maps of any size and shape

Visual and collision tiles

Display of sub area for optimal display

Auto tile generation

Lets take a look at an example of how to create a MapActor in code:

1

2

3

4

5

6

7

8

9

10

varmap=newb5.MapActor();// Create instance of actor

map.map_width=100;// Set map width in cells

map.map_height=100;// Set map height in cells

map.display_width=16;// Set how many cells to display on x axis

map.display_height=16;// Set how many cells to display on y axis

map.generateTiles(32,64,64,256);// Generate the tile set

map.bitmap=newb5.Bitmap("tiles","testmap.png",true);// Set tile set bitmap

In the above example we create a 100×100 cell map of 64×64 pixel tiles, generate a tile set with 32 tiles then fill it with randomly selected tiles from the tile set.

MapActors have a special feature that can drastically improve the performance when rendering the map. Instead of attempting to render the entire 100×100 cell map every game frame the map_width and map_height properties can be used to specify a sub area of the map to display. The MapActor will take into account the actos position and the camera position to decide which section of the map to display to ensure that the ceklls are always displayed in relation to the cameraas position, this allows the game to scroll the map around and only display cells that are around the camera.

Note that map_width and map_height should be large enough to ensure that the displayed area overhands the edges of the screen, otherwise you will see tiles appear / disappear at the edges.

The MapActor has also been provided with a number of query functions that can be used top determine the tile at positions in the scene

Speeding up Rendering

Each actor can be set to round its rendered pixel coordinate up to the nearest integer value which can significantly speed up the rendering of game objects. However, the downside of using this feature is that you will lose visual precision. To force an actor to round pixels set its round_pixels property to true.

Miscellaneous

Testing for actor overlap

You can test if two actors overlap by calling Actor.overlaps(other_actor). Note that this method currently does a simple test an does not take into account shape, orientation, origin or scale.

Transforming a point by an actors transform

You can transform an x,y point by an actors current transform using Actor.transformPoint(x, y)

Test a point for actor hit

You can test to see if an x,y point hits an actor by calling Actor.hitTest(position), where position is {x, y}