An object oriented game engine for the Roku
The purpose of this project is to make it easy to develop games for the Roku in an object oriented fasion. Similar to how you would with an engine such as Gamemaker or Unity (minus any visual software that is).
First start by creating the gameEngine object
game = new_game(canvas_width as Integer, canvas_height as Integer, canvas_as_screen_if_possible = false as Boolean) as Object
Creates the main game object, the canvas width and height create an empty bitmap of that size that the game is drawn to. If canvas_as_screen_if_possible is set the game will draw to the roScreen directly if the canvas dimensions are the same as the screen dimensions, this improves performance but makes it so you can't do various canvas manipulations (such as screen shake or taking screenshots).
After setting up your game, call this method to execute it.
This will end your game. All existing instances will be destroyed before exiting (meaning onDestroy() will be called).
This will pause your game. Note: all instances that have pauseable = false will continue to execute. Also keep in mind that onDrawBegin, onDrawEnd, and onDrawGui are always executed even when the game is paused.
This will resume your paused game. Returns how long the game was paused in milliseconds if the game was paused, otherwise returns invalid if the game wasn't paused.
Returns true if the game is paused.
Returns the delta time. Note: Delta time is automatically applied to the built in instance xspeed and yspeed. Delta time is also automatically passed to the onUpdate(dt) function in every instance for convenience.
Returns the current room.
Returns the canvas bitmap object.
Returns the screen object.
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.
This method is primarily for internal use, but may be called manually if desired. It returns an empty game object.
This enables or disables the drawing of all colliders.
This enables or disables the drawing of safe zones.
This sets the frame rate limit for the testing game behavior under such circumstances. Default is 0, which is no limit.
This method is for debugging purposes, it will draw the colliders associated with the provided instance.
This method is for debugging purposes, when called in an object's onDrawGui() method it will display the Action Safe Zone and Title Safe Zone. Helps with ensuring elements will not be cut off by overscan.
Define a new game object. The function provided will be called when an instance of the object is created, the function provided receives an empty object and modifies it as necessary.
Define a new interface. The function provided will be called when an instance of a game object calls addInterface, a roAssociativeArray with the property "owner" will be passed in to the defined function.
Creates a new instance of an object that has been defined using defineObject(). The args AssociativeArray is optional, it will be passed to the onCreate() method.
If the instance is created successfully, the instance is returned. Otherwise returns invalid.
Returns the instance associated with the provided ID.
Returns the first instance of an object of the specified name. (note: If more than one instance exists, only the first one will be returned)
Returns array containing all instances of the specified name.
Destroys the provided instance.
Destroys all instances of the specified name.
Returns the number of instances of the specified name.
Define a new room. The function provided will be called when the room is switched to, the function provided receives an empty object and modifies it as necessary. This is the same as defineObject() except it is used for rooms.
Switches to a room that has been defined using defineRoom(). The args AssociativeArray is optional, it will be passed to the onCreate() method.
Resets the current room, retaining the original args.
Loads a bitmap into memory and makes it available by name with the getBitmap() function. The path can also be an associative array structured like so {width: 10, height: 10, AlphaEnable: true}, doing this will create an empty bitmap. Returns true if successful.
Returns the bitmap associated with the provided name. Returns invalid if a bitmap with the provided name hasn't been loaded.
Unloads the bitmap associated with the provided name from memory. Returns true if successful.
Registers the font at the provided path. Returns true if successful. Note: All fonts in the directory pkg:/fonts/ automatically get registered.
loadFont(font_name as String, font as String, size as Integer, italic as Boolean, bold as Boolean) as Void
Loads the font into memory and makes it accessable by the provided name. Note: The font must be registered first and "font" must be the filename prefix.
Unloads the font associated with the provided name from memory.
Returns the font associated with the provided name. Font must have been previously loaded using loadFont().
Modifies the canvas size with the provided width and height.
Returns an associative array with the current canvas offset. Will contain values for x and y.
Returns an associative array with the current canvas scale. Will contain values for x and y.
Set the canvas x and y positions. Note: positions are absolute and not in relation to the current scale, you should take scale into account when manually setting the positions.
Sets the canvas scale to the given amount, if only scale_x is given, scale_y will be set to the same amount. The scale_y parameter is only necessary if you want to stretch the canvas.
This fits the game canvas to the screen regardless of the screen aspect ratio. This makes it so a game can be made at any size and black bars will be shown on the top/bottom or left/right if the game aspect ratio is not the same as the TV's.
This centers the game canvas.
Plays music from the provided path. Loop defaults to false. Returns true if the path is valid.
Stops the currently playing music.
Pauses the currently playing music.
Resumes music that is paused.
Loads a short sound in to memory from the provided path to be triggered by playSound() with the provided name. This is specifically for sound effects, because the sounds are in memory they will be played instantly.
Plays the sound associated with the name provided, sound must have already been loaded using loadSound(). Returns true if the sound was triggered.
Returns a roUrlTransfer object that can be used to asynchronously request data from a server. The response message is then passed to the gameObject onUrlEvent method. The roUrlTransfer object must be used only once for a url request as it will be automatically destroyed upon recieving a response. A new roUrlTransfer object should be retrieved for each independent transfer request. This allows for multiple transfers to occur simultaneously.
A game object is an object that has been created using the function newEmptyObject(), this is usually done internally by defining a new object using defineObject() and then creating a new instance of it using createInstance(). Instructions on doing this can be found above.
The basic game object structure looks like this.
new_object = {
' -----Constants-----
name: object_name
id: m.currentID.ToStr()
game: m
' -----Variables-----
persistent: false
pauseable: true
depth: 0
x: 0.0
y: 0.0
xspeed: 0.0
yspeed: 0.0
colliders: {}
images: []
' -----Methods-----
(Methods will be described below)
}
- name: This is the object name as declared by defineObject(). For example - A "ball" object can be defined, all instances of the object will have the name "ball" but will have different IDs.
- id: This is the ID for this specific instance.
- game: This is a reference to the game so that every object instance can easily access its methods.
- persistent: If true the instance will not be destroyed when the on changeRoom(), default behavior is to destroy all instances on changeRoom().
- pauseable: If set to false the instance will continue to execute even when the game is paused. Default is set to true, in which case only onDrawBegin(), onDrawEnd() and onDrawGui() will be called when the game is paused.
- depth: Declares the instance draw depth.
- x/y: The x and y positions of the instance.
- xspeed/yspeed: The movement speed of the instance. Note: This is automatically multiplied by delta time.
- colliders: Instances can have multiple colliders, you can modify collider properties here but adding a new collider should be done by the methods described below.
- images: Instances can have multiple images, you can modify image properties here but adding a new image should be done by the methods described below.
The override methods are designed to be overridden. They are automatically called by the game at the approprate times. Note: For these methods, if an argument is shown, then the override method must accept that argument as well.
This method will always be called when the instance is created. Put creation code here. Must receive args as an associative array, this is the same associative array that is passed as args when calling createInstance().
This method is called every frame. Put code to be constantly ran here.
This method is called just before collision checking occurs, any important pre-collision check adjustments can be made here.
This method is called when two object instances collide. collider and other_collider are strings refering to the specific colliders that are in collision. other_instance is the object instance that has been collided with.
This method is called just after collision checking occurs, any post-collision processing can be put here.
This is called before the instance is drawn and receives the canvas as a object that can be drawn to.
This is called after the instance is drawn and receives the canvas as a object that can be drawn to.
This is called whenever a button is pressed, released, or held.
Button | When Pressed | When Released | When Held |
---|---|---|---|
Back | 0 | 100 | 1000 |
Up | 2 | 102 | 1002 |
Down | 3 | 103 | 1003 |
Left | 4 | 104 | 1004 |
Right | 5 | 105 | 1005 |
Select | 6 | 106 | 1006 |
Instant Replay | 7 | 107 | 1007 |
Rewind | 8 | 108 | 1008 |
Fast Forward | 9 | 109 | 1009 |
Info | 10 | 110 | 1010 |
Play | 13 | 113 | 1013 |
This can be used to receive text input from ECP keyboard events.
This is called when an audio event is triggered, the message is passed to the method.
This is called when the game is paused via Pause()
This is called when the game is resumed via Resume, the amount of time the game was paused (in milliseconds) is passed to the method.
This is called when a URL event is triggered by a roUrlTransfer object retrieved from newAsyncUrlTransfer(). The message is passed to the method, then the roUrlTransfer object is automatically destroyed.
This method will be called on all objects whenever PostGameEvent(event as String, data = {} as Object) is called. It is a basic event system for objects to inform other objects of events.
This method will be called when the room is changed and recieves the name of the new room
This method will always be called just before the instance is destroyed.
addColliderRectangle(collider_name as String, offset_x as Integer, offset_y as Integer, width as Integer, height as Integer, [enabled as Boolean])
Adds a rectangle collider to the instance's colliders associative array with the provided name and properties. Enabled is true by default.
addColliderCircle(collider_name, radius, [offset_x as Integer, offset_y as Integer, enabled as Boolean])
Adds a circular collider to the instance's colliders associative array with the provided name and properties. By default offset_x is 0, offset_y is 0, and enabled is true.
Returns the collider with the provided name, returns invalid if it doesn't exist.
Removes the collider with the provided name.
Adds the provided roRegion to the instance's images array. By default images are added to the end of the images array but you can also choose to insert the image to a specific position in the array with the insert_position argument. Images are drawn in the order they exist in the instance's images array. Args is an associative array with values to override the defaults. Here are the defaults that can be overridden.
{
offset_x: 0 ' The offset of the image.
offset_y: 0
scale_x: 1.0 ' The image scale.
scale_y: 1.0
rotation: 0 ' The image rotation in degrees
color: &hFFFFFF ' This can be used to tint the image with the provided color if desired. White makes no change to the original image.
alpha: 255 ' Change the image alpha (transparency).
enabled: true ' Whether or not the image will be drawn.
}
- Note 1: You cannot rotate and scale an image at the same time as Roku does not provide a function for doing so.
- Note 2: The origin property has been removed from images, instead to handle origins the user should pass in roRegions with SetPretranslation set.
addAnimatedImage(image_name as String, regions as Object, [args as Object, insert_position as Integer])
addAnimatedImage functions the same as addImage except that it accepts an array of roRegions and contains additional properties for handling animations. Here are the additional properties, which can be overriden with args.
{
index: 0 ' The index of the region to be shown. This would not normally be changed manually, but if you wanted to stop on a specific image in the spritesheet this could be set.
animation_speed: 0 ' The time in milliseconds for a single cycle through the animation to play. If the animation speed is left as 0 the image will not animate automatically and it will be up to the user to manually set the appropriate index.
animation_tween: "LinearTween" ' The tween method (from the list in tweens.brs) to use in cycling through the animation.
}
This method is used internally by addImage and addAnimatedImage to add the image object to the images array. However, this method could also be used to provide an image object with a customized structure. The image object must be an roAssociativeArray and must have a Draw() method that will automatically get called by the engine.
Returns the image with the provided image name.
Removes the image matching the provided image name.
Sets a variable for an object type that is persistent across all objects of this type (based on the concept of static variables)
Returns a static variable, returns invalid if static variable has not been set.
Adds a previously defined interface to the instance.
Returns true if the instance has the interface.
This area will be a collection of functions that I've found useful for game development.
This function is used internally. It will insert a value to the specified index of an array and shift all subsequent values.
This function is used interally when DrawColliders() is called. It will draw an empty circle to the screen, however this is extremely expensive and is meant for debugging purposes only.
This is here because brightscript unfortunately doesn't provide an atan2 math function.
This will convert a hue, saturation, value color to a red, green, blue color hex. If alpha is provided the returned hex will be in RGBA format instead of RGB. These registry functions make it easy to read and write to the registry, they should be mostly self exlanitory.
Writes to the provided registry section the provided key/value pair. Data types supported are booleans, integer and floating point numbers, strings, roArray, and roAssociativeArray objects.
Reads the provided key from the provided registry section. The default value will be written if the registry section and key have no value yet.
DrawText(draw2d as Object, text as String, x as Integer, y as Integer, font as Object, alignment = "left" as String, color = &hEBEBEBFF as Integer)
Gives a convenient way to draw text with halignement set as "left", "right", or "center"
DrawScaledAndRotatedObject(draw2d as object, x as float, y as float, scale_x as float, scale_y as float, theta as float, drawable as object, color = &hFFFFFFFF as integer)
WARNING: This is potentially unsafe and always slow by comparison to normal draw calls. It attempts to both scale and rotate an image when drawing, I say attempts because in order to do both actions it must create a separate roBitmap and do the scaled draw to that before then doing to rotated draw to the draw2d destination. If the scaling is large enough that the created roBitmap is too big or consumes too much video memory this could potentially be breaking.
This basically creates an improved roTimespan object which adds the AddTime and RemoveTime methods which are useful when pausing/resuming gameplay (used automatically with the addAnimatedImage timer).
Automatically parses a JSON Hash type data export from TexturePacker to return an roAssociativeArray with roRegions mapped to the provided bitmap. SetPretranslation will be applied automatically on the regions if pivot points have been enabled in TexturePacker. atlas can be either parsed or unparsed JSON.