RoomController - coldrockgames/gml-raptor GitHub Wiki

In the project template, you can see, that there is one specific RoomController prepared for each room of the game. I strongly recommend, to keep that strategy through your game!

The reason is, that the RoomController has a lot of features and methods that work on the current room's settings, like Camera, Viewport(s) and the room size. It's not a good idea to create one persistent RoomController object for your entire game. That's, what a GameController is for.

It defines lots of macros and offers some very helpful methods to control the camera, like zooming and shaking and moving. However, with Virtual Rooms you can bring your control over the camera's viewport to the next level!

Variables of the RoomController

image

Variable Description
particle_layer_names This holds either a string or an array of strings with the names of the layers, where you want your Particle Effects to spawn. Read the documentation about the raptor particle systems for more information.
hide_mouse_cursor Some games need a mouse, some don't. Set this to true, to have your mouse cursor hidden when you enter the room that is controlled by this RoomController instance. See the next flag below, to understand the options, you have.
show_mouse_on_popups Works only, if hide_mouse_cursor is set to true. Activating this second flag will reshow the mouse cursor, whenever you show any popup view (via the show_popup() function) or use any of the MessageBox Functions.
adapt_app_surface If this is true, then the RoomController will resize the application surface to the dimensions of the main viewport in this room (index 0). As you should always use the RoomTemplate for raptor rooms, all your rooms should have viewport[0] enabled anyways.
escape_leaves_room Tired of writing the same "KeyPress-ESC" code over and over again? Just set this to true, to make the RoomController navigate back to the previous room, when you press the ESC key.
Navigation will only take place, if there is currently no popup visible.
The callback method onTransitBack will be invoked in your RoomController, so you can control the Room Transitions, that shall be used.
record_in_transit_chain Set, whether this room shall be recorded in the transit_back stack of the room controller. Read more in Room Transitions.

Game UI

With Release 3.0, a new macro, UI_ROOT has been added to the RoomController.

This is the root ControlTree for your game UI in the current room. It is recommended, that you add your UI elements for this room through the UI_ROOT tree. Please consult the UI Subsystem and ControlTree documentations for details about the new UI.

Tracking of GameWindow size changes

The RoomController detects, if the size of the game window has changed. This includes the HTML5 target, where changes of the browser window are also detected.

Macro Description
WINDOW_SIZE_X
WINDOW_SIZE_Y
Current size of the GameWindow
WINDOW_SIZE_X_PREVIOUS
WINDOW_SIZE_Y_PREVIOUS
Size of the GameWindow in the last frame
WINDOW_SIZE_DELTA_X
WINDOW_SIZE_DELTA_Y
Difference between the above values
WINDOW_SIZE_HAS_CHANGED true, if anything has changed, otherwise false

Mouse-Coordinate translation to GUI layer

These macros hold translated values from the world coordinates to the UI coordinates. The top left edge is always 0,0, no matter where your Camera is currently looking at.

Macro Description
GUI_MOUSE_X
GUI_MOUSE_Y
Current size of the GameWindow
GUI_MOUSE_X_PREVIOUS
GUI_MOUSE_Y_PREVIOUS
Size of the GameWindow in the last frame
GUI_MOUSE_DELTA_X
GUI_MOUSE_DELTA_Y
Difference between the above values
GUI_MOUSE_HAS_MOVED
MOUSE_HAS_MOVED
true, if anything has changed, otherwise false.
Both macros hold the same value, they point to the same variable, there's nothing calculated twice.
The second macro only exists for better readable code (it may look strange if you query a GUI mouse movement in a code part that has nothing to do with the GUI)

Camera control

RoomController offers some methods to animate the camera. Use these to add some nice effects to your game. But first, some details about how they work and what you need to know. But keep in mind that the camera control is also effected by Virtual Rooms!

camera_action_data

All these methods return a camera_action_data struct, which, while being an internal struct of raptor, and therefore you should not tinker with it too much, offers one important end-user function.

By default the movement follows a linear AnimCurve (acLinearMove), moving (or zooming) at a constant rate to the target. To change this, you can use this function to replace the AnimCurve with a more spectacular effect if needed, like bouncing or smoother start/end movement.

set_anim_curve

/// @function		set_anim_curve(curve, x_channel_name = "x", y_channel_name = "y")
/// @description	Assigns a different AnimCurve than the default acLinearMove curve to this camera action.
///			The curve must provide the channels named in the x_ and y_channel_name parameters and
///			the value range must be 0..1, where 0 meanse "0%" and 1 means "100%" of distance done.
///			This function returns self to make it chainable.
/// @param {AnimCurve} curve 	The AnimCurve to use.
/// @param {string} x_channel_name	Name of the channel for the x-coordinate
/// @param {string} y_channel_name	Name of the channel for the y-coordinate
/// @returns {camera_action_data} struct Self, to be chainable.
static set_anim_curve = function(curve, x_channel_name = "x", y_channel_name = "y") {

A typical call to one of these functions could look like this:

Example for having the camera "look at" a specific point on the map (like hinting the player to an object, he should pay attention to), and moving back to the player object after a short wait time:

#macro MOVE_TIME   30
#macro WAIT_BEFORE_MOVE_BACK 180
camera_move_to(MOVE_TIME, super_treasure.x, super_treasure.y,, cam_align.middle_center)
    .set_anim_curve(acSmoothInOut);

run_delayed(WAIT_BEFORE_MOVE_BACK, function() {
    camera_move_to(MOVE_TIME, player.x, player.y,, cam_align.middle_center)
        .set_anim_curve(acSmoothInOut);
});

Camera animation functions

The Cam Stack

When you start manipulating the camera, one question arises quite quickly: "How do I remember where that camera has been before all that move action?". This is especially true when you want to just "do a quick zoom to look at x/y and then go back".

For this, the cam stack of the room controller jumps in to help you out.

camera_push

/// @func	camera_push()
/// @desc	Push the current camera position an size on a stack
camera_push = function() {

camera_pop

/// @func	camera_pop(_frames = 0, _pos_curve = acLinearMove, _zoom_curve = acLinearMove)
/// @desc	Restore the last stored position and size of the camera
///		optionally with an animation time and animation curves
camera_pop = function(_frames = 0, _pos_curve = acLinearMove, _zoom_curve = acLinearMove) {

camera_pop_all

/// @func	camera_pop_all(_frames = 0, _pos_curve = acLinearMove, _zoom_curve = acLinearMove)
/// @desc	Similar to camera_pop but it skips all the in-between steps and returns the camera
///		to the FIRST stored position. The entire cam stack is cleared afterwards.
camera_pop_all = function(_frames = 0, _pos_curve = acLinearMove, _zoom_curve = acLinearMove) {

screen_shake

/// @func	screen_shake(frames, xintensity, yintensity, camera_index = 0)
/// @desc	lets rumble! NOTE: Ignored, if already rumbling!
screen_shake = function(frames, xintensity, yintensity, camera_index = 0) {

camera_zoom_to

/// @func	camera_zoom_to(frames, new_width, 
///		curve = acLinearMove, enqueue_if_running = true, camera_index = 0)
/// @desc	zoom the camera animated by X pixels
camera_zoom_to = function(frames, new_width, 
                 curve = acLinearMove, enqueue_if_running = true, camera_index = 0) {

camera_zoom_by

/// @func	camera_zoom_by(frames, width_delta, min_width, max_width, 
///		curve = acLinearMove, enqueue_if_running = true, camera_index = 0)
/// @desc	zoom the camera animated by X pixels
camera_zoom_by = function(frames, width_delta, min_width, max_width, 
                 curve = acLinearMove, enqueue_if_running = true, camera_index = 0) {

camera_move_to

/// @func	camera_move_to(frames, target_x, target_y, 
///		curve = acLinearMove, camera_align = cam_align.top_left, 
///		enqueue_if_running = true, camera_index = 0)
/// @desc	move the camera animated to a specified position with an optional alignment.
///			The cam_align enum can be used to specify a different alignment than
///			the default of top_left. For instance, if you specify align.middle_center here,
///			this function works like a kind of "look at that point", 
///			as the CENTER of the view will be at target_x, target_y coordinates.
camera_move_to = function(frames, target_x, target_y, 
                 curve = acLinearMove, camera_align = cam_align.top_left, 
                 enqueue_if_running = true, camera_index = 0) {

camera_move_by

/// @func	camera_move_by(frames, distance_x, distance_y, 
///		curve = acLinearMove, enqueue_if_running = true, camera_index = 0)
/// @desc	move the camera animated by a specified distance
camera_move_by = function(frames, distance_x, distance_y, 
                 curve = acLinearMove, enqueue_if_running = true, camera_index = 0) {

camera_look_at

/// @func	camera_look_at(frames, target_x, target_y, 
///		curve = acLinearMove, enqueue_if_running = true, camera_index = 0)
/// @desc	move the camera animated so that target_x and target_y 
///		are in the center of the screen when finished.
camera_look_at = function(frames, target_x, target_y, 
                 curve = acLinearMove, enqueue_if_running = true, camera_index = 0) {

camera_bump_x

/// @func	camera_bump_x(frames, distance_x, enqueue_if_running = true, camera_index = 0)
/// @desc	A bump animation horizontal
camera_bump_x = function(frames, distance_x, enqueue_if_running = true, camera_index = 0) {

camera_bump_y

/// @func	camera_bump_y(frames, distance_x, enqueue_if_running = true, camera_index = 0)
/// @desc	A bump animation vertical
camera_bump_y = function(frames, distance_y, enqueue_if_running = true, camera_index = 0) {

Other Callbacks

The ROOMCONTROLLER holds some additional callbacks which get invoked by raptor, when certain events occur.

The template room controller you get, when you use the raptor room templates already contains empty implementations of these callbacks.

// Invoked, when the transition to this room is finished and
// the scene is visible.
// The _data argument contains the data that has been sent
// when the transition was instantiated in the previous room.
// NOTE: If this room has been entered through the savegame system
// and a transition was specified to enter the room when loading,
// this _data member has been enriched by a "was_loading = true"
// member. With this, you can always distinguish between a "normal"
// enter of the room or an enter caused by game load.
onTransitFinished = function(_data) {
}
// Invoked, when you start loading a game in a different room
// and when this room is the target room of the savegame.
// If something goes wrong during load and object restore,
// this function is invoked.
// The exception has already been written to the error log.
onGameLoadFailed = function(_exception) {
	elog($"**ERROR** Game load failed: {_exception.message}");
}
// Invoked, when the "transit_back" method is called
// _transition_data has these members:
// .cancel (set to true to stay in this room)
// .target_room
// .transition (set a transition to animate room change)
onTransitBack = function(_transition_data) {
}

onTransitFinished Example

Here is an example, how you can detect, whether a room has been entered through the savegame system or "normally".

This is, how you can distinguish between a game load scenario and a fresh startup of a room:

onTransitFinished = function(_data) {
    if (!vsget(_data, "was_loading", false)) {
        // The room has been created normally, not through savegame
        myplayer = instance_create(... ...); // spawn your player
    } else {
        // The game has just been loaded, so your player is likely aready there
    }
}

Fade Out a Room

Sometimes you want the scene to go black animated (fading out), but need to do something before you leave the room.

An example would be, that you need to save your game before leaving the room, but you want to remove all dynamically created objects and all objects that do not need to be saved/persisted (like critters, particle emitters and other things you will create anyways when loading). The player shall not see, that you remove those objects, so you "silently" destroy them while the screen is black.

For this, and similar, scenarios, ROOMCONTROLLER offers a convenience method fade_out. You will receive a callback, as soon as the scene is black. That's the moment, where you can do your hidden things, before moving to another room, saving your game, or whatever you need to do, what the user shall not see.

/// @func	fade_out(_fade_out_frames, _finished_callback)
fade_out = function(_fade_out_frames, _finished_callback) {
⚠️ **GitHub.com Fallback** ⚠️