Scenes – A Place for Actors to Play

Introduction

A scene is a container for a collection of actors and other resources (such as shapes, materials, bitmaps etc..), whilst an actor is simply a game object that provides some kind of game functionality. A scene will manage the lifetime, processing and rendering of any game objects that are added to it. A scene will also manage the lifetime of any local resources (such as images, sounds etc..) as well as animation timelines (animation timelines are targeted at scenes and game objects to animate them) and actions lists.

It can be easier to think about Booty5 game development if we think in terms of the movie business, we all watch movies and programmes on the TV which makes it easy to relate to. A movie usually consists of a number of scenes that contain the environment, actors (provide the focus and entertainment of the movie) and a view into the scene (a camera).

Booty5 is based on these similar principles, where the scene acts as the game environment where the action takes place, actors represent individual game objects and the camera (which in this case is part of the scene) the view into the game.

Creating Scenes

Scenes are created by creating an instance of the b5.Scene object which are then added to the main App object for processing using b5.App.addScene(), e.g.:

1

2

3

4

// Create a scene

varscene=newb5.Scene();

// Add scene to the app

app.addScene(scene);

Once the scene has been created you can begin setting the various properties of the scene. Its best to always give your new scene a name by assigning the name to scene.name. This will allow you to find the scene at some point in the future by searching for it by name using b5.App.findScene(name).

Once the scene is added to the app the app will begin processing and rendering it. When we are done with a scene we can remove / destroy it by calling b5.App.removeScene(), e.g.:

1

2

// Remove scene from app

b5.app.removeScene(scene);

You can also remove / destroy a scene by calling destroy() on the scene object:

1

2

// Remove scene from app

scene.destroy();

Note that the scene will not be removed until the end of the apps processing loop.

Scene Events

The scene handles a number of events that you can tap into:

onCreate() – When a scene that was exported from the Booty5 game editor is created it will call the this event in response to the scene being created as long as it was defined within the editor

onDestroy() – When a scene is to be destroyed during tear down this event will be raised

onTick(delta_time) – This event is raised every time the scene is about to be updated (every logic frame)

onBeginTouch(touch_pos) – This events is raised when the user touches the scene

onEndTouch(touch_pos) – This events is raised when the user stops touching the scene

onMoveTouch(touch_pos) – This events is raised when the user moves a touch around the scene

Lets take a quick look at an example of using scene events:

1

2

3

scene.onBeginTouch=function(touch_pos){

console.log("Scene was touched");

}

Processing and Visibility

Scenes are processed when their active property is set to true, if a scene is marked as not active then the scene and all of its actors and timelines will not be updated. Its generally a good idea to deactivate scenes when they are not in use, especially when targeting resource constrained devices such as mobile devices.

Scenes are rendered when their visible property is set to true. If a scene is marked as not visible then the scene and all of its contained actors will not be rendered. Again, its a good idea to hide scenes that are hidden by other scenes or are currently off screen.

Note that each time the scene is updated (each game frame and as long as the scene is active) its onTick() method will be called. You can tap into this event to add scene specific functionality, e.g.:

1

2

3

scene.onTick=function(dt){

// Do something with the scene (dt is delta time passed since last updated)

};

Local Resources

Resources can be local or global. If a resource is global then it is available to all scenes and the objects which they contain. Global resources are also always present in memory and are not freed until the app exits or are removed manually. If a resource is local to a scene then it is usually only accessible to the scene and objects within that scene. In addition, when the scene is destroyed all resources that it contains are destroyed along with it.

Resources can be added to a scene using b5.Scene.addResource(), e.g.:

1

2

3

varmaterial=newb5.Material("static_bounce");

material.restitution=1;

scene.addResource(material,"Material");

In the above piece of code we create a physics material then add it to the scenes resources.

To later retrieve that resource we would search for it using:

1

scene.findResource("static_bounce","Material");

Resources can also be located via their path. A path represents the hierarchical path to the object which consists of the names of the parent objects separated by dots. For example, if you want to locate a physics material called “material1” that is located in a scene named “scene1” then the path to that resources would be “scene1.material1”. If the material was located in the Apps global resource space then the path would simply be “material1”. To find the instance of the resource from the path you can call b5.Utils.findResourceFromPath(path, type), e.g.:

Later if we need to remove and destroy the resource then we can either call:

1

2

3

4

5

// If we do not have a reference to the resource then we can tell the scene to find and remove it

scene.destroyResource("static_bounce","Material");

// If we already have reference to the material then we can destroy it through the object itself

material.destroy();

Working with Actors

Scenes are designed by their very nature to contain and manage game objects (actors). An actors life time is determined by the lifetime of a scene, once a scene is killed off so are all of the game objects that it contains. When an actor is first created it needs to be added to a scene in order for it to be processed and rendered.

To add an actor to a scene use b5.Scene.addActor(actor), to later find an actor simply call b5.Scene.findActor(actor_name), you can pass an additional parameter to this method that will force the search to search all child actors also.

Once an actor is part of a scene it can later be removed by calling b5.Scene.removeActor(actor) or by calling b5.Actor.destroy() on the actor object.

Actors can be categorised using a tag name that is specified by the actors tag property. Game objects can be removed en-mass by tag using b5.Scene.removeActorsByTag(tag_name);, this method will remove all actors within the scene that have the specified tag; tags enable you to mark groups of actors and later remove them all in one go.

Whilst layers can be used to visually order the order in which visible scenes are overlaid, where layers are not used you can bring actors to the front of the visual stack or send them to the back using b5.Scene.bringToFront() and b5.Scene.sendToBack().

Scene Camera

The camera is the view into the scene (game world). The scene can be moved around by changing Scene.camera_x and Scene.camera_y or by changing the cameras velocities Scene.camera_vx and Scene.camera_vy.

A scene has a single camera with a variety of built in functions:

Touch panning

Target tracking

Constrained movement

Velocity damping

Touch panning

Touch panning is a feature that allows the user to pan around the game world (a scene) using their finger on touch devices or the mouse on desktop devices. When the user holds down the mouse button or touches the screen and drags, the camera will follow the players finger. This feature is not only great during testing but also very useful for many different types of games that have game worlds that are larger than the screen as it gives the user the opportunity to take a look around the world.

Touch panning can be enabled for each separate axis by setting b5.Scene.touch_pan_x and / or b5.Scene.touch_pan_y to true.

Its often useful to be able to tell if the user is currently touch panning the camera, this can be done by checking the value of b5.Scene.panning, if true then the user is currently panning around the scene. During the development of Leapo I bumped into an issue on mobile devices. I allow the user to pan around the game world, but also when the user taps the screen it causes the frog to jump. On some mobile devices, very small touch pans were causing the game to ignore frog jumps. To fix this I included a tolerance in b5.Scene.min_panning, which sets a minimum amount of panning movement that should be considered a pan (note that this value is the squared distance of the minimum, for example if you want a minimum value of 2 pixels in either direction then set this value to 2*2 + 2*2 = 8).

Target tracking

Target tracking (or camera follow) is a feature that enables the scenes camera to follow a specified actor or pair of actors. The camera can track game objects on separate axis, so for example you could have the camera track a player character on the x-axis, whilst also simultaneously tracking an evil alien on the y-axis.

To enable target tracking simply set b5.Scene.target_x and / or b5.Scene.target_y to the actor that you wish the camera to follow (in the game editor this option is available the the scenes properties), e.g.:

1

2

3

// Camera tracking two actors

scene.target_x=b5.Utils.resolveObject("scene1.actor1");

scene.target_y=b5.Utils.resolveObject("scene1.actor2");

The rate at which the camera follows the targets can be set via b5.Scene.follow_speed_x and b5.Scene.follow_speed_y, higher values will cause the camera to catch up with the target more quickly,

Constrained Movement

Scenes have a rectangular boundary (extents) that can be used to constrain the camera and its actors. A scenes extents can be set via b5.Scene.extents which is an array of 4 values that represents the top, left, width, height of the constrained area. (In the game editor the scenes extents is represented by a green rectangle). When the camera hits the edges of the scene extents it will stop, e.g.:

1

2

// Limit movement of camera between -200, -200 and 200, 200

scene.extents=[-200,-200,400,400];

Coordinate System

A scenes coordinate system is based at its centre, if the scene is located in the middle of the screen then the scenes world origin will be at the centre of the screen. The coordinate system is designed this way to make it easier to design outwards. Designing outwards is incredibly useful when designing games that can be played across a variety of different sized displays as the main focus of the game is at its centre and not at a potentially clipped edge.

Position and Opacity

A scene has position and size (b5.Scene.x, b5.Scene.y, b5.Scene.w, b5.Scene.h) and can be moved around the screen, enabling effects such as scrolling scenes on and off the screen. When a scene is moved all of its contained actors are also moved.

Scenes have an opacity level (b5.Scene.opacity) between 0 and 1 which determines how opaque / transparent the scene and its contained game objects are This values can be used for effects such as fades where the entire scene is faded up and down

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 scenes Colour property.

Child Clipping

A scene can clip its child actors by enabling Scene.clip_children. By default the scene will clip children against its dimensions (defined by Scene.w and Scene.h), but this can be changed by assigning a Shape to Scene.clip_shape which causes scene objects to be clipped against that shape, e.g.:

1

2

// Set clipping shape that scene will use to clip children

scene.clip_shape=b5.Utils.resolveResource("shape1","shape");

Scene Layering

During game development you will find times when you need to display more than one scene at the same time. For example in the game Leapo there is the main game scene which contains the game world and the heads up display (HUD) scene which contains the players lives left. time left, level and pause button. Each scene can have a layer number (b5.Scene.layer) which determines the visual order in which scenes are drawn to the display, scenes on higher layers will appear above scenes on lower layers.

Note that you should always set the scenes layer via the b5.Scene._layer property setter to ensure that the scene layers get re-sorted, e.g.:

1

2

scene1._layer=1;// This scene will appear below layer 2

scene2._layer=2;// This scene will appear above layer 1

Scene Physics

Scenes can support a Box2D physics world, by default Box2D physics is disabled and has to be enabled. To enable physics you need to include the Box2D JavaScript library into your index.html file:

1

&lt;script src='lib/Box2dWeb-2.1.a.3.min.js'&gt;&lt;/script&gt;

Booty5 uses the Box2DWeb JavaScript library, you can see reference for this library here.

Scenes can selectively use Box2D physics, to enable physics in a scene you need to initialise the scenes physics world by calling b5.Scene.initWorld(), e.g:

1

scene.initWorld(gravity_x,gravity_y,do_sleep);

In the call to initWorld() we pass the x-axis and y-axis gravity (0, 10 as default) and a flag that determines if the physics system should allow objects to sleep. I recommend that you do enable sleeping as it provides a good speed boost on mobile devices.

Once physics has been enabled for the scene you can set a number of other properties that affect how the physics system behaves:

time_step – This is the amount of time that has elapsed between each call to update physics in seconds. By default this value is set to 0, which causes the scene to pass a variable time step to the physics system, this however is not ideal as physics will not behave consistently across different speed devices. Its generally better to pass a constant value and run the physics system multiple times when the frame rate drops. When exporting from the game editor a default value of 0.033 is passed (30 fps). Note that when adaptive physics is enabled in the App, the physics system will automatically be ran multiple times if the frame rate drops.

world_scale – This value affects how the physics world maps to the visual world (default value is 20)

If a scene has any objects that use the Box2D physics system then the scene must have physics enabled for it to work.

When physics is enabled in a scene the physics simulation will be updated during the scenes game logic update.

Animation Timelines

A scene manages a collection of animation timelines via its TimelineManager (b5.Scene.timelines). An animation timeline is basically a collection of animations that are played back asynchronously. Usually objects within the scene or even the scene itself will add its animation to the scene for processing. Timelines will only play whilst the scene is active and destroying the scene will also destroy all contained animation timelines.

To add an animation timeline to a scene you can call b5.Scene.timelines.add(my_timeline), e.g.:

Actions Lists

A scene manages a collection of actions lists via the ActionsListManager (b5.Scene.actions). An actions list is a collection of actions that are executed consecutively. An action is a single unit of functionality such as tween a collection of properties over time, start a sound effect or animation etc..

Usually objects within the scene or even the scene itself will add its action lists to the scene for processing. Action Lists will only play whilst the scene is active and destroying the scene will also destroy all contained action lists.

To add an actions list to a scene you can call b5.Scene.actions.add(actions_list), e.g.:

1

2

3

4

5

6

7

8

// Create actions list

varactions_list=newb5.ActionsList("turn",0);

// Add an action to actions list

actions_list.add(newb5.A_SetProps(actor,"vr",2/5));

// Add actions list to the scenes actions list manager

scene.actions.add(actions_list);

Input Events

Scenes can receive input events if they are set as a focus or secondary focus scene in TheApp. When a touch / mouse event occurs it is sent from the app to the focus scene and then the secondary focus scene. In order to act upon these events you need to assign the following event handlers:

onTapped(touch_pos) – This event is raised when the user taps the screen (a tap is defined as when the user touches the screen then lets go)

onBeginTouch(touch_pos) – This event is raised when the user touches / clicks the screen

onEndTouch(touch_pos) – This event is raised when the user stops touching / clicking the screen

onMoveTouch(touch_pos) – This event is raised when the user moves their finger / mouse around the screen whilst touching it

A scene also receives keyboard input events, but only the main focus scene can receive them and not the secondary focus scene. These events include:

onKeyDown(e) – This event is raised when the user presses a key, the raised event e contains the keys details with e.keyCode containing the key code

onKeyUp(e) – This event is raised when the stops pressing a key, the raised event e contains the keys details with e.keyCode containing the key code

Note that within the game editor, the code entered into the event handlers will be called each time the event is raised.

A number of useful properties of the scene can be used to determine if the user is touching or moving a touch:

b5.Scene.touching – Set to true when the user is touching the screen

b5.Scene.touchmove – Set to true when the user is moving a touch

Detecting when Resources have Loaded

Booty5 can automatically take care of waiting for resources to be loaded, including loading the resources that need to be loaded for all scenes that are loaded at the start of the app. However, you may find that you need to load scenes at a later date that contain resources.

Its possible to check when a scenes resources have finished loading using b5.Scene.areResourcesLoaded(), which will return true when all resources have finished loading. You could do this using a timer then update the UI to display a loading bar, e.g.:

1

2

3

4

5

6

7

// Wait for scene resources to finish loading

varresource_check_interval=setInterval(function(){

if(scene.areResourcesLoaded()){

// Resources have finished loading

}

clearInterval(resource_check_interval);

},500);

You can also find out how many resources need to be loaded in the scene by calling b5.Scene.countResourcesNeedLoading().