Game
Main Game Engine class which runs everything The main game loop is as follows:
- Update - For each GameEntity:
- Process Input from roku remote
- Process Audio Events (https://developer.roku.com/en-ca/docs/references/brightscript/events/roaudioplayerevent.md)
- Process ECP input (https://developer.roku.com/en-ca/docs/developer-program/debugging/external-control-api.md)
- Process URL events (https://developer.roku.com/en-ca/docs/references/brightscript/events/rourlevent.md)
- Runs the Entity's onUpdate() function
- Moves Entity based on velocity
- Collisions - For each GameEntity:
- Run Entity's onPreCollision() function
- For any collisions, runs Entity's onCollision() function
- Runs entity's onPostCollision() function (At any time, the Entity in question may Delete() itself. Before every entity interaction, the entity is checked to make sure it is still valid in case it was deleted in the last interaction)
- Draw - For each GameEntity, sorted by zIndex
- Runs the Entity onDrawBegin() function
- For each drawable in the Entity, run the draw() function
- Run the Entity onDrawEnd() function
-
Draw all debug items in game space (e.g. colliders, screen safe zones, etc).
-
UI - For the tree of widgets in the UI Container
- Run onUpdate()
- Run draw()
- Debug UI - Draw all debug windows in the tree of the Debug UI
Properties
sortedEntities(Array.<GameEntity>)compositor(roCompositor)screen(roScreen)canvas(BGE.Canvas)uiCanvas(BGE.Canvas)dummyScreen(roScreen)renderQuality(BGE.RenderQualityManager) — The game's render quality level and presets - seesetQualityLevel(),currentScene(GameScene) — The scene currently in playcurrentSceneArgs(object) — The args passed to changeScene() for the current sceneEntities(object) — All of the GameEntities by name => => GameEntityStatics(object) — All static variables for a given object typeScenes(object) — The scene definitions by name (see defineScene())Interfaces(object) — The interface definitions by nameBitmaps(object) — The loaded bitmaps by nameSounds(object) — The loaded sounds by nameFonts(object) — The loaded fonts by nameModels(object) — The loaded Models by nametweenManager(BGE.TweenManager) — Ticks every live tween once per frame and writes interpolated values onto arbitraryscreenFade(BGE.ScreenFade) — Full-screen overlay used by changeSceneWithFade() - see BGE.ScreenFade.gameUi(BGE.UI.UiContainer) — Container for all UIdebugUi(BGE.UI.UiContainer) — Container for Debug UIfocusManager(BGE.UI.FocusManager) — The single, global focused-widget/cursor state shared by gameUi and anydefaultTheme(BGE.UI.Theme) — Default theme for all UI widgets, set in new()uiFocusSoundKey(string) — Default Game.loadSound() keys played by every BGE.UI.Button on focus/click (seeuiClickSoundKey(string)controls(BGE.Controller.ControlMap) — Unified remote+controller input mapping - see enableControllerInput()
Constructor
new Game(
canvasWidth: integer,
canvasHeight: integer,
uiWidth?: integer,
uiHeight?: integer,
): GameConstructor for GameEngine
Parameters
canvasWidth(integer) — Width of the canvas the game is drawn tocanvasHeight(integer) — Height of the canvas the game is drawn touiWidth(integer, optional, default: 0) — Width of the UI canvas - if 0, will be same as screenuiHeight(integer, optional, default: 0) — Height of the UI canvas - if 0, will be same as screen
Instance Methods
setCamera(cam: Camera): void
Parameters
cam(Camera)
Returns
void
setupUi(uiWidth: integer, uiHeight: integer): void
Sets up the Ui layer
Parameters
uiWidth(integer)uiHeight(integer)
Returns
void
scaleCanvasToFillScreen(): void
Returns
void
getNextGameEntityId(): string
Gets the next valid id for a GameEntity
Returns
string
Play(): void
Returns
void
broadcastControllerConnectionInfo(): void
Sends every currently-connected controller-web client (see controller-web/index.html) a fresh {playerIndex, labels, connectedCount} message - unlike the old single sendMessage() this replaced (still correct for the client that just opened, since it's the only one that needs its own playerIndex/labels), a client already connected also needs to hear about connectedCount changing when a different client opens or closes, so the page can show "2 controllers connected" - it has no other way to find that out. No-op if controller input was never enabled. Left non-private (like processEntityOnControls/ ControllerServer.parseHttpRequest - see their own doc comments) so a future spec has a seam to exercise this without standing up real sockets end to end.
Returns
void
clearStaleInputCaptureForTest(): void
Test-only passthrough to the private clearStaleInputCapture(), so specs can exercise the top-of-frame capture reset Game.Play() performs without driving a full Play() loop iteration.
Returns
void
processCollisionsForTest(): void
Test-only passthrough to the private processEntitiesCollisions(), so specs can run one frame's collision pass without driving a full Play() loop iteration.
Returns
void
processKeyboardCharsForTest(
entity: GameEntity,
chars: Array.<integer>,
): boolean
Test-only: runs processEntityOnInput() for one entity as if these characters had been typed this frame, with no button events.
Parameters
entity(GameEntity)chars(Array.<integer>)
Returns
boolean— true if the entity is still valid
dispatchOnInputForTest(
entity: GameEntity,
input: GameInput,
): boolean
Test-only passthrough to the private dispatchOnInput(), so specs can exercise the same currentInputEntityId gating Game.Play() relies on without needing a full Play() loop iteration.
Parameters
entity(GameEntity)input(GameInput)
Returns
boolean— true if the entity is still valid
processUiInputForTest(controllerInputs: Array.<GameInput>): void
Test-only passthrough to the private processUiInput() with only controller-originated inputs, so specs can check gameUi dispatch.
Parameters
controllerInputs(Array.<GameInput>)
Returns
void
processEntityOnControls(entity: GameEntity): boolean
Dispatches onControls() to one entity, but only if the game has bound at least one action/axis (ControlMap.hasBindings()) - see GameEntity.onControls()'s doc comment for the zero-cost-when-unbound guarantee this preserves. Not private, matching this file's own precedent (BGE.Controller.ControllerServer.parseHttpRequest) of an otherwise-internal method left public purely so a spec can exercise it directly, since Game's real per-frame loop has no other test seam.
Parameters
entity(GameEntity)
Returns
boolean— true if this entity is still valid
End(): void
Ends the Game
Returns
void
Pause(): void
Pauses the game Only entities marked as pausable = false will be processed in game loop For each entity, the onPause() function will be called
Returns
void
Resume(): integer
Resumes / unpauses the game For each entity, the onResume() function will be called, and any image in the entity will have its onResume() called
Returns
integer
isPaused(): boolean
Is the game paused?
Returns
boolean
setBackgroundColor(color: integer): void
Sets the default background color for the game Before any entities are drawn, the screen is cleared to this color
Parameters
color(integer)
Returns
void
getDeltaTime(): float
What's the time in seconds since last frame?
Returns
float
getTotalTime(): float
What's the total time in seconds since ths start
Returns
float
getScene(): GameScene
Gets the scene the game is currently in
Returns
getCanvas(): ifDraw2D
Gets the bitmap the game is currently drawing to
Returns
ifDraw2D
getScreen(): roScreen
Gets the screen object
Returns
roScreen
getScreenSize(): BGE.Math.Vector
Returns
BGE.Math.Vector
getScreenCenter(): BGE.Math.Vector
Returns
BGE.Math.Vector
resetScreen(): void
Resets the screen Note: Important This function is here because of a bug with the Roku. If you ever try to use a component that displays something on the screen aside from roScreen, such as roKeyboardScreen, roMessageDialog, etc. the screen will flicker after you return to your game You should always call this method after using a screen that's outside of roScreen in order to prevent this bug.
Returns
void
getEmptyBitmap(): roBitmap
Gets a 1x1 bitmap image (used for collider compositing)
Returns
roBitmap
getUI(): BGE.Ui.UiContainer
Gets the UI Container to add new UI elements (which get drawn on top off Game Entities)
Returns
BGE.Ui.UiContainer
getDebugUI(): BGE.UI.UiContainer
Gets the main debug window to add other debug widgets to
Returns
BGE.UI.UiContainer
enableControllerInput(
port?: integer,
shareFirstControllerWithRemote?: boolean,
): void
Starts a local HTTP + WebSocket server so a browser (phone/tablet) can connect as a virtual twin-stick controller - see BGE.Controller.ControlMap (game.controls) to map its input to named actions/axes.
Never calling this creates no socket and drains no messages. The per-entity controller-input dispatch is likewise skipped whenever no controller events were produced this frame, and all ControlMap work is skipped until a game binds an action/axis - so a game using neither pays nothing per frame, and a remote-only game that uses game.controls still works without calling this.
Parameters
port(integer, optional, default: 8888) — TCP port to listen onshareFirstControllerWithRemote(boolean, optional, default: true) — share playerIndex 0 between the first browser and first remote/gamepad (whichever connects first), so a default bindAction(playerIndex=0) responds to either. Set false to give every input source its own distinct index instead.
Returns
void
setCombineRemoteInputs(combine: boolean): void
Selects how physical remotes/gamepads map to player indices, independent of enableControllerInput()/browser controllers. Default false: each device gets its own stable index. Set true so every device drives playerIndex 0 instead, regardless of connect/input order - for a single-player game where either the remote or a gamepad should work. Only affects a device first seen after this call.
Parameters
combine(boolean)
Returns
void
getControllerConnectionInfo(): string
The LAN URL to open on a phone/tablet to connect as a controller, or "" if enableControllerInput() hasn't been called.
Returns
string
enableStandardDebugUi(args?: roAssociativeArray): void
Adds the standard set of debug panels (fps, input, memory, garbageCollector, log) to the debug UI - the same five widgets nearly every example wires up by hand in main.bs. Pass false for any key in args to opt out of that one panel, e.g. {log: false}.
Parameters
args(roAssociativeArray, optional, default: "{}") — set fps/input/memory/garbageCollector/log to false to skip that panel
Returns
void
debugDrawColliders(enabled: boolean): void
Set if colliders should be drawn
Parameters
enabled(boolean)
Returns
void
debugDrawSafeZones(enabled: boolean): void
Set if Safe Zone should be drawn
Parameters
enabled(boolean)
Returns
void
debugDrawEntityDetails(enabled: boolean): void
Set GameEntity and SceneObject debug view on or off
Parameters
enabled(boolean)
Returns
void
debugShowUi(enabled: boolean, drawToScreen?: boolean): void
Set if Debug UI/Windows should be drawn
Parameters
enabled(boolean)drawToScreen(boolean, optional, default: true) — Draw the debug UI to the screen instead of the canvas
Returns
void
isDebugUiEnabled(): boolean
Returns
boolean
debugPrintPerfStats(
enabled: boolean,
intervalSeconds?: float,
): void
Set whether Play() prints per-frame perf stats to the console (entity/collider counts and per-phase timing: UI input, update+collision, entity draw, buffer swap). Off by default - each phase timestamp above is only measured while this is on, so leaving it off costs nothing per frame. Independent of, and typically a much shorter interval than, the periodic garbage-collection print.
Parameters
enabled(boolean)intervalSeconds(float, optional, default: "2.0") — How often to print, in seconds (default 2)
Returns
void
getDebugValue(debugKey: string): dynamic
Parameters
debugKey(string)
Returns
dynamic
log(message: string, level?: BGE.Debug.LogLevel): void
Logs a message, printing it and recording it for on-screen debug display (e.g. BGE.Debug.LogDisplay)
Parameters
message(string)level(BGE.Debug.LogLevel, optional, default: "BGE.Debug.LogLevel.info")
Returns
void
getLogHistory(): Array.<object>
Gets the history of messages logged via log()
Returns
Array.<object>— an array of {message: string, level: BGE.Debug.LogLevel}
debugSetColors(colors: DebugColors): void
Sets the colors for the debug items to be drawn colors = {colliders: integer, safe_action_zone: integer, safe_title_zone: integer}
Parameters
colors(DebugColors)
Returns
void
debugLimitFrameRate(limit_frame_rate: integer): void
Limit the frame rate to the given number of frames per second
Parameters
limit_frame_rate(integer)
Returns
void
getGarbageCollectionStats(): GarbageCollectionInfo
Gets the latest stats from automatic garbage collection https://developer.roku.com/en-ca/docs/references/brightscript/language/global-utility-functions.md#rungarbagecollector-as-object
Returns
GarbageCollectionInfo— Stats of garbage collection. Properties: count, orphaned, root
raycast(
origin: BGE.Math.Vector,
direction: BGE.Math.Vector,
maxDistance?: float,
collidableFlags?: integer,
): BGE.RaycastHit
Casts a ray from origin in direction and returns the nearest collider it intersects - 2D (CircleCollider/RectangleCollider) and 3D (SphereCollider3d/BoxCollider3d) alike. Useful for line-of-sight checks, hitscan weapons, ground/wall detection, AI vision cones, and mouse/cursor picking.
Parameters
origin(BGE.Math.Vector) — world-space point the ray starts fromdirection(BGE.Math.Vector) — world-space direction of the ray (does not need to be pre-normalized)maxDistance(float, optional, default: "10000.0") — the ray stops testing past this distancecollidableFlags(integer, optional, default: "&hFFFFFFFF") — only colliders whose memberFlags overlap this mask are tested (see Collider.memberFlags)
Returns
BGE.RaycastHit— the nearest hit, orinvalidif the ray hit nothing
raycastAll(
origin: BGE.Math.Vector,
direction: BGE.Math.Vector,
maxDistance?: float,
collidableFlags?: integer,
): Array.<BGE.RaycastHit>
Casts a ray from origin in direction and returns every collider it intersects, sorted by ascending distance from origin. See raycast() for the single-nearest-hit variant.
Parameters
origin(BGE.Math.Vector) — world-space point the ray starts fromdirection(BGE.Math.Vector) — world-space direction of the ray (does not need to be pre-normalized)maxDistance(float, optional, default: "10000.0") — the ray stops testing past this distancecollidableFlags(integer, optional, default: "&hFFFFFFFF") — only colliders whose memberFlags overlap this mask are tested (see Collider.memberFlags)
Returns
Array.<BGE.RaycastHit>— every hit along the ray, nearest first (empty array if none)
defineInterface(
interfaceName: string,
interfaceCreationFunction: function,
): void
TODO: work on interfaces
Parameters
interfaceName(string)interfaceCreationFunction(function)
Returns
void
addEntity(
entity: GameEntity,
args?: roAssociativeArray,
): GameEntity
Adds a game entity to be processed by the game engine Only entities that have been added will be part of the game Calls the entity's onCreate() function with the args provided
Parameters
entity(GameEntity) — the entity to be addedargs(roAssociativeArray, optional, default: "{}") — arguments to the entity's onCreate() method
Returns
GameEntity— the entity that was added
getEntityByID(entityId: string | dynamic): GameEntity
Gets an entity by its unique id
Parameters
entityId(string | dynamic)
Returns
GameEntity— the entity with the given id, if found, otherwise invalid
getEntityByName(objectName: string): GameEntity
Gets the first entity with the given name
Parameters
objectName(string)
Returns
GameEntity— the entity with the given name, if found, otherwise invalid
getAllEntities(objectName: string): Array.<GameEntity>
Gets all the entities that match the given name
Parameters
objectName(string)
Returns
Array.<GameEntity>— an array with entities with the given name
getEntitiesByTag(tag: string): Array.<GameEntity>
Gets all entities tagged with the given tag (via GameEntity.tagsList), across every scene
Parameters
tag(string) — the tag to look for (case insensitive, see BGE.TagList)
Returns
Array.<GameEntity>— an array of entities with the given tag
getAllEntitiesWithInterface(interfaceName: string): dynamic
TODO: work on interfaces
Parameters
interfaceName(string)
Returns
dynamic
destroyEntity(entity: GameEntity, callOnDestroy?: boolean): void
Destroys an entity and all its colliders Clears its properties, so images, etc. won't get drawn anymore
Parameters
entity(GameEntity) — the entity to destroycallOnDestroy(boolean, optional, default: true)
Returns
void
destroyAllEntities(
objectName: string,
callOnDestroy?: boolean,
): void
Destroys all entities with a given name
Parameters
objectName(string)callOnDestroy(boolean, optional, default: true)
Returns
void
entityCount(objectName: string): integer
Gets the number of entities of a given name
Parameters
objectName(string)
Returns
integer
defineScene(newScene: GameScene): void
Registers a scene so it can later be switched to by name with changeScene().
Parameters
newScene(GameScene) — The scene to register; itsnameis the keychangeScene()uses
Returns
void
isSceneChanging(): boolean
Whether a scene change was requested this frame and hasn't been applied yet.
Returns
boolean
changeScene(sceneName: string, args?: object): boolean
Changes to the scene registered under the given name, then calls its onCreate(args). While the game is running, the change is applied at the end of the current frame.
Parameters
sceneName(string) — The name of a scene registered withdefineScene()args(object, optional, default: "{}") — Passed to the scene'sonCreate()
Returns
boolean— true if a scene with that name exists
changeSceneWithFade(
sceneName: string,
args?: object,
seconds?: float,
): boolean
Fades the screen to black, changes to the scene registered under the given name, then fades back in once its onCreate(args) has run. With no current scene yet (e.g. starting the first scene), the scene changes straight away and just fades in from black. Check isTransitioning() to ignore gameplay input while this runs.
Parameters
sceneName(string) — The name of a scene registered withdefineScene()args(object, optional, default: "{}") — Passed to the scene'sonCreate()seconds(float, optional, default: 0.3) — How long each half of the fade takes
Returns
boolean— false if the scene doesn't exist or a transition is already running
isTransitioning(): boolean
Whether a changeSceneWithFade() transition is running (fading out, changing scene, or fading back in).
Returns
boolean
updateFadeTransitionForTest(dt: float): void
Test-only: one frame's fade step with a given dt, then any scene change it requested, the way the end of a Play() frame applies it.
Parameters
dt(float)
Returns
void
resetScene(): void
Restarts the current scene by changing to it again with the same args.
Returns
void
getSceneNames(): Array.<string>
The names of every scene registered with defineScene().
Returns
Array.<string>
loadBitmap(bitmapName: string, path: dynamic): boolean
Loads an image file to be used as an image in the game.
Supported file types are .png, .jpg/.jpeg, .webp, .bmp and .gif. SVG is not supported by Roku. An animated .gif only loads its first frame - use a sprite sheet with AnimatedImage for animation.
Parameters
bitmapName(string) — the name this bitmap will be referenced by laterpath(dynamic) — The path to the bitmap, or an associative array {width: integer, height: integer, alphaEnable:boolean}
Returns
boolean— true if image was loaded
getBitmap(bitmapName: string): roBitmap
Gets a bitmap image (roBitmap) by the name given to it when loadBitmap() was called
Parameters
bitmapName(string)
Returns
roBitmap
unloadBitmap(bitmapName: string): void
Invalidates a bitmap name, so it can't be loaded again
Parameters
bitmapName(string)
Returns
void
load3dModel(
modelName: string,
modelPath: string,
options?: BGE.Model3dLoadOptions,
): boolean
Loads a 3d model file (.stl or .obj) to be used in the game. For an .obj file, also resolves and loads its texture (if any) - either from options.texturePath (always takes priority) or from the .obj's own mtllib/map_Kd reference. A missing or unreadable texture file logs a warning and leaves the model untextured (flat-shaded) rather than failing the whole load - see BGE.Model3dOps.applyTexture.
Parameters
modelName(string) — the name this model will be referenced by latermodelPath(string) — the path to the model fileoptions(BGE.Model3dLoadOptions, optional, default: "{}") — optional load options (currently just texturePath, an .obj-only explicit texture override)
Returns
boolean— true if the model was loaded
get3dModel(modelName: string): Model3d
Gets a 3d Model (Model3d) by the name given to it when load3dModel() was called
Parameters
modelName(string)
Returns
unload3dModel(modelName: string): void
Invalidates a 3d Model name, so it can't be loaded again
Parameters
modelName(string)
Returns
void
registerFont(path: string): boolean
Registers a font by its path
Parameters
path(string)
Returns
boolean— true if font was registered
loadFont(
fontName: string,
font: string,
size: integer,
italic: boolean,
bold: boolean,
): void
Loads a font from the registry, and assigns it the given name
Parameters
fontName(string) — the lookup name to assign to this fontfont(string) — the font to loadsize(integer)italic(boolean)bold(boolean)
Returns
void
unloadFont(fontName: string): void
Unloads a font so it can't be used again
Parameters
fontName(string)
Returns
void
getFont(fontName: string): roFont
Gets a font object, to be used for writing text to the screen For example, in BGE.DrawText()
Parameters
fontName(string)
Returns
roFont
fitCanvasToScreen(): void
Scales and positions the current canvas to fit the screen
Returns
void
centerCanvasToScreen(): void
Centers the canvas on the screen
Returns
void
musicPlay(path: string, loop?: boolean): boolean
Plays an audio file at the given path This is designed for music, where only one file can play at a time.
Parameters
path(string) — the path of the music fileloop(boolean, optional, default: false)
Returns
boolean
musicStop(): void
Stops the currently playing music file
Returns
void
musicPause(): void
Pauses the currently playing music
Returns
void
musicResume(): void
Resumes / unpauses the current music
Returns
void
loadSound(soundName: string, path: string): void
Loads a sound file from the given path to be played later
Parameters
soundName(string) — the name to assign this sound to, to be referenced laterpath(string) — the path to load
Returns
void
playSound(soundName: string, volume?: integer): boolean
Plays the given sound
Parameters
soundName(string) — the name of the sound to playvolume(integer, optional, default: 100) — volume (0-100) to play the sound at
Returns
boolean
newAsyncUrlTransfer(): roUrlTransfer
Creates a new URL Async Transfer object, which is handled by the game loop Events from this URL transfer will be set to entities via the onUrlEvent() method
Returns
roUrlTransfer
setInputEntity(entity: GameEntity): void
Set only one entity to receive onInput() calls Useful for when a menu/pause screen should handle all input Takes effect immediately (this frame's remaining dispatch), not just next frame.
Parameters
entity(GameEntity)
Returns
void
unsetInputEntity(): void
Unset that only one entity will receive onInputCalls() Takes effect immediately (this frame's remaining dispatch), not just next frame.
Returns
void
postGameEvent(
eventName: string,
data?: roAssociativeArray,
): void
General purpose event dispatch method Game entities can listen for events via the onGameEvent() method
Parameters
eventName(string) — identifier for the event, eg. "hit", "win", etc.data(roAssociativeArray, optional, default: "{}") — any data that needs to be be passed with the event
Returns
void
setQualityLevel(level: integer): void
Pins the render quality level and turns off adaptive tuning.
Parameters
level(integer) — aBGE.RenderQualityLevelvalue
Returns
void
enableAdaptiveQuality(
options?: BGE.AdaptiveQualityOptions,
): void
Adjusts the render quality level automatically to hold a target frame rate, starting from the current level (moved into minLevel..maxLevel first if needed).
Parameters
options(BGE.AdaptiveQualityOptions, optional, default: "{}") — e.g. {targetFps: 30, minLevel: BGE.RenderQualityLevel.low}
Returns
void
disableAdaptiveQuality(): void
Stops adaptive tuning, keeping the current level.
Returns
void