API reference¶
The scripting API of RedGem games: the classes and methods scripts use. Generated from docs/scripting/api.json, which tests keep in step with the engine.
| Class | What it is |
|---|---|
Behaviour |
A Ruby class attached to an object: the engine calls its methods as the game runs. |
GameObject |
An object of the scene, as scripts see it. |
Transform |
Where an object is, how it is turned and how big it is. |
Vector3 |
A point or a direction in meters: x, y, z. |
Scene |
The objects of the running scene. |
SceneScript |
Sets a level up from Ruby when it loads: scripts/ |
Input |
Keyboard, mouse, gamepad and touch, read every frame. |
Time |
The game's clock (added to Ruby's Time). |
Physics |
Questions to the physics world: rays, moving shapes and shapes in place. |
Joint |
What holds two bodies together, or one to the world (made by Physics.joint). |
CharacterController |
The body of an object with body = "character": walks, jumps, climbs steps. |
Rigidbody |
The body of an object with body = "dynamic" or "kinematic" (or a vehicle's chassis). |
Vehicle |
The body of an object with body = "vehicle" and wheels. |
Camera |
The camera the game is seen through, and what it does on its own: follow, orbit, shake. |
Camera::Orbit |
What Camera.orbit returns: the camera's angles and distance around what it orbits, for scripts to read and change. |
Light |
game_object.light: the light an object shines with. |
Animation |
The scene's own animations (exported from Blender), by name. |
Animator |
game_object.animation (animation in a behaviour): an object's own clips. |
Animation::Graph |
Named states and transitions for one character (animation.use(graph)). |
Audio |
Sounds and music from the game's sounds/ folder. |
UI |
What a script draws over the game this frame: texts, rectangles, pictures, buttons. |
UI::Focus |
Which widget of a screen the keyboard and a gamepad work: up and down move it, wrapping. |
Debug |
Developer diagnostics: console messages, frame timings and immediate world drawing. |
Game |
The game itself. |
Settings |
How the player chose the game to be shown and heard; a change takes effect at once. |
GameMenu |
A behaviour: title screen, pause menu, end screen and settings screen with its controls page; arrows or the D-pad move the focus, Enter or A picks. |
GameMenu::Screen |
A screen of the GameMenu. |
Particles |
Short-lived sparks, smoke and dust. |
Particles::Emitter |
A continuous particle effect attached to an object, returned by Particles.emitter. |
Scatter |
Great numbers of copies of a mesh (grass, trees, rocks), drawn only. |
Save |
What the game keeps between runs. |
HTTP |
Web requests; the answer comes to the block. |
HTTP::Response |
What a web request's block is given. |
I18n |
The game's texts in several languages (locales/*.json). |
Network |
Games played together: on a local network, through a relay or on a dedicated server. |
Network::Decision |
What an authenticate block decides with. |
NetworkSync |
A behaviour: the same object in the same place on every machine. |
Behaviour¶
A Ruby class attached to an object: the engine calls its methods as the game runs. See behaviours.md.
start: called once, before the first updateupdate(dt): called every frame; dt is the seconds since the last onefixed_update(dt): called 60 times a second, with the physicson_trigger_enter(other): something entered this object's trigger, or it entered oneon_trigger_exit(other): something left this object's triggeron_collision_enter(other): this object's body touched anotheron_collision_exit(other): this object's body stopped touching anotheron_destroy: the object is being destroyedgame_object: the object this behaviour is attached toname: the object's nametransform: the object's Transformcharacter: the object's CharacterController, or nilrigidbody: the object's Rigidbody, or nilvehicle: the object's Vehicle, or nilanimation: the object's own Animatorprops: the object's custom properties, as a Hashprop(key, default = nil): a setting: what add_component was given, else the object's property, else the defaultfind(name): the object called name, or nilfind!(name): find that stops with a clear error when the object is missingfind_all(tag): every object with that tagdestroy(target = game_object): removes an object (this one unless said) at the end of the stepget_component(klass): another behaviour of this object, or nilafter(seconds, &block): runs the block once, that many seconds from nowevery(seconds, &block): runs the block every that many secondstween(seconds, ease: :smooth, &block): calls the block with t from 0 to 1 over that many secondscancel_timers: stops every after, every and tween of this behaviour
GameObject¶
An object of the scene, as scripts see it. See behaviours.md.
name: its nameid: its number in the running gamestable_id: its persistent scene-file identity as a String; nil for runtime copiescapture_state: a versioned checkpoint of local pose, tint and visibility, suitable for Saverestore_state(state): validates a checkpoint then restores pose and appearance; teleports physical descendants and returns selftag: its tag propertytag?(value): whether its tag is valueprops: its custom propertiesalive?: false once it was destroyeddestroy: removes it at the end of the stepvisible: whether it is drawnvisible = value: shows or hides itbehaviours: its behavioursparent: the object it is under, or nilchildren: the objects under ittransform: its Transformcharacter: its CharacterController, or nilrigidbody: its Rigidbody, or nilvehicle: its Vehicle, or nillight: the Light it shines with, or nilanimation: its Animatoranimation_offset: seconds its animations run ahead of the original's (a spawned copy)animation_offset = seconds: sets that offsetget_component(klass): one of its behaviours, or niladd_component(klass, **settings): attaches a behaviour; settings are what its prop readstint: the color its colors are multiplied bytint = color: multiplies its colors: [1.0, 0.5, 0.5]
Transform¶
Where an object is, how it is turned and how big it is.
position: its position in the world (Vector3)position = vector: moves it; a physics object is teleportedlocal_position: its position relative to its parentlocal_position = vector: moves it relative to its parentrotation: its rotation, Euler degrees (Vector3)rotation = degrees: turns it to those Euler degreesrotate(degrees): turns it by those Euler degreeslook_at(target, up = Vector3.up): turns it to face a pointtranslate(offset): moves it by an offsetscale: its scale (Vector3)scale = vector: resizes itforward: the direction it faces (-Z)right: its right (+X)up: its up (+Y)
Vector3¶
A point or a direction in meters: x, y, z.
Vector3.new(x, y, z): a vectorVector3[x, y, z]: the same as newVector3.zero: (0, 0, 0)Vector3.one: (1, 1, 1)Vector3.up: (0, 1, 0)Vector3.down: (0, -1, 0)Vector3.left: (-1, 0, 0)Vector3.right: (1, 0, 0)Vector3.forward: (0, 0, -1)Vector3.back: (0, 0, 1)Vector3.blender(x, y, z): a vector given in Blender's axes (Z up)x: its xy: its yz: its z+ other: sum- other: difference-@: the opposite vector* number: scaled/ number: divided== other: whether the numbers are exactly the samedot(other): dot productcross(other): cross productlength: its lengthlength_squared: its length squared (faster)normalized: the same direction, length 1clamped(max_length = 1.0): the same direction, no longer than max_lengthlerp(other, t): the point t of the way to otherflat: the same with y = 0with(x:, y:, z:): a copy with some parts changed: v.with(y: 0)distance_to(other): the distance to another pointapprox?(other, tolerance = 0.0001): whether two vectors are about the sameto_a: [x, y, z]set(x, y, z): changes it in placeadd!(other): adds in placesub!(other): subtracts in placescale!(number): scales in placenormalize!: normalizes in place
== compares the numbers exactly, and equal vectors are one key of a Hash. A vector used as a key must not be changed in place (set, add!...) while the Hash holds it: use a dup as the key. The scene keeps positions, rotations and scales in 32-bit floats, so a vector that goes through it comes back rounded: compare what comes back from the scene with approx?(other, tolerance). The in-place methods change the vector and hand it back: dup one you got from someone else first. Arithmetic whose result would not fit a float, and dividing by zero, raise an ArgumentError; a vector changed in place is then left as it was.
Scene¶
The objects of the running scene. See gameplay.md.
Scene.find(name): the object called name, or nilScene.find_by_id(identity): the current scene object with that persistent String/Symbol identity, or nilScene.find!(name): find that stops with a clear error when the object is missingScene.find_all(tag): every object with that tagScene.objects: every objectScene.spawn(template, position: nil, rotation: nil, physics: true): copies a prefab = true template, with its physics and scripts; returns the copy
SceneScript¶
Sets a level up from Ruby when it loads: scripts/
setup: runs when the level loads, before any behaviour startsfind(name): the object called name, or nilfind!(name): find that stops with a clear error when the object is missingfind_all(tag): every object with that tag
Input¶
Keyboard, mouse, gamepad and touch, read every frame. See gameplay.md.
Input.axis(name): :horizontal or :vertical, from -1 to 1 (keys, stick)Input.down?(key): whether a key is heldInput.pressed?(key): whether a key went down this frameInput.released?(key): whether a key went up this frameInput.action?(name): whether a named action (game settings) is heldInput.action_pressed?(name): whether a named action started this frameInput.action_released?(name, pad: 0): whether a named action ended this frameInput.define_action(name, *bindings, keys: [], buttons: []): adds an action of the game's own (besides game.json's input section)Input.define_axis(name, negative: [], positive: [], pad_axis: nil, invert: false): adds an axis of the game's own: define_axis(:steer, negative: ["key:a"], positive: ["key:d"])Input.actions: the names of the actionsInput.axes: the names of the axesInput.axis_stick(name): the stick that moves an axis (:left_x), the game's for every player; nil when none doesInput.bindings(name, pad: 0): what a player bound to an action: ["key:space", "pad:a"]Input.bindings_changes: a count that goes up whenever actions, axes or bindings may have changedInput.bind(name, binding = nil, key: nil, button: nil, side: nil, pad: 0): binds a key or a button to an action; kept between runsInput.unbind(name, binding = nil, key: nil, button: nil, side: nil, pad: 0): takes a binding off an actionInput.reset_bindings(name = nil, pad: nil): back to the game's own bindings (of one action, or all; of one pad, or all)Input.capture_next(cancel: ["key:escape", "pad:b", "pad:back"], &block): the next key or button pressed, to the block: |binding, pad| (nil: called off)Input.capturing?: whether a capture waits for a keyInput.capturing_for?(block): whether a capture still waits to call that block (not once another took its place)Input.cancel_capture: calls a capture offInput.mouse_x: the pointer's x, in pixelsInput.mouse_y: the pointer's y, in pixelsInput.mouse_dx: how far the mouse moved this frame, acrossInput.mouse_dy: how far the mouse moved this frame, up and downInput.mouse_wheel: how far the wheel turned this frameInput.mouse_down?(button): whether a mouse button (:left, :right, :middle) is heldInput.mouse_pressed?(button): whether a mouse button went down this frameInput.mouse_released?(button): whether a mouse button went up this frameInput.mouse_locked = locked: hides the pointer and keeps it in the window (first-person cameras)Input.mouse_locked?: whether the pointer is lockedInput.pads: the numbers of the gamepads plugged inInput.gamepad?: whether a gamepad is connectedInput.gamepad_axis(axis): :left_x, :left_y, :right_x, :right_y, :left_trigger, :right_triggerInput.gamepad_down?(button): whether a gamepad button (:a, :b, :x, :y...) is heldInput.gamepad_pressed?(button): whether a gamepad button went down this frameInput.gamepad_released?(button): whether a gamepad button went up this frameInput.text: what was typed this frameInput.touch_controls = on: shows the on-screen stick and buttons of a phoneInput.touch_controls?: whether they are shown
Every action, axis, binding and gamepad call takes pad: (0 to 3: the player; 0 when left out). Actions and axes come from game.json's input section and define_action/define_axis; a player's bindings are kept between runs, beside the game's save. See Controls.
Time¶
The game's clock (added to Ruby's Time).
Time.delta: seconds since the last frameTime.unscaled_delta: seconds since the last frame, whatever Time.scale (also while paused)Time.fixed_delta: seconds of a physics step (1/60)Time.elapsed: seconds since the game startedTime.frame: how many frames have runTime.scale: how fast game time runs (1 is normal)Time.scale = value: slows or speeds the game; 0 pauses it
Physics¶
Questions to the physics world: rays, moving shapes and shapes in place. See gameplay.md.
Physics.raycast(origin, direction, max_distance = 1000, skip = nil, layers: nil, ignore: nil): the first thing a ray hits: {object:, point:, normal:, distance:}, or nil (skip: an object it sees through)Physics.raycast_all(origin, direction, max_distance = 1000, layers: nil, ignore: nil): everything a ray hits, nearest firstPhysics.sphere_cast(from, to, radius, layers: nil, ignore: nil): the first thing a ball moving fromfromtototouches, or nilPhysics.box_cast(from, to, size, rotation: nil, layers: nil, ignore: nil): the same for a box (its whole size; rotation in degrees)Physics.capsule_cast(from, to, radius, height, rotation: nil, layers: nil, ignore: nil): the same for an upright capsule (height end to end)Physics.overlap_sphere(center, radius, layers: nil, ignore: nil): the hits of everything inside a ball, nearest firstPhysics.overlap_box(center, size, rotation: nil, layers: nil, ignore: nil): the same inside a boxPhysics.overlap_capsule(center, radius, height, rotation: nil, layers: nil, ignore: nil): the same inside a capsulePhysics.layers: the game's collision layers, as Symbols (game.json's physics layers)Physics.joint(kind, object, other = nil, anchor: nil, other_anchor: nil, axis: nil, limits: nil, motor_speed: nil, motor_torque: nil, min: nil, max: nil, spring: nil, damping: nil, break_force: nil): joins two objects, or one to the world (other nil): :fixed, :hinge, :slider, :point or :distance
layers: is a layer's name or a list of them (every layer when nil); ignore: is an object or a list of objects to see through. Hits are {object:, point:, normal:, distance:}, each object once, nearest first, at most 64; triggers are never hit. A cast that starts inside something hits it at distance 0.
Joint¶
What holds two bodies together, or one to the world (made by Physics.joint). See gameplay.md.
kind: :fixed, :hinge, :slider, :point or :distanceobject: the object it holdsother: the other object it holds, or nil for the worldalive?: whether it still holds thembroken?: whether it was pulled past its break forceremove: lets goenabled?: whether it holds right nowenabled = flag: lets go for a while, or holds againbreak_force: the pull (newtons) or twist (newton meters) it breaks at; 0 never breaksbreak_force = newtons: sets the pull it breaks atmotor(speed, torque): a hinge turns at that speed (degrees per second) with at most that torque; 0 torque lets it goangle: how far a hinge turned from where it started, in degrees
Points and axes are in world space; anchor: defaults to the object's position, other_anchor: (a distance joint's other end) to the other object's, axis: to up. A hinge's limits: are degrees [low, high] from where it starts (low -180 to 0, high 0 to 180), a slider's are meters along its axis; a hinge's motor_speed: needs a motor_torque:. A distance joint keeps between min: (0) and max: (how far apart the ends are) apart, springy with spring: (hertz) and damping:. Each kind refuses options it has no use for, and motor and angle raise for anything but a hinge. A joint needs a dynamic body at one end (one whose bodies were all made kinematic since holds nothing until one is dynamic again); it goes when either object is destroyed or the scene changes.
CharacterController¶
The body of an object with body = "character": walks, jumps, climbs steps. See gameplay.md.
move(velocity): walks with that velocity (m/s) this framejump(speed): jumps up at that speedgrounded?: whether it stands on somethingvelocity: its velocitylayer: its collision layer, a Symbollayer = name: moves it to another collision layer
Rigidbody¶
The body of an object with body = "dynamic" or "kinematic" (or a vehicle's chassis). See gameplay.md.
velocity: its velocityvelocity = vector: sets its velocityadd_impulse(vector): pushes itadd_force(force, at: nil): pushes it during the next step (newtons); at a point (world space), it also turns itadd_torque(torque): turns it during the next step (newton meters)angular_velocity: how fast it spins, degrees per second around each axisangular_velocity = vector: sets how fast it spinsmass: its mass in kilogramsmass = kilograms: changes its mass (more than 0)kinematic?: whether scripts move it (instead of forces)kinematic = flag: turns a dynamic body kinematic, or backdynamic?: whether forces move itdynamic = flag: turns a kinematic body dynamic, or backgravity_scale: how much gravity pulls it (1 is normal)gravity_scale = scale: 0 floats, 2 falls twice as hardsleep: stops simulating it until something touches itwake: simulates it againsleeping?: whether it sleepslayer: its collision layer, a Symbollayer = name: moves it to another collision layer
Forces and torques act during the next physics step only: add them every fixed_update to keep pushing. A body made dynamic again starts at rest. kinematic= and dynamic= raise for a vehicle.
Vehicle¶
The body of an object with body = "vehicle" and wheels. See gameplay.md.
drive(throttle: 0.0, steering: 0.0, brake: 0.0, handbrake: 0.0): drives it this frame (each from -1 or 0 to 1)stop: brakes fullyspeed: its speed in m/s, signedvelocity: its velocity
Wheel meshes must have their rotation applied (the axle along X). drive's inputs are the one setting the engine clamps, since an analog stick may push a little past full.
Camera¶
The camera the game is seen through, and what it does on its own: follow, orbit, shake. See gameplay.md#follow-orbit-and-shake-the-camera.
Camera.main: the object holding the cameraCamera.screen_ray(x, y): [origin, direction] through a pixel of the screenCamera.world_to_screen(point): [x, y]: where a Vector3 (or an object) is on the screen, in the pixels UI draws in; nil behind the cameraCamera.fov: its vertical field of view, in degreesCamera.fov = degrees: sets the field of viewCamera.motion_blur: how much the picture streaks with speed, 0 to 1Camera.motion_blur = amount: sets itCamera.follow(target, offset: [0, 3, 6], relative: false, smoothing: 0.15, look_at: true, look_height: 1.0, avoid_walls: true, dead_zone: 0, snap: true): follows an object from now on: offset in meters (relative: in its own axes), smoothing in seconds to close half the way, in front of walls between; snap: false flies thereCamera.orbit(target, distance: 6, yaw: 0, pitch: 20, distances: 1..30, pitches: -80..80, smoothing: 0.08, input: true, height: 1.0, avoid_walls: true): orbits an object or a point, looking at it, turned by dragging with the right mouse button or the right stick and zoomed by the wheel, also while paused; returns a Camera::OrbitCamera.stop_following: stops following or orbiting; the camera stays where it isCamera.following?: whether it follows or orbits something (an object destroyed is let go)Camera.shake(strength, duration: 0.5): shakes what it shows (never the camera object): strength (0 to 1) adds to its trauma, held at 1, fading over duration secondsCamera.trauma: how much it shakes now, 0 to 1Camera.stop_shaking: stops the shake at once
Camera::Orbit¶
What Camera.orbit returns: the camera's angles and distance around what it orbits, for scripts to read and change. See gameplay.md#follow-orbit-and-shake-the-camera.
yaw: degrees around it, -180 to 180: 0 behind it (its +Z side), 90 on its rightpitch: degrees above itdistance: meters from ittarget: the object or point it orbitsturn(yaw, pitch): turns by degrees (the yaw wraps round, eased the short way), the pitch kept within its rangezoom(meters): comes nearer (negative) or goes further, within its range
Light¶
game_object.light: the light an object shines with. See gameplay.md#light-that-flickers-and-fades.
intensity: watts for a point or spot light, lux for the sunintensity = value: sets it; shows from the next framecolor: its color [r, g, b], 0 to 255color = color: :orange or [r, g, b] from 0 to 255
Animation¶
The scene's own animations (exported from Blender), by name. See animation.md.
Animation.names: the names of the scene's animationsAnimation.play(name, loop: true, speed: 1.0, restart: false): plays oneAnimation.pause(name): pauses oneAnimation.stop(name): stops oneAnimation.playing?(name): whether it playsAnimation.time(name): where it is, in secondsAnimation.duration(name): how long it is, in secondsAnimation.seek(name, seconds): jumps to a moment
Animator¶
game_object.animation (animation in a behaviour): an object's own clips. See animation.md.
play(name, loop: true, speed: 1.0, fade: 0.0, restart: false): plays a clip, fading from the last onemix(name, weight: 1.0, loop: true, speed: 1.0): plays a clip over the one playingunmix: stops the clip mixed overpause: pauses its clipsfollow_scene(fade: 0.0): goes back to the scene's animationsclip: the clip playingplaying?: whether a clip playstime: where the clip is, in secondsuse(graph): installs an Animation::Graphset(parameter, value): sets a parameter of the graphstate: the graph's state, or nil
Animation::Graph¶
Named states and transitions for one character (animation.use(graph)). See animation.md.
Animation::Graph.new(initial:, parameters: {}): a graph starting at a state, with its parameters and their defaultsclip(name, clip, loop: true, speed: 1.0): a state that plays one clipblend_1d(name, parameter:, clips:, loop: true, speed: 1.0): a state that blends clips by a number: clips: [[0.0, :Idle], [5.0, :Run]]blend_2d(name, parameters:, clips:, loop: true, speed: 1.0): a rectangular two-dimensional grid: parameters: [:x, :y], clips: [[[x, y], :Clip], ...]transition(from, to, parameter:, equals: nil, above: nil, below: nil, fade: 0.0): goes from one state to another when a parameter says so
Audio¶
Sounds and music from the game's sounds/ folder.
Audio.play(name, volume: 1.0, pitch: 1.0): plays a sound onceAudio.music(name, loop: true, volume: 0.7): plays musicAudio.stop_music: stops the musicAudio.music_pitch = pitch: changes the music's pitchAudio.music_volume = volume: changes the music's volumeAudio.volume = volume: the volume of everythingAudio.play_at(name, position, loop: false, volume: 1.0, pitch: 1.0, reference_distance: 1.0, max_distance: 50.0): plays a sound at a place in the world; returns its id, or nilAudio.listener(position, forward, up): where the ears are (move it with the camera)Audio.move(id, position): moves a sound played with play_atAudio.playing?(id): whether that sound still playsAudio.stop(id): stops that soundAudio.stop_sources: stops every sound played with play_at
play_at sources use stereo panning and inverse-distance volume, fading to silence at max_distance. volume must be 0 or more and pitch from 0.01 to 8; 0 < reference_distance < max_distance. Positions and directions may be arrays or Vector3. Update Audio.listener(position, forward, up) when the camera moves: nothing follows an object by itself. At most 64 sources play at once; old ids are never reused.
UI¶
What a script draws over the game this frame: texts, rectangles, pictures, buttons. See gameplay.md.
UI.text(str, x:, y:, size:, color:, alpha:, align:): draws a textUI.rect(x:, y:, width:, height:, color:, alpha:, radius:): draws a rectangleUI.image(name, x:, y:, width:, height:): draws a picture of images/UI.button(label, x:, y:, width:, height:): draws a button; true the frame it is clickedUI.text_field(value, x:, y:, width:, height:, max_length:, secret:): a field to type in; returns the new valueUI.width: the width of the screen, in pixelsUI.height: the height of the screen, in pixelsUI.text_width(str, size:): how wide a text is, in pixels (in the face selected)UI.toggle(label, on, x:, y:, width:, height:, focused: false): an on/off row of a settings screen; returns whether it is onUI.choice(label, choices, index, x:, y:, width:, height:, focused: false): a row that picks one of choices; returns the index chosenUI.slider(label, value, x:, y:, width:, height:, min: 0.0, max: 1.0, step: 0.05, focused: false): a row with a slider; returns the valueUI.font: the face texts are drawn with: a file name of fonts/, or nil for the built-in oneUI.font = name: draws the next texts with fonts/.ttf or .otf (nil: the built-in face)
A focused widget (focused: true) is worked by Enter or a gamepad's A, and left and right change it. The built-in face adds glyphs as they are asked for (Greek, Cyrillic, accented letters, €); for another face or script, put a .ttf or .otf in fonts/ and set UI.font. A missing or unreadable face falls back to the built-in one, with a warning; glyphs a face lacks show as ?; there is no bidirectional layout or complex-script shaping.
UI::Focus¶
Which widget of a screen the keyboard and a gamepad work: up and down move it, wrapping. See gameplay.md.
UI::Focus.new: a focus on the first widgetupdate(count): moves it among count widgets, as up or down was pressed this frameat?(index): whether the widget of that index has it: pass it as focused:move_to(index): puts it on a widget (one clicked, or the one a screen comes back to)index: the widget that has itreset: back to the first widget
Debug¶
Developer diagnostics: console messages, frame timings and immediate world drawing.
Debug.log(message): says somethingDebug.warn(message): warnsDebug.error(message): reports an errorDebug.profiling?: whether foreground frame timings are being collectedDebug.profiling = enabled: starts a fresh profile window when enabled; disabling retains the last summaryDebug.stats_visible?: whether the developer statistics overlay was requestedDebug.stats_visible = visible: shows frame timings and FPS; showing also enables profiling, hiding leaves collection runningDebug.frame_stats: a snapshot with samples, fps and latest/mean/peak timings in millisecondsDebug.reset_frame_stats: clears statistics and discards any unfinished measurementDebug.line(from, to, color: :green, alpha: 255, depth_test: true): draws a world-space line for this frame; returns whether it was acceptedDebug.box(center, size, color: :green, alpha: 255, depth_test: true): draws an axis-aligned wire box with full nonnegative size for this frame; returns whether it was accepted
Profiling is off by default. The overlay uses the shared game HUD, including editor Play and recordings; it is hidden when profiling is off. Timings use the real steady clock, independently of Time.scale or fixed-step replay. The most recent 120 completed frames form the window; reads during a frame expose only completed frames. FPS uses completion-to-completion intervals, and is zero until an interval is available. latest, mean and peak contain frame_ms, interval_ms, has_interval, and input_ms, network_ms, http_ms, update_ms, physics_ms, presentation_ms, scene_ms. Input includes pending script startup; network and HTTP include their callbacks; update includes animations, scripts, particles, loading UI and physics. Physics includes fixed-update callbacks, body synchronization and contacts, so its time overlaps update. Presentation includes uploads, drawing and any frame-cap or synchronization waits. Scene includes request polling, synchronous reads and activation; the asynchronous worker is not instrumented, while offline fixed-step waits count as scene wall time. These are foreground wall times, not GPU timers or CPU utilization. Phase times are inclusive and must not be summed as a partition. Overlay timings and captures are nondeterministic; leave the overlay off for reproducible pictures. Debug.line and Debug.box use world coordinates and live for one frame: submit from ready/update/fixed_update. At most 4096 commands are accepted per frame; later calls return false. They are local-only and return false without a presenter, while still validating arguments. depth_test: false draws through objects. Shape frames use unjittered rendering and reset temporal history; normal temporal sampling resumes afterwards. Native windows allocate one cached color/depth target only when shapes are requested; editor, scaled and recorded views reuse their target. If that extra native target is unavailable, the game still draws with a warning and the shapes are omitted.
Game¶
The game itself. See gameplay.md#a-loading-screen.
Game.load_scene(name): switches to scenes/.glb ("main" is scene.glb); Ruby globals survive Game.load_scene_async(name): queues a background scene read; the old world survives failed reads and cancellationGame.loading?: a scene request is queued or being readGame.loading_scene: the requested scene name, or nilGame.loading_error: the last asynchronous read error, or nil; cleared by the next load requestGame.cancel_scene_load: cancels a pending asynchronous request; returns whether one was pendingGame.on_loading(&block): draws the loading screen each frame with unscaled delta; no block restores the defaultGame.scene_name: the scene runningGame.title: the game's titleGame.quit: ends the gameGame.stop_recording: ends a video recorded with --record; the game goes onGame.version: the version in game.json ("1.2.0"), or nil
While an asynchronous read is pending, physics, animations and normal behaviour callbacks pause.
Input, networking, HTTP callbacks, audio and presentation continue. The loading callback can use
UI, handle cancel buttons and animate using its unscaled delta; Time.delta is zero during
loading. The pointer is released while the screen is shown. The default screen draws a translated
loading label over the old world. A callback error is reported once and disables it for that load.
Unsafe names are rejected immediately; missing or unreadable files are reported through
Game.loading_error after the request runs. The old world stays intact if reading fails or is cancelled. The most recent request wins;
Game.load_scene also supersedes an asynchronous request. Globals survive successful activation,
but the old scene's loading callback is removed before the next scene's setup runs. Errors are
reported through Game.loading_error and the event log. At most eight background requests/results can be
outstanding across the process, using one shared reader; a full queue fails without changing the
world. Cancelling an active read discards its result; it does not interrupt the file parser.
Only file reading and glTF parsing happen on the worker. Physics creation, script setup, texture decoding and GPU upload still happen on the owning thread and may hitch during activation. The old and incoming scene coexist in memory during reading. Fixed-step offline runs (including recordings and scripted replays) wait for the reader before advancing, then show exactly one loading frame before activation so completion does not depend on thread scheduling. Networked runs and dedicated-server rooms keep the background reader even in fixed-step mode; activation still runs on the server loop and can stall other rooms sharing that loop. Closing the process waits for an active parser to return.
Settings¶
How the player chose the game to be shown and heard; a change takes effect at once. See ../shipping.md#notes.
Settings.window_mode: :windowed, :fullscreen or :borderlessSettings.window_mode = mode: changes itSettings.fullscreen?: whether the game fills the screenSettings.fullscreen = on: fullscreen, or back to a windowSettings.resolution: [width, height] of the window, in pixelsSettings.resolution = size: resizes the window: one of resolutionsSettings.resolutions: the sizes the monitor offers: [[w, h], ...]Settings.render_scale: the share of the window's size the world is drawn at (0.5 to 2)Settings.render_scale = scale: changes itSettings.vsync: whether frames wait for the screenSettings.vsync = on: changes itSettings.fps_cap: frames a second at most; nil for noneSettings.fps_cap = cap: changes itSettings.quality: :low, :medium, :high, :ultra or :customSettings.quality = quality: the most a level's environment gets of what it asks forSettings.quality_details: what the custom quality allows: {msaa:, antialias:, shadow_cascades:, ...}Settings.quality_details = details: changes some of them, and makes the quality :customSettings.volume: the player's volume, 0 to 1 (it multiplies Audio.volume)Settings.volume = volume: changes itSettings.save: keeps them for the next runs; false where they last for the run only
Until the player chooses, everything is what game.json says. Settings.save keeps them only in a built game a player plays: in the editor's Play, redgem run, a server's rooms and tests they last for the run, and save returns false.
GameMenu¶
A behaviour: title screen, pause menu, end screen and settings screen with its controls page; arrows or the D-pad move the focus, Enter or A picks. See gameplay.md#pause-and-the-flow-between-screens.
GameMenu.instance: the menu of the scene, or nilshow(screen): opens a screen: :title, :pause, :over, :settings or one of the game'sshow_settings: opens the settings screen (window, resolution, quality, volume...; its Controls button opens the controls page)resume: closes the menu and goes onrestart: starts the scene againfinish(message): opens the end screen with a messageopen?: whether the menu is openscreen: the screen openscreens: the screens, by name (:title, :pause, :over, :settings, :controls and the game's own)button_box(index): where the menu's button of that index is: [x, y, width, height]
GameMenu::Screen¶
A screen of the GameMenu. See gameplay.md#pause-and-the-flow-between-screens.
GameMenu::Screen.new(heading:, options:, back:): a screen with a heading and options: [[label, action], ...]add_option(label, index:, &action): adds an optionheading: its headingheading = text: changes its headingoptions: its optionsback: the screen Esc goes back toopened: called when it is shownclosed: called when it is leftdraw(first_button): draws what else it showsspace_above: pixels kept between its heading and its buttonstyping?: whether letters are typed into itrows: how many widgets it draws above its buttons that take the focusfirst_button_share: where its first button sits, a share of the height (nil: the menu's)focus: its UI::Focus, which the menu gives itfocus = focus: sets it
Particles¶
Short-lived sparks, smoke and dust. See gameplay.md#sparks-dust-and-smoke.
Particles.burst(position, count:, color:, alpha:, glow:, lit:, cast_shadow:, soft:, direction:, spread:, speed:, life:, size:, gravity:, image:, frames:, fps:, spin:): adds particles; returns how many (size, color and alpha may be lists over their life)Particles.emitter(object, rate: 24, offset: Vector3.zero, **settings): starts a continuous local effect; returns a Particles::Emitter handle; uses burst settings except countParticles.count: how many are aliveParticles.clear: removes all particles and stops every emitter
Emitters follow game time and stop on object destruction or scene changes. They are local visual effects, not replicated. Without a presenter, creation returns an inactive handle and no emitter is allocated or simulated. Births follow ordinary movement; movement over 10 meters per update starts them at the destination. Up to 256 emitters fairly share 4096 live particles; missed births are dropped.
Particles::Emitter¶
A continuous particle effect attached to an object, returned by Particles.emitter. See gameplay.md#sparks-dust-and-smoke.
active?: whether this emitter is still emitting from a live objectstop: stops new births; existing particles finish their lives
Scatter¶
Great numbers of copies of a mesh (grass, trees, rocks), drawn only. See ../levels.md#grass-forests-and-cities.
Scatter.place(template, count:, area:, ground: nil, seed: 0, scale: 1.0, align: false, tints:, tint_variation:, fade:, normals_up:, lods:): places copies; returns a set (count, remove)Scatter.clear: removes every setcount: how many copies a set placedremove: removes a set
Save¶
What the game keeps between runs. See online-services.md#saving-on-a-server.
Save.get(key, default = nil): a value, or the defaultSave.set(key, value): keeps a value (nil removes it)Save[key]: the same as getSave[key] = value: the same as setSave.update(key, default = nil, &block): reads and writes a key with nothing in betweenSave.delete(key): removes a keySave.clear: removes everythingSave.keys: every keySave.slot: the selected save slot name; default keeps the existing save fileSave.slot = name: selects a named slot for this engine; default restores the original storeSave.slots: sorted names of persisted slots and slots opened in this run, including default
Values are numbers, texts, true/false, Vector3, and arrays and hashes of those; hashes come back with string keys. Named slots start on default for every engine and keep their selection across scenes. Selection is local to each engine, including shared-database server rooms. Names are 1–48 lowercase ASCII letters/digits, hyphens or underscores, starting with a letter/digit. At most 64 named stores may be opened per run/local backend and 4096 names listed; invalid names or unavailable backends leave selection unchanged and raise a Ruby error. The existing default file/table is preserved. Named files use their own atomic writes/backups; SQLite uses separate slot tables. Save.update writes to its entry store even if its block selects another slot. Slots keep values, not object-state snapshots or migration metadata.
HTTP¶
Web requests; the answer comes to the block. See online-services.md#http.
HTTP.get(url, headers: {}, timeout: 15, &block): GETHTTP.post(url, json: nil, body: nil, headers: {}, timeout: 15, &block): POSTHTTP.put(url, json: nil, body: nil, headers: {}, timeout: 15, &block): PUTHTTP.patch(url, json: nil, body: nil, headers: {}, timeout: 15, &block): PATCHHTTP.delete(url, headers: {}, timeout: 15, &block): DELETEHTTP.request(verb, url, json: nil, body: nil, headers: {}, timeout: 15, &block): any verb
HTTP::Response¶
What a web request's block is given. See online-services.md#http.
ok?: whether it came back with a 2xx statusstatus: its statusheaders: its headersbody: its bodyjson: its body read as JSONerror: why there was no answer, or nil
I18n¶
The game's texts in several languages (locales/*.json). See i18n.md.
I18n.t(key, **values): the text of a key in the language in use, its {placeholders} filledI18n.locale: the language in use (:en)I18n.locale = language: changes the languageI18n.available_locales: the languages of the game's locales/ files
Network¶
Games played together: on a local network, through a relay or on a dedicated server. See multiplayer.md.
Network.host(port: 7777, name: nil, visible: true, room: false): hosts a gameNetwork.join(address = nil, port: 7777, room: nil, auth: nil): joins a game (an address, or a room code)Network.leave: leaves the gameNetwork.online?: whether this machine is in a gameNetwork.connecting?: whether a join is on its wayNetwork.host?: whether this machine hostsNetwork.server?: whether this machine is a dedicated serverNetwork.id: this machine's peer idNetwork.peers: the peers of the gameNetwork.players: the peers without a dedicated serverNetwork.port: the port of the gameNetwork.room: the room code, on a relayNetwork.relay: the relay's addressNetwork.relay = address: sets the relay's addressNetwork.search: looks for games on the local networkNetwork.searching?: whether it is lookingNetwork.stop_search: stops lookingNetwork.games: the games foundNetwork.discovery_port: the port games are looked for onNetwork.discovery_port = port: changes itNetwork.emit(name, data = nil, to: :all): sends a message (:all, :host or a peer id)Network.on(name, &block): receives a message: |data, from|Network.on_connect(&block): this machine is in the gameNetwork.on_disconnect(&block): the game is goneNetwork.on_join(&block): someone arrived: |peer|Network.on_leave(&block): someone left: |peer|Network.on_fail(&block): a join did not work out: |reason|Network.authenticate(&block): decides who gets in: |peer, auth, decide|Network.identity(peer): who a peer was accepted asNetwork.player_name(peer): a peer's nameNetwork.spawn(template, owner: Network.id, position:, rotation:): spawns a copy on every machineNetwork.allow_spawn(*templates): lets guests spawn those templates
Network::Decision¶
What an authenticate block decides with. See online-services.md.
accept(identity:, name: nil): lets the peer indeny(reason = "not let in"): keeps the peer out
NetworkSync¶
A behaviour: the same object in the same place on every machine. See multiplayer.md#objects-in-the-same-place-everywhere.
mine?: whether this machine owns itowner: the peer that owns itowner = peer: gives it to a peerkey: the name it is known by on every machineassign(owner:, key:): sets its owner and key
Notes¶
Script errors are logged with a backtrace and only disable the failing behaviour; the game keeps running. Every method takes finite numbers a float can hold: infinity, NaN or a number too large raises an ArgumentError instead of reaching the scene. A setting with a range raises outside it and says the range; nothing is quietly clamped, except Vehicle#drive's inputs. Assigning transform.position to a physics object teleports it (moving bodies also stop); changing its rotation keeps its velocity. Images may be PNG, JPEG or static WebP (a name without an extension looks for .webp last), at most 8192 pixels a side; animated WebP and KTX2/Basis are not read. Missing or unreadable images (scene textures, UI.image, particle images) show an opaque magenta-and-black checkerboard, with a warning; a material that never named a texture keeps its plain color, and no path reads outside the game's folder.