← GameCrom Studio

GAMECROM 2D STUDIO

Scripting Reference

Learn how to program your games with JavaScript. Explore the GameCrom API, execution lifecycle, objects, components, properties, events and practical examples.

1. Create and assign a script

Each project has a folder scripts. You can create, edit, rename and delete scripts from the Scripts tab in the bottom panel. Each object can have a script assigned from the Inspector. The same script can be assigned to several objects.

Use Refresh, on the right side of the Scripts tab, after creating, deleting or renaming a file directly in VS Code or File Explorer. When you use Rename inside the editor, GameCrom renames the file and automatically updates its assignments in objects, saved scenes and prefabs.

  1. Select an object in the scene or in the hierarchy.
  2. In the Inspector look for the component Script or open the tab Scripts.
  3. Click Create to create a new one or choose an existing one.in File.
  4. Click Edit to open it in Visual Studio Code.
  5. Press Play to run the script.

Scripts only run in Play. When you exit Play, the scene returns to the editing state.

Prefabs

A prefab is a reusable template of an object. It is used to save a scene object with its properties and its children, and then create new copies when you need them.

  1. Select the object you want to convert into a prefab.
  2. Open the tab Prefabs in the lower panel.
  3. Click Create From Selection.
  4. Write the name of the prefab andcommit.
  5. Use Instantiate to create a copy of the prefab in the scene.
  6. Use Delete to delete the prefab file from the project.

The prefab list displays a thumbnail of the root object. If the object has texture, the image is seen;if not, a shape is displayed with its color.

In the top bar of the editor, Snap preserves step scrolling. The check Snap to Grid snaps the top left corner of the object directly onto the grid.

Prefabs are saved inside the project's prefabs folder. When instantiating one, the engine creates new objects with new IDs so as not to modify the original prefab or step on objects in the scene.

It is savedDetail
Root objectName, tag, position, scale, rotation, color, texture, collision, visibility and Static.
ChildrenThe complete hierarchy hanging from the selected object.
ScriptThe reference to the script assigned to the object.
AnimationThe assigned animation and its playback options.
ParticlesThe systemof particles assigned and its options.
ComponentsComponents added to the object, such as Audio Source, Parallax or Character Controller.

At the moment the prefab works as a reusable template. If you edit the instantiated object in the scene, those changes belong to that copy. They are not automatically applied to the saved prefab.

2D Lights

You can create an object Light from Add GameObject. In Play it is not drawn as a normal sprite: it illuminates the scene with a radial light on the canvas. Light objects do not display Sprite Renderer nor Collider 2D because they are not physical objects or game sprites. Light only affects the layers below it in the drawing order;Objects placed above are drawn later and are not illuminated by that light.

PropertyUse
EnabledActivates or deactivates the light.
Light ColorColor of the light.
RadiusRange of light in world pixels.
IntensityLight strength, from 0 a 1.
OpacityGlobal transparency of light, from 0 a 1.
SoftnessEdge smoothing, from 0 a 1.
EffectLight animation: None, Torch, Candle, Alarm, Fluorescent or Pulse.
Effect SpeedSpeed of theeffect. 0 leaves the light practically fixed.
Effect AmountAmount of intensity variation of the effect.
Radius AmountAmount of radius variation during the effect.
Effect ColorSecondary color used by effects such as Alarm and Pulse.

The effects are animated duringPlay. Torch and Candle simulate organic flicker, Alarm alternates towards a secondary color, Fluorescent creates small cuts of intensity and Pulse breathes gently. The Play button on the component allows you to preview the effect in the editor without launching the game.

Crop sprites

The trimmer is used to separate a large texture that contains many mixed sprites, such as a sprite sheet. Slices are saved as new PNG textures within the project.

  1. Open the tab Slice Sprite from the bottom panel.
  2. Choose the source texture.
  3. Set Cell W and Cell H with the size of each sprite.
  4. Adjusts Offset X/Y if the sheet has an outside margin.
  5. Adjusts Spacing X/Y if there is separation between sprites.
  6. Use Columns and Rows to limit the area, or leave 0 to calculate it automatically.
  7. Click Save Slices to save each slice as a new texture.

The original texture is not modified. If Empty is disabled, fully transparent clippings are skipped.

2. Execution cycle

A script can export loop functions. They all receive the object assigned to the script. If you do not declare a function, it is simply not called.

FunctionWhen calledParameters
start(object)Once when entering Play.object: object that owns the script.
fixedUpdate(object, fixedDeltaTime)At a fixed pace, 60 times per second if performance allows.Movementstable, physics and pushes.
update(object, deltaTime)Every frame during Play.Input, normal logic, visual movement and UI.
lateUpdate(object, deltaTime)At the end of the frame, after update and collisions.Camera, UI dependent on final positions and final settings.
export function start(object) {
    debug("Empieza: " + object.name);
}

export function fixedUpdate(object, fixedDeltaTime) {
    // Fixed step: ideal for physics.
}

export function update(object, deltaTime) {
    object.x += 100 * deltaTime;
}

export function lateUpdate(object, deltaTime) {
    // Runs after every update in the frame has finished.
}

3. The object received

The parameter object is the actual scene object during Play. You can read its data and change properties such as position, rotation, scale, color, opacity or active state.

export function start(object) {
    debug({
        id: object.id,
        name: object.name,
        tag: object.tag,
        x: object.x,
        y: object.y
    });
}

If you want to see everything that an object has, you can send it completely to the console:

export function start(object) {
    debug(object);
}

4. Variable handling

In scripts you can create normal JavaScript variables. Depending on where you save them, they last only within a function, they belong to an object, the current scene or the entire project game.

Common types

TypeExampleUse
numberlet vida = 100;Numbers, speed, time,punctuation.
stringlet estado = "idle";Text, names, states.
booleanlet vivo = true;True/false values.
objectlet datos = { vida: 100 };Group data.
arraylet inventario = [];Lists of values.

Local variables

They live only within the function where they are created. They are lost when that call ends.

export function update(object, deltaTime) {
    const speed = 120;
    object.translate(speed * deltaTime, 0);
}

Script variables

If you create them outside of start and update, they are preserved while that script is loaded in Play. If the same script is assigned to multiple objects, that variable is shared between them.

let totalUpdates = 0;

export function update(object, deltaTime) {
    totalUpdates += 1;
    debug(totalUpdates);
}

Local variables of an object

To save data for a specific object, create your own properties within object. Each object will have its own values.

export function start(object) {
    object.vida = 100;
    object.velocidad = 180;
}

export function update(object, deltaTime) {
    object.translate(object.velocidad * deltaTime, 0);
}

Global scene variables

Use Scene.vars for data shared by all scripts in the current scene. It resets when you enter Play and also when you load another scene with Scene.load.

export function start(object) {
    Scene.vars.enemigos = Scene.vars.enemigos || 0;
    Scene.vars.enemigos += 1;
}

Global project variables

Use Project.vars for data that must survive changing scenes during the same game, such as score, lives or progress.

export function start(object) {
    Project.vars.score = Project.vars.score || 0;
}

export function update(object, deltaTime) {
    Project.vars.score += 1;
    debug("Score: " + Project.vars.score);
}

Data saved with PlayerPrefs

Use PlayerPrefs for saving data that must continue to exist even if you close the game, such as record, options, volume, coins or the last levelunlocked. The data is saved separately by project.

Project.vars it is deleted when you exit Play. PlayerPrefs it stays saved in the browser/Tauri until you delete the key or call PlayerPrefs.deleteAll().

FunctionUseExample
PlayerPrefs.setString(key, value)Save text.PlayerPrefs.setString("playerName", "Alex")
PlayerPrefs.getString(key, defaultValue)Read text.PlayerPrefs.getString("playerName", "Player")
PlayerPrefs.setNumber(key, value)Save a number.PlayerPrefs.setNumber("volume", 0.8)
PlayerPrefs.getNumber(key, defaultValue)Read a number.PlayerPrefs.getNumber("volume", 1)
PlayerPrefs.setInt(key, value)Save an integer.PlayerPrefs.setInt("coins", 25)
PlayerPrefs.getInt(key, defaultValue)Read an integer.PlayerPrefs.getInt("coins", 0)
PlayerPrefs.setBool(key, value)Save true/false.PlayerPrefs.setBool("music", true)
PlayerPrefs.getBool(key, defaultValue)Readtrue/false.PlayerPrefs.getBool("music", true)
PlayerPrefs.setJSON(key, value)Saves objects or arrays.PlayerPrefs.setJSON("inventory", ["key"])
PlayerPrefs.getJSON(key, defaultValue)Reads objects or arrays.PlayerPrefs.getJSON("inventory", [])
PlayerPrefs.hasKey(key)Checks if a key exists.PlayerPrefs.hasKey("record")
PlayerPrefs.deleteKey(key)Deletes a key.PlayerPrefs.deleteKey("record")
PlayerPrefs.deleteAll()Deletes all saved data from the current project.PlayerPrefs.deleteAll()
PlayerPrefs.keys()Returns saved keys from the current project.PlayerPrefs.keys()
PlayerPrefs.save()Exists forcompatibility. In this engine the saving is immediate.PlayerPrefs.save()

Example: save record

export function start(object) {
    Project.vars.score = 0;
    Project.vars.record = PlayerPrefs.getInt("record", 0);
}

export function update(object, deltaTime) {
    Project.vars.score += Math.round(10 * deltaTime);

    if (Project.vars.score > Project.vars.record) {
        Project.vars.record = Project.vars.score;
        PlayerPrefs.setInt("record", Project.vars.record);
    }

    debug({
        score: Project.vars.score,
        record: Project.vars.record
    });
}

Example: save options

export function start(object) {
    const volume = PlayerPrefs.getNumber("volume", 1);
    const fullscreen = PlayerPrefs.getBool("fullscreen", false);

    debug({ volume, fullscreen });
}

export function update(object) {
    if (Input.getKeyDown("M")) {
        PlayerPrefs.setNumber("volume", 0);
    }

    if (Input.getKeyDown("F")) {
        const current = PlayerPrefs.getBool("fullscreen", false);
        PlayerPrefs.setBool("fullscreen", !current);
    }
}

Available Mathematics

Scripts can directly use the standard Math JavaScript object. The engine also includes the APIs Random, Mathf and Vector2.

Current operationExample
Minimum, maximum and absolute valueMath.min(a, b), Math.max(a, b), Math.abs(x)
RoundingMath.floor(x), Math.ceil(x), Math.round(x)
Powers and rootMath.pow(x, 2), Math.sqrt(x)
2D distanceMath.hypot(dx, dy)
Angles andtrigonometryMath.atan2(y, x), Math.sin(x), Math.cos(x)
SignMath.sign(x)
Random between 0 and 1Math.random()
const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
const lerp = (a, b, t) => a + (b - a) * t;
const randomRange = (min, max) => min + Math.random() * (max - min);

API Random

FunctionUseExample
Random.value()Decimal between 0 included and 1 excluded.Random.value()
Random.range(min, max)Decimal between the two values.Random.range(10, 20)
Random.int(min, max)Integer between min and max, including both.Random.int(1, 6)
Random.choose(array)Random elemento null if the array is empty.Random.choose(["red", "blue"])
Random.chance(probability)Returns true with a probability between 0 and 1.Random.chance(0.25)
Random.sign()Randomly returns -1 or 1.Random.sign()
Random.shuffle(array)Returns a shuffled copy without modifying the original array.Random.shuffle(cards)
export function start(object) {
    object.x = Random.range(100, 700);
    object.vida = Random.int(2, 5);
    object.color = Random.choose(["#ff0000", "#00ff00", "#0088ff"]);

    if (Random.chance(0.2)) {
        debug("Enemigo especial");
    }
}

Mathf works with numbers and angles. Vector2 returns new objects { x, y };does not modify the received vectors.

Mathf API

Mathf.clamp(value, min, max)Limits a value.
Mathf.clamp01(value)Limits between 0 and 1.
Mathf.lerp(a, b, t)Interpolates using t between 0 and 1.
Mathf.inverseLerp(a, b, value)Calculates the ratio of value between a and b.
Mathf.moveTowards(current, target, step)Narrows a number withoutexceed it.
Mathf.repeat(value, length)Repeats a value within an interval.
Mathf.pingPong(value, length)Oscillates between 0 and length.
Mathf.degToRad(degrees), radToDeg(radians)Converts angles.
Mathf.deltaAngle(a, b)Smallest signed angular difference.
Mathf.lerpAngle(a, b, t)Interpolates along the shortest angular path.

Vector2 API

Vector2.create(x, y)Creates a vector.
Vector2.add(a, b), subtract(a, b)Add or subtract.
Vector2.multiply(v, scalar), divide(v, scalar)Scale a vector.
Vector2.length(v)Length.
Vector2.distance(a, b)Distance betweenpoints.
Vector2.normalize(v)Length vector 1.
Vector2.dot(a, b)Scalar product.
Vector2.angle(a, b)Angle in degrees.
Vector2.lerp(a, b, t)Interpolates two vectors.
Vector2.moveTowards(a, b, distance)Zooms one point closer to another.
const direction = Vector2.normalize({
    x: enemy.x - object.x,
    y: enemy.y - object.y
});

object.translate(direction.x * 120 * deltaTime, direction.y * 120 * deltaTime);

5. Object movement

During Play objects have useful methods to move and orient themselves. These methods return the object itself, so you can chain them if that's comfortable for you.

MethodUseExample
object.translate(x, y)Moves the object in its local coordinates.player.translate(10, 0)
object.lookAt(target, eje)Rotates the object facing another object or point using the indicated axis.player.lookAt(enemy, "x")
object.moveTowards(target, speed, deltaTime)Moves the object toward a target.player.moveTowards(target, 150, deltaTime)
export function update(object, deltaTime) {
    object.translate(100 * deltaTime, 0);
}
export function update(object, deltaTime) {
    const enemy = FindByTag("Enemy");
    if (!enemy) return;

    object.lookAt(enemy, "x");
    object.moveTowards(enemy, 120, deltaTime);
}

lookAt and moveTowards accept an object or point as { x: 100, y: 50 }. In lookAt, the default axis is "x". You can also use "-x", "y" or "-y". For example, if your sprite is facing up, use object.lookAt(enemy, "-y").

6. Object Hierarchy

During Play you can check and change parent/child relationships. When changing parents, the engine tries to maintain the visual position of the object in the world.

MethodUseExample
object.addChild(child)Makes another object a child of this object.player.addChild(gun)
object.removeChild(child)Removes a direct child and leaves it without a parent.player.removeChild(gun)
object.parent()Returns the parent of the object or null.const p = gun.parent()
object.root()Returns the root object of the hierarchy.const root = gun.root()
object.children()Returns an array with the direct children.const hijos = player.children()
object.destroyAllChildren(tiempo)Destroys all direct children, immediately or after a while.player.destroyAllChildren(1)
export function start(object) {
    const gun = FindByName("Gun");
    if (!gun) return;

    object.addChild(gun);
}
export function update(object, deltaTime) {
    for (const child of object.children()) {
        debug(child.name);
    }
}
export function start(object) {
    object.destroyAllChildren(2);
}

addChild does not allow creating hierarchy loops. For example, you cannot make an object a child of one of its own descendants.

7. Object properties

These are the main properties that you can read and modify from a script.

PropertyTypeUseExample
idstring/numberUnique identifier of the object.debug(object.id)
namestringName visible in the editor.object.name = "Player"
tagstringLabel to search for objects by category.object.tag = "Enemy"
parentIdstring/nullParent IDin the hierarchy.debug(object.parentId)
typestringVisual type: square or circle.debug(object.type)
activebooleanTurns the object on or off.object.active = false
isStaticbooleanMarks the object as static for future optimizations.object.isStatic = true
visibleInPlaybooleanControls whether it is visible during Play.object.visibleInPlay = true
x, ynumberLocal position of the object.object.x += 10
w, hnumberBase size of the object.object.w = 80
rotationnumberRotation in degrees.object.rotation += 90 * deltaTime
scaleX, scaleYnumberHorizontal scale andvertical.object.scaleX = 2
znumberVisual order layer.object.z = 5
colorstringColor in hexadecimal format.object.color = "#ff0000"
opacitynumberOpacity between 0 and 1.object.opacity = 0.5
texturestringName of the assigned texture.object.texture = "player.png"
textureTilingX, textureTilingYnumberRepetition of the texture.object.textureTilingX = 2
textureOffsetX, textureOffsetYnumberOffset of the texture.object.textureOffsetX += deltaTime
textureFlipX, textureFlipYbooleanFlip thetexture.object.textureFlipX = true
pixelPerfectbooleanRender of texture with a pixel art look.object.pixelPerfect = true
animationstringAssigned animation ID.debug(object.animation)
animationPlayingbooleanActivates or pauses the animation.object.animationPlaying = true
animationRunInPlaybooleanIndicates if the animation starts in Play.object.animationRunInPlay = true
particleSystemstringID of the assigned particle system.debug(object.particleSystem)
particlesPlayingbooleanActivates or pauses particles.object.particlesPlaying = true
particlesRunInPlaybooleanIndicates if the particles start in Play.object.particlesRunInPlay = true
particlesDetachedbooleanAllows the particle trailis separated from the object.object.particlesDetached = true
collisionEnabledbooleanMarks the collider as active.object.collisionEnabled = true
isTriggerbooleanMarks the collider as trigger.object.isTrigger = true
colliderobjectCollider data: shape, offsetX/Y, width/height and radius.object.collider.shape = "capsule"
scriptstringName of the assigned script.debug(object.script)

If an object has isStatic = true, it is recommended not to move it, rotate it, scale it or change its hierarchy during Play. This flag is used so that the engine can optimize rendering, collisions, navigation and other systems in the future.

Activation cycle: if active es false, the components, collisions and object script are not executed. It also applies when one of its parents is inactive. If activated after starting the scene, start(object) is then executed only once and before the first update(object, deltaTime). Automatic components, such as Audio Source / Play On Start, start when activated.

8.debug API

Messages appear in the tab Console from the bottom panel of the editor.

FunctionUseExample
debug(value)Displays any value.debug("Hola")
Debug.log(value)Normal message.Debug.log(object.name)
Debug.warn(value)Warning message.Debug.warn("Vida baja")
Debug.error(value)Error message.Debug.error("No hay objetivo")
Debug.clear()Clears the console.Debug.clear()
export function start(object) {
    Debug.log({ nombre: object.name, posicion: { x: object.x, y: object.y } });
}

9. You wait with Wait

Wait allows you to pause an asynchronous function, similar to a coroutine. To use it, the function must be declared with async.

FunctionUseExample
await Wait.seconds(segundos)Wait a number of seconds.await Wait.seconds(0.2)
await Wait.frames(frames)Wait a number of frames.await Wait.frames(1)
export async function start(object) {
    object.color = "#ff0000";
    await Wait.seconds(0.2);
    object.color = "#ffffff";
}
export async function start(object) {
    debug("3");
    await Wait.seconds(1);
    debug("2");
    await Wait.seconds(1);
    debug("1");
}

Property animations with Tween

Tween smoothly change numeric properties during Play. It is used to move, rotate, scale or fade objects without programming the interpolation within update. Duration and delays are expressed in seconds.

FunctionUseExample
Tween.to(target, values, duration, options)Animates from the current values to those indicated.Tween.to(object, { x: 400 }, 1)
Tween.from(target, values, duration, options)Places the initial values and animates up to those the object had.Tween.from(object, { opacity: 0 }, 0.5)
Tween.cancel(target)Cancels all tweens of an object.Tween.cancel(object)
Tween.cancel(target, property)Cancels only the tweens of a property.Tween.cancel(object, "x")
Tween.cancelAll()Cancels all tweensactive.Tween.cancelAll()
Tween.isTweening(target, property)Checks if there is an active tween.Tween.isTweening(object, "x")
Tween.pauseAll()Pauses all tweens.Tween.pauseAll()
Tween.resumeAll()Resume all tweens.Tween.resumeAll()
export function start(object) {
    Tween.to(object, {
        x: object.x + 240,
        rotation: 360,
        scaleX: 2,
        scaleY: 2
    }, 1.5, {
        ease: "cubicInOut",
        yoyo: true,
        repeat: 1
    });
}

Available options: ease, delay, repeat, repeatDelay, yoyo, paused, overwrite, onStart, onUpdate, onRepeat, onComplete and onCancel. By default, a new tween cancels previous tweens that modify the same properties of the same object. Use overwrite: false to allow them.

Curves included: linear, easeIn, easeOut, easeInOut, quadIn, quadOut, quadInOut, cubicIn, cubicOut, cubicInOut, backIn, backOut, sineIn, sineOut and sineInOut.

export async function start(object) {
    const movement = Tween.to(object, { y: object.y - 100 }, 0.8, {
        ease: "backOut"
    });

    const result = await movement;
    debug(result.status); // "completed" or "cancelled"
}

The return value allows pause(), resume(), cancel() and complete(). You can also wait directly with await. Tweens are automatically canceled when you exit Play, destroy your object or change scenes.

Tween only interpolates numerical properties. If a physical component or a script modifies the same property at the same time, both systems will compete for the value.

10. Find objects

FunctionReturnsExample
FindByName(name)The first object with that name or null.FindByName("Player")
FindByTag(tag)The first object with that tag or null.FindByTag("Enemy")
FindAllByName(name)Array with all active objects that have that name.FindAllByName("Coin")
FindAllByTag(tag)Array with all active objects that have that tag.FindAllByTag("Enemy")
FindAllByComponent(type)Array of active objects with that component.FindAllByComponent("PhysicsBody")
FindAllInArea(x, y, w, h)Active objects whose limits overlap with the indicated rectangle.FindAllInArea(0, 0, 800, 600)
export function start(object) {
    const player = FindByName("Player");

    if (player) {
        debug("Player found at X: " + player.x);
    }
}
export function update(object, deltaTime) {
    const target = FindByTag("Target");
    if (!target) return;

    object.x += Math.sign(target.x - object.x) * 80 * deltaTime;
}

Temporary groups

Groups allows you to gather objects during Play without changing their name, tag or hierarchy. Groups are automatically emptied when changing scenes.

Groups.create(name, objects)Creates a group and adds an optional list.
Groups.add(name, object)Adds an object.
Groups.remove(name, object)Removes an object.
Groups.get(name)Returns valid members.
Groups.has(name, object)Checks if it belongs to the group.
Groups.forEach(name, callback)Executes a function for eachmember.
Groups.setActive(name, active)Activates or disables all its members.
Groups.clear(name)Empties the group.
Groups.delete(name)Deletes the group.
Groups.names()Returns all group names.
export function start(object) {
    const enemies = FindAllByTag("Enemy");
    Groups.create("wave", enemies);
}

export function update(object) {
    if (Input.getKeyDown("K")) {
        Groups.setActive("wave", false);
    }
}

11. Destroy objects

FunctionUseExample
Destroy(object)Destroys an object instantly.Destroy(enemy)
Destroy(object, tiempo)Destroys an object after a few seconds.Destroy(object, 2)

If you destroy an object that has children, its children are also destroyed. Destroy should only be used during Play.

export function start(object) {
    Destroy(object, 3);
}
export function update(object, deltaTime) {
    const enemy = FindByTag("Enemy");

    if (enemy && enemy.x < -500) {
        Destroy(enemy);
    }
}

Instantiate prefabs from code

Prefab allows you to create copies of prefabs during Play. The prefab must exist in the Prefabs tab of the project.

FunctionUseExample
await Prefab.instantiate(nombre)Creates a copy of the prefab.await Prefab.instantiate("Enemy")
await Prefab.instantiate(nombre, opciones)Creates a copy with position, name or parent.await Prefab.instantiate("Bullet", { x: 100, y: 40 })
await Prefab.create(nombre, opciones)Alias ​​of instantiate.await Prefab.create("Coin")
await Prefab.spawn(nombre, opciones)Alias ​​of instantiate.await Prefab.spawn("Explosion")

If the prefab has a single root object, the function returns that object. If the prefab has multiple root objects, it returns a list. The prefab scripts are loaded and start running in Play.

OptionTypeDescription
xnumberX position of the root object.
ynumberY position of the root object.
offsetXnumberDisplacement X if you do not indicate x e y.
offsetYnumberDisplacement Y if you do not indicate x e y.
namestringBase name for the created copy.
parentobjectObject that will be the parent of the instantiated prefab.
rotationnumberInitial rotation of the root object.
scaleXnumberInitial X scale of the root object.
scaleYnumberInitial Y scale of the root object.
export async function start(object) {
    const enemy = await Prefab.instantiate("Enemy", {
        x: object.x + 120,
        y: object.y,
        name: "EnemySpawned"
    });

    debug(enemy.name);
}
export async function start(object) {
    await Wait.seconds(1);

    const bullet = await Prefab.instantiate("Bullet", {
        x: object.x + 32,
        y: object.y,
        parent: object
    });

    bullet.translate(10, 0);
}

Prefab.instantiate it is only used during Play and requires Tauri to read the prefab saved in the project.

Prefab Pool

Pool preloads inactive copies and reuses them. It is recommended for bullets, enemies, coins and explosions that appear many times.

await Pool.create(name, prefab, size)Creates the pool and preloads the indicated amount.
await Pool.spawn(name, { x, y })Obtains and activates a copy. If none remain, expands the default pool.
Pool.release(object)Deactivates and returns the object to its pool.
Pool.releaseAll(name)Returns all active members.
Pool.get(name)Returns size, active, and available.
Pool.has(name)Checks if it exists.
Pool.clear(name)Deregisters the pool.
export async function start(object) {
    await Pool.create("bullets", "Bullet", 32);
}

export async function update(object) {
    if (Input.getKeyDown("Space")) {
        const bullet = await Pool.spawn("bullets", {
            x: object.x + 24,
            y: object.y
        });
        Physics.setVelocity(bullet, 500, 0);
    }
}

export function recycleBullet(bullet) {
    Pool.release(bullet);
}

Pools are temporary and are cleared when changing pools.scene. Use Pool.release instead of Destroy to return a scratchable instance.

12. Load scenes

Scene.load loads a project scene by name. During Play it keeps the game running, switches to the new scene and starts the scripts for the objects in that scene.

FunctionUseExample
await Scene.load(nombre)Loads a scene by name.await Scene.load("Level1")
await Scene.load(nombre, opciones)Allows a fade transition.await Scene.load("Boss", { transition: "fade", duration: 0.4 })
await Scene.reload()Reloads the current scene.await Scene.reload()
await Scene.preload(nombre)Reads and prepares a scene to speed up the next load.await Scene.preload("Boss")
Scene.currentScene namecurrent.debug(Scene.current)
Scene.getCurrent()Returns the name of the current scene.Scene.getCurrent()
Scene.onLoad(callback)Registers a function when finishing a load and returns a function to cancel it.Scene.onLoad(name => debug(name))
Scene.onUnload(callback)Registers a function before leaving the scene.Scene.onUnload(name => debug(name))
export async function start(object) {
    await Wait.seconds(2);
    await Scene.load("Level1");
}

Fade Transition

You can pass options as a second parameter. With transition: "fade", the screen fades to black, the engine changes the scene when it is already covered and then gradually shows the new scene. Use duration to indicate the seconds of each phase of the fade.

export async function update(object) {
    if (object.x > 800) {
        await Scene.load("Level2", {
            transition: "fade",
            duration: 0.4
        });
    }
}

Use await to wait until the charge and fade have finished. If you omit duration, 0.3 seconds are used. Without options, the change is immediate: await Scene.load("Level2").

export async function update(object, deltaTime) {
    if (object.x > 800) {
        await Scene.load("NextLevel");
    }
}

The name must match an existing scene in the project. Do not write the file extension. Scene.vars, groups and pools are reset when changing scenes.

13. Animations API

Sprite and Property Animations

The editor separates the two systems so that they do not mix. The tab Animations Contains exclusively Sprite clips with textures and FPS. The Timeline tab contains exclusively Property clips organized by tracks and keyframes.

To create a property clip open Timeline and press New Property. Then assign that clip from the field Animation Timeline of the Object Inspector. Timeline automatically uses that object as a Target Object;It is not selected within the editor. The name and ID always indicate which object is being edited. Choose a track and place the cursor on the desired time. Press Add/Update Key to capture the current value of the object. Modify the object, move the time and add another key;the engine will interpolate the values ​​between both.

To assign it to an object use the field Animation Timeline of the Timeline Animator section of the Inspector. The field Animation is reserved exclusively for Sprite animations. When you open the Timeline tab with that object selected, the editor loads its assigned clip and allows you to view it with Play.

TrackAnimated property
Position X / YLocal position x e y.
RotationRotation of the object in degrees.
Scale X / YScale independent of each axis.
OpacityInterpolated opacity of the object.
ColorInterpolated color between two keys.
  • Duration defines the total duration of the clip in seconds.
  • Target Object automatically shows the object that has the clip assigned in its field Animation Timeline.
  • Local Position checked applies the offset of the clip from the initial position of each object;unchecked uses the absolute X/Y values ​​of the clip.
  • The Timeline panel docks at the bottom of the editor to keep the scene visible while you transform the object.
  • The red line is the playhead: it indicates the current instant and advances along the tracks during preview.
  • Play plays from the current time, Pause and Stop preserve the position, and Rewind returns to the start.
  • The playback controls preserve the zoom and the visible area of ​​the Timeline.
  • Activate Follow Playhead so that the horizontal view automatically follows the red line during playback.
  • When you move the cursor, the position, scale, rotation, opacity and color of the target object are updated live.
  • Closing Timeline, changing tabs or entering Play automatically restores the stateoriginal.
  • Loop repeat the clip continuously.
  • Pingpong plays back and forth when Loop is active.
  • Tap a diamond to select its timing.
  • Drag a diamond horizontally with the mouse to change the timing of that keyframe and preview the result.
  • Select a diamond and press Duplicate Key to copy it 0.10 seconds later.
  • Use Zoom - and Zoom + to compress or horizontally expand the Timeline between 50% and 400%.
  • Right click on a diamond to delete that key.

Property clips are assigned and played from the Inspector the samethan Sprite clips. They also work with the same API Animations and are included in the exported game.

Control from scripts

Animations allows you to assign and control animations from a script. You can use the ID or the name of the animation.

FunctionUseExample
Animations.find(nombreOId)Search for an animation.Animations.find("Run")
Animations.assign(object, nombreOId)Assign an animation to the object.Animations.assign(object, "Run")
Animations.play(object)Play the assigned animation.Animations.play(object)
Animations.play(object, nombreOId)Assign and play an animation.Animations.play(object, "Jump")
Animations.stop(object)Stop the animation.Animations.stop(object)
Animations.enable(object)Enable it to start automatically onPlay.Animations.enable(object)
Animations.disable(object)Deactivates automatic start and stops it.Animations.disable(object)
Animations.activate(object)Alias ​​of enable.Animations.activate(object)
Animations.deactivate(object)Alias ​​of disable.Animations.deactivate(object)
export function start(object) {
    Animations.assign(object, "Idle");
    Animations.play(object);
}
export async function start(object) {
    Animations.play(object, "Hit");
    await Wait.seconds(0.5);
    Animations.play(object, "Idle");
}

14. Particle API

Particles allows you to assign and control particle systems from a script. You can use the system ID or name.

FunctionUseExample
Particles.find(nombreOId)Searches for a particle system.Particles.find("Explosion")
Particles.assign(object, nombreOId)Assigns particles to the object.Particles.assign(object, "Smoke")
Particles.play(object)Plays the assigned particles.Particles.play(object)
Particles.play(object, nombreOId)Assigns and plays particles.Particles.play(object, "Explosion")
Particles.stop(object)Stops the particles.Particles.stop(object)
Particles.enable(object)Activates automatic start in Play.Particles.enable(object)
Particles.disable(object)Disables automatic start andstops.Particles.disable(object)
Particles.activate(object)Alias ​​of enable.Particles.activate(object)
Particles.deactivate(object)Alias ​​of disable.Particles.deactivate(object)
export function start(object) {
    Particles.assign(object, "Smoke");
    Particles.play(object);
}
export async function start(object) {
    Particles.play(object, "Explosion");
    await Wait.seconds(1);
    Destroy(object);
}

15. Complete examples

Move an object

export function update(object, deltaTime) {
    object.x += 120 * deltaTime;
}

Rotate constantly

export function update(object, deltaTime) {
    object.rotation += 180 * deltaTime;
}

Blink changing opacity

let time = 0;

export function update(object, deltaTime) {
    time += deltaTime;
    object.opacity = 0.5 + Math.sin(time * 8) * 0.5;
}

Follow the player

export function update(object, deltaTime) {
    const player = FindByName("Player");
    if (!player) return;

    const speed = 90;
    object.x += Math.sign(player.x - object.x) * speed * deltaTime;
    object.y += Math.sign(player.y - object.y) * speed * deltaTime;
}

Eliminate enemies by tag

export function start(object) {
    const enemy = FindByTag("Enemy");

    if (enemy) {
        Destroy(enemy, 1.5);
    }
}

Change scene after a wait

export async function start(object) {
    debug("Cargando siguiente nivel...");
    await Wait.seconds(1);
    await Scene.load("Level2");
}

Follow Camera

The Play camera can automatically follow an object by tag. In the left panel Scene > Camera, activate Follow Player and choose the tag of the object you want to follow, for example Player.

PropertyUse
Follow PlayerActivate camera tracking during Play.
TagTag of the object that the camera will follow. The list comes from the scene tags.
Dead Zone X/YDead zone before moving the camera. It is used so that the character can move a little without dragging the camera.
SmoothTracking response between 0 and 1. 0 does not move the camera, 1 follows immediately.
Lock X/YLocks the tracking on one axis.
Offset X/YMoves the tracking point with respect to the center of the object.
BoundsLimits the camera within aworld rectangle with min/max X/Y.
EffectVisual filter applied only during Play: None, Scanlines, CRT, Noir, Sepia or Dream.
FXIntensity of the effect between 0 and 1.
Scanline SizeSeparation of the lines when you use Scanlines or CRT.
VignetteGently darkens the edges of the camera.
NoiseAdds light old screen type noise. It is also activated with CRT.

Backgrounds with component Parallax use this camera when they do not have a manual target. That's why the parallax moves naturally when activating Follow Player.

Camera API

Camera allows you to move the game camera from scripts during Play. If Follow Player is active, tracking can move it again in the next frame;use { disableFollow: true } when you want to place it manually.

FunctionUseExample
Camera.moveTo(x, y)Moves the top left corner of the camera to a position in the world.Camera.moveTo(400, 120)
Camera.setPosition(x, y)Alias ​​of moveTo.Camera.setPosition(0, 0)
Camera.centerOn(x, y)Centers the camera on a point in the world.Camera.centerOn(player.x, player.y)
Camera.getPosition()Returns { x, y } with the current position of the camera.const pos = Camera.getPosition()
Camera.getRect(margen)Returns the visible camera rectangle with optional margin.const rect = Camera.getRect(32)
Camera.isObjectOutside(object, margen)Indicates whether the entire object is out of camera. The optional margin enlarges the rectangle.Camera.isObjectOutside(enemy, 64)
object.isOutsideCamera(margen)Direct method of the object to know if it left the camera.object.isOutsideCamera(64)
await Camera.fadeOut(tiempo, color)Darks the camera until it is covered with the indicated color. The default color is black.await Camera.fadeOut(1)
await Camera.fadeIn(tiempo, color)Remove the fade color and show the scene again.await Camera.fadeIn(0.8, "#000")
await Camera.fade(tipo, tiempo, color)Generic function. tipo can be "in" or "out".await Camera.fade("out", 1, "black")
Camera.cutToBlack(color)Instant color cut, default black.Camera.cutToBlack()
Camera.clearFade()Remove any active fade instantly.Camera.clearFade()
export function start(object) {
    Camera.moveTo(0, 0, { disableFollow: true });
}

export function update(object) {
    const player = FindByTag("Player");
    if (player && Input.getKeyDown("C")) {
        Camera.centerOn(player.x, player.y, { disableFollow: true });
    }
}

Detect camera output

export function update(object) {
    object.translate(300 * deltaTime, 0);

    if (object.isOutsideCamera(64)) {
        Destroy(object);
    }
}

Fade for scene change

export async function start(object) {
    await Camera.fadeOut(1, "#000000");
    await Scene.load("Level2");
    await Camera.fadeIn(1, "#000000");
}

16. UI Canvas

The user UI is drawn inside the game canvas. In the editor it is placed inside the camera rectangle and in Play it appears as Screen Space Overlay, above the scene and without moving with the world camera.

From Add GameObject you can create: UI Canvas, UI Panel, UI Text, UI Image, UI Button, UI Input, UI Checkbox, UI Select, UI Progress Bar and UI Slider.

ControlUse
UI PanelBackground or visual container. UI children are placed relative to the panel in Play.
UI TextText for punctuation, messages, names or labels.
UI ImageImage from Textures or color block if no image is assigned. Does not use text or font.
UI ButtonInteractive button. It has normal color, color Hover on hover, and color Pressed while pressed. From script you can hear click with UI.onClick.
UI InputEditable field during Play. On mobile it automatically opens the system virtual keyboard.
UI CheckboxInteractive true/false value. Has color Hover on hover.
UI SelectHTML select style drop-down list. In Play it opens its options, highlights the option under the pointer, allows you to choose one and fires UI.onChange when changing. If there are too many options, it shows a scroll bar.
UI Progress BarNon-interactive bar for life, energy, charge or experience. Uses Value, Min, Max and color Fill.
UI SliderInteractive numerical value control. In Play you can drag and shoot UI.onChange.

The UI uses Rect Transform: Anchor, Pivot, X/Y offset, size and order Z. To create windows, make a UI Panel and put texts, buttons, inputs, checks, selects, sliders or bars as children in the hierarchy. Anchor works as a preset: by choosing Center, Top Right, Bottom, etc.the control is placed in that zone, sets its Pivot and leaves the X/Y offset at zero. Then you can move it with X/Y as a margin from that anchor. In Play, UI children are drawn on top of their parent even if they have a smaller Z. All controls have Opacity. The field Font allows you to choose Arial or any font imported into Fonts. Controls with text have Align and V Align to align the text left, center, right, top, middle or bottom. UI Text can activate Multiline to work as a block of text: accept line breaks with \n, Word Wrap, Line Height, Max Lines and Overflow in mode Clip, Visible or Ellipsis. UI objects can also carry a Script just like any other object: they receive start(object) and update(object, deltaTime) only during Play. In UI Select, options are edited in the Inspector as a list: you can add, delete, and change each option separately. Visible Rows controls how many options are seen before scrolling and Row Height allows you to adjust the height of each row of the dropdown. UI Panel and UI Button have Corner Radius to round edges.

UI API

FunctionUseExample
UI.find(name)Search for a UI object by name.UI.find("ScoreText")
UI.show(target)Show and activate a control.UI.show("PausePanel")
UI.hide(target)Hide a control in Play.UI.hide("PausePanel")
UI.setText(target, text)Change the textvisible.UI.setText(score, "100")
UI.getValue(target)Read input, checkbox, select, slider, progress bar or text.UI.getValue("VolumeSlider")
UI.setValue(target, value)Change the internal value.UI.setValue("MusicCheck", true)
UI.setRange(target, min, max, value)Change range and value of slider or progress bar.UI.setRange("HealthBar", 0, 100, 75)
UI.setImage(target, texture)Change the texture of a UI image.UI.setImage(icon, "coin.png")
UI.setButtonColors(target, normal, hover, pressed)Change the normal, hover and button pressed colors.UI.setButtonColors("PlayButton", "#1f8fff", "#2fb0ff", "#0d4f9a")
UI.clear(target)Clearthe value of an input.UI.clear("NameInput")
UI.onClick(target, fn)Listen for button clicks.UI.onClick(button, fn)
UI.onChange(target, fn)Listen for input, checkbox, select or slider changes.UI.onChange(slider, fn)
export function start(object) {
    const score = UI.find("ScoreText");
    const button = UI.find("StartButton");

    UI.setText(score, "Score: 0");

    UI.onClick(button, () => {
        Scene.load("Level1");
    });
}
// UI Text multiline.
export function start(object) {
    UI.setText("DialogText", "Linea 1\nLinea 2\nLinea 3");
}
// Script assigned directly to a UI Button.
export function start(object) {
    UI.onClick(object, () => {
        debug("Boton pulsado");
    });
}
// Progress Bar: display the player's health.
let vida = 100;

export function start(object) {
    const healthBar = UI.find("HealthBar");
    const healthText = UI.find("HealthText");

    UI.setRange(healthBar, 0, 100, vida);
    UI.setText(healthText, `Vida: ${vida}`);
}

export function update(object, deltaTime) {
    const healthBar = UI.find("HealthBar");
    const healthText = UI.find("HealthText");

    // Example: health decreases gradually.
    vida = Math.max(vida - 5 * deltaTime, 0);

    UI.setValue(healthBar, vida);
    UI.setText(healthText, `Vida: ${Math.round(vida)}`);
}
// Slider: display the value in a UI Text.
export function start(object) {
    const slider = UI.find("VolumeSlider");
    const valueText = UI.find("VolumeValueText");

    UI.setRange(slider, 0, 100, 50);
    UI.setText(valueText, "Volumen: 50");

    UI.onChange(slider, () => {
        const value = Math.round(UI.getValue(slider));
        UI.setText(valueText, `Volumen: ${value}`);
    });
}

17. Components

Components add extra behavior or data to an object. Select an object, click Add Component in the Inspector and find the component you want to add.

Audio Source

Audio Source play project sounds from an object. Its parameters are: sound, volume, pitch, loop, play on start and enabled.

The project sounds are loaded into memory when opening/refreshing the project. Audio Source does not hot-load sounds during Play;if a sound is not preloaded, an error will be displayed.

PropertyUse
SoundImported sound file in the Sounds tab.
VolumeVolume between 0 and 1.
PitchPitch and speed between 0.1 and 4. Less than 1 sounds lower and slower;More than 1 sounds higher and faster. The value 1 preserves the original sound.
LoopRepeat the sound automatically.
Play On StartPlay the sound when entering Play.
EnabledTurns the component on or off.

AudioSource API

FunctionUseExample
AudioSource.get(object)Returns the Audio Source component of the object.AudioSource.get(object)
await AudioSource.play(object)Plays the sound.assigned.await AudioSource.play(object)
AudioSource.pause(object)Pauses the current playback.AudioSource.pause(object)
AudioSource.stop(object)Stops and returns to the start.AudioSource.stop(object)
AudioSource.isPlaying(object)Indicates if it is playing.AudioSource.isPlaying(object)
AudioSource.setSound(object, sound)Change the sound.AudioSource.setSound(object, "jump.wav")
AudioSource.setVolume(object, volume)Change the volume.AudioSource.setVolume(object, 0.5)
AudioSource.getPitch(object)Returns the current pitch.AudioSource.getPitch(object)
AudioSource.setPitch(object, pitch)Changes speed and pitch between 0.1 and 4.AudioSource.setPitch(object, 1.5)
AudioSource.setLoop(object, loop)Turns loop on or off.AudioSource.setLoop(object, true)
AudioSource.setEnabled(object, enabled)Turns the component on or off.AudioSource.setEnabled(object, false)
export async function start(object) {
    AudioSource.setVolume(object, 0.7);
    AudioSource.setPitch(object, 1.2);
    await AudioSource.play(object);
}

export function update(object) {
    if (Input.getKeyDown("Space")) {
        AudioSource.play(object);
    }
}

Audio Effect

Audio Effect processes the sound of the Audio Source that is on the same object. Multiple Audio Effects can be added: the engine connects them in the same order they appear in the component list.

The object requires an Audio Source. For example, you can chain Filter → Delay → Reverb. On low-power equipment it is advisable to limit the number of reverbs and delays that play simultaneously.

EffectParametersCommon use
ReverbMix, Duration and DecayRooms, caves, halls and large spaces.
Delay / EchoMix, Delay Time and FeedbackEchoes and repetitions. High feedback produces more repetitions.
FilterLow/High/Band Pass, Frequency, Resonance and MixSound underwater, behind walls, radios or phones.
DistortionAmount and MixEngines, weapons, impacts and saturated sound.
Stereo PanPan from -1 to 1 andMixPlaces the sound to the left or right.
PitchPitch from 0.1 to 4Change speed and pitch;1 preserves the original sound.

Audio Effect API

FunctionUse
AudioEffect.getAll(object)Returns all effects in chain order.
AudioEffect.get(object, index)Returns an effect by its index, starting at 0.
AudioEffect.setEnabled(object, index, enabled)Turns an effect on or off.
AudioEffect.setMix(object, index, mix)Toggles the dry/process mix between 0 and 1.
AudioEffect.setReverb(object, index, options)Configure duration, decay and mix.
AudioEffect.setDelay(object, index, options)Configure time, feedback and mix.
AudioEffect.setFilter(object, index, options)Configure type, frequency, resonance and mix.
AudioEffect.setDistortion(object, index, amount, mix)Configure distortion.
AudioEffect.setPan(object, index, pan)Configure pan between -1 and 1.
AudioEffect.setPitch(object, index, pitch)Configure pitch between 0.1 and 4.

Example: delayand reverb

export function start(object) {
    // First Audio Effect: Delay.
    AudioEffect.setDelay(object, 0, {
        time: 0.25,
        feedback: 0.35,
        mix: 0.25
    });

    // Second Audio Effect: Reverb.
    AudioEffect.setReverb(object, 1, {
        duration: 1.8,
        decay: 2.2,
        mix: 0.4
    });

    AudioSource.play(object);
}

export function update(object) {
    if (Input.getKeyDown("R")) {
        AudioEffect.setEnabled(object, 1, false);
    }
}

Direct push on objects

To apply force you don't need to add Physics Body manually. You can call these functions directly from the object and the engine will create the physical component automatically if necessary.

FunctionUseExample
object.addForwardForce(amount, axis)Pushes the object where it is facing. axis indicates which axis of the sprite is the front.object.addForwardForce(500, "x")
object.addForce(x, y)Applies force in a specific direction.object.addForce(0, -650)
object.setGravity(enabled, scale)Activates/disables gravity. Create Physics Body if missing.object.setGravity(false)
object.forward(axis)Returns the frontal vector of the object.object.forward("-y")

Add Physics Body in the editor only when you want to configure mass, drag, bounce, friction, gravity or axis lock visually.

Example: Asteroids type ship

For a shiptype Asteroids, disables gravity and applies thrust in the direction the ship is facing. If you want it to not speed up infinitely, add Physics Body in the editor and go up a little Drag.

export function start(object) {
    object.setGravity(false);
}

export function update(object, deltaTime) {
    if (Input.getKey("ArrowLeft")) {
        object.rotation -= 180 * deltaTime;
    }

    if (Input.getKey("ArrowRight")) {
        object.rotation += 180 * deltaTime;
    }

    if (Input.getKey("ArrowUp")) {
        // Use "x" if the sprite faces right by default.
        // Use "-y" if the sprite faces up by default.
        object.addForwardForce(520 * deltaTime, "x");
    }
}

Bouncy Ball

Bouncy Ball turn an object into a ball type Pong or Arkanoid. No need Physics Body: Uses its own internal velocity and bounces against colliders in the scene.

When adding this component, the engine activates Collision, disables Trigger and marks the object as no Static. Use colliders on walls, paddles, blocks and boundaries so the ball can bounce.

PropertyUse
EnabledTurns the component on or off.
Start On PlayIf active, the ball starts moving when entering Play.
SpeedSpeed ​​of the ball in pixels per second.
AngleInitial exit direction in degrees. 0 right, 90 down, -90 up and 180 left.
Constant SpeedMaintains the same speed after each bounce.

Bouncy Ball API

FunctionUseExample
BouncyBall.get(object)Returns the Bouncy Ball component.BouncyBall.get(ball)
BouncyBall.setSpeed(object, speed)Change the speed.BouncyBall.setSpeed(ball, 420)
BouncyBall.getSpeed(object)Returns the current speed.BouncyBall.getSpeed(ball)
BouncyBall.launch(object, angle, speed)Throws the ball with angle and speedoptional.BouncyBall.launch(ball, -45, 360)
BouncyBall.stop(object)Stops the ball.BouncyBall.stop(ball)
object.setBouncySpeed(speed)Direct version from the object.object.setBouncySpeed(500)
object.launchBouncy(angle, speed)Launches the ball from the object itself.object.launchBouncy(-45, 360)

Example: Pong ball or Arkanoid

Creates a ball, adds the component Bouncy Ball and activates Start On Play. Then place colliders on the walls, the shovel and the blocks. For Pong it usually works well to go out diagonally. For Arkanoid you can relaunch it from below when you lose a life.

// Ball script
export function start(object) {
    // Launch upward and to the right.
    object.launchBouncy(-45, 360);
}

export function update(object) {
    // Relaunch the ball during testing.
    if (Input.getKeyDown("R")) {
        object.launchBouncy(-45, 360);
    }

    // Increase speed gradually.
    if (Input.getKeyDown("Space")) {
        const speed = BouncyBall.getSpeed(object);
        BouncyBall.setSpeed(object, speed + 40);
    }
}

Example: Arkanoid Shovel

The shovel only needs to move and have Collision active. The ball will bounce off it because the Bouncy Ball component manages its own direction after the collision.

// Paddle script
export function update(object, deltaTime) {
    const speed = 420;

    if (Input.getKey("A") || Input.getKey("ArrowLeft")) {
        object.translate(-speed * deltaTime, 0);
    }

    if (Input.getKey("D") || Input.getKey("ArrowRight")) {
        object.translate(speed * deltaTime, 0);
    }
}

Waypoint Move

Waypoint Move moves an object following a list of world points. It is used for patrols, platforms, flying enemies, cameras, moving decorations or any object that must travel a route during Play.

In the editor, when you select the object, you will see the points WP and the route arrows. The component only moves the object during Play.

PropertyUse
SpeedSpeed in pixels per second.
LoopWhen it reaches the end it starts again.
Ping PongTraverses the route forward and then back.
RandomChooses the next waypoint at random, avoiding repeating the current point when there is more than one.
Move Points With ObjectWhen moving the object in the editor, it moves all itswaypoints for the same distance. It is useful to relocate the object and its complete path at once. It works by dragging the object and changing its X/Y values ​​in the inspector;does not modify movement during Play.
Rotate To TargetRotates the object facing the waypoint it is moving to.
Flip XInverts the texture at X when the object moves left and restores it when moving right.
Flip YInverts the texture at Y when the object moves up and restores it when moving down.
Pause Min/MaxGeneral random pause between points.
Waypoint P Min/P MaxSpecific random pause for that point.
Rotation OffsetSet in degrees if the sprite does not face right by default.
Arrive DistanceDistance at which the object is considered to have already arrived.

To reposition an entire patrol, activate Move Points With Object before moving the object. Disable it if you want to change the initial position of the object without moving the path.

Waypoint Move API

FunctionUseExample
WaypointMover.get(object)Returns the component.WaypointMover.get(enemy)
WaypointMover.setSpeed(object, speed)Change the speed.WaypointMover.setSpeed(enemy, 180)
WaypointMover.setLoop(object, loop, pingPong)Change loop and optionally ping pong.WaypointMover.setLoop(enemy, true, true)
WaypointMover.setRandom(object, random)Activate or disable random mode.WaypointMover.setRandom(enemy, true)
WaypointMover.setRotateToWaypoint(object, enabled, offset)Activate rotation towards the target.WaypointMover.setRotateToWaypoint(enemy, true, 0)
WaypointMover.setFlip(object, flipX, flipY)Activate automatic flip according to direction.WaypointMover.setFlip(enemy, true, false)
WaypointMover.setPause(object, min, max)Change general random pause.WaypointMover.setPause(enemy, 0.2, 1)
WaypointMover.setWaypoints(object, points)Replace the entire path.WaypointMover.setWaypoints(enemy, points)
WaypointMover.addWaypoint(object, x, y)Add a point forcode.WaypointMover.addWaypoint(enemy, 400, 120)
WaypointMover.clearWaypoints(object)Delete the route.WaypointMover.clearWaypoints(enemy)
WaypointMover.goTo(object, index)Force the next waypoint.WaypointMover.goTo(enemy, 2)
WaypointMover.pause(object, seconds)Pause temporarily.WaypointMover.pause(enemy, 2)
WaypointMover.resume(object)Resume movement.WaypointMover.resume(enemy)
WaypointMover.reset(object)Restart the cycle.WaypointMover.reset(enemy)
object.setWaypointSpeed(speed)Direct version from the object.object.setWaypointSpeed(200)
object.goToWaypoint(index)Direct version to change target.object.goToWaypoint(1)

Example: patrol with pingpong

export function start(object) {
    WaypointMover.setWaypoints(object, [
        { x: 100, y: 200, pauseMin: 0.2, pauseMax: 0.5 },
        { x: 360, y: 200, pauseMin: 0.2, pauseMax: 0.5 },
        { x: 360, y: 320, pauseMin: 0.8, pauseMax: 1.2 }
    ]);

    WaypointMover.setLoop(object, true, true);
    WaypointMover.setSpeed(object, 120);
}

Example: enemy choosing random points

export function start(object) {
    WaypointMover.setRandom(object, true);
    WaypointMover.setPause(object, 0.3, 1.4);
    WaypointMover.setRotateToWaypoint(object, true, 0);
}

Example: changing movement during Play

export function update(object) {
    if (Input.getKeyDown("1")) {
        object.goToWaypoint(0);
    }

    if (Input.getKeyDown("2")) {
        object.goToWaypoint(1);
    }

    if (Input.getKeyDown("Space")) {
        object.pauseWaypointMover(1);
    }

    if (Input.getKeyDown("R")) {
        object.resumeWaypointMover();
        object.setWaypointSpeed(220);
    }
}

Pathfinding Agent

Pathfinding Agent turns an object into an agent capable of automatically finding and following a path around colliding objects. It is useful for enemies that chase the player, NPC, strategy units or characters that must reach a point without crossing walls.

Add the component from Add Component > Pathfinding Agent. The active colliders form the obstacles;objects marked as triggers do not block the route. Activate Debug Path to see the route in magenta during Play in the editor.

PropertyUse
Target ModeSearch for the destination by tag, by name or use fixed coordinates.
Target Tag / NameTag or name of the object that the agent must pursue.
Destination X/YFixed destination when the selected mode is Position.
SpeedMovement speed in pixels per second.
Cell SizeSize of each search cell. A small value gives more accurate routes, but requires more calculation.
PaddingAdditional margin around obstacles to avoid brushing against them.
Arrive DistanceDistance at which the destination is considered reached.
Repath IntervalSeconds between recalculations while the target moves. Lowering it improves the reaction and increases CPU work.
Max NodesLimit of cells that a search can explore.
DiagonalAllows paths and diagonal movement.
Rotate To TargetOrients the object in the direction of movement.
Flip X/YAutomatically inverts the sprite according to the direction.
Rotation OffsetCorrects the orientation if the sprite is not facing right.by default.

Pathfinding Agent API

FunctionUse
PathfindingAgent.get(object)Returns the object component.
PathfindingAgent.setEnabled(object, enabled)Enables or disables the agent.
PathfindingAgent.setTarget(object, target)Makes it chase a specific object.
PathfindingAgent.setDestination(object, x, y)Switches to Position mode and searches for those coordinates.
PathfindingAgent.setSpeed(object, speed)Change the speed.
PathfindingAgent.pause(object)Pauses movement without deleting the destination.
PathfindingAgent.resume(object)Resume and recalculate the route.
PathfindingAgent.stop(object)Stops the agent and deletes its current route.
PathfindingAgent.recalculate(object)Forces a new route calculation.
PathfindingAgent.hasPath(object)Indicates if an active route exists.
PathfindingAgent.hasArrived(object)Indicates if it has reached the destination.

Example: chase the player

export function start(object) {
    const player = FindByTag("Player");
    PathfindingAgent.setTarget(object, player);
    PathfindingAgent.setSpeed(object, 100);
}

Example: send an object to a position

export function update(object) {
    if (Input.getKeyDown("Space")) {
        PathfindingAgent.setDestination(object, 640, 320);
    }

    if (PathfindingAgent.hasArrived(object)) {
        // The object has arrived.
    }
}

Waypoint Move follows a drawn routemanually. Pathfinding Agent calculates the path and modifies it to go around obstacles.

Look At Target

Look At Target keeps one object facing another. It is designed for turrets, cannons, spotlights, eyes, enemies and any object that must visually follow a target without changing its position.

PropertyUse
Target ModeLocates the target by tag or name.
Target Tag / NameTag or name of the object at which it must look.
Turn SpeedMaximum rotation speed in degrees per second. With 0 it spins instantly.
Reaction DelayTime in seconds between updates of the target address. With 0 it follows the target in each frame.
Original DirectionDirection in which the drawing points without any rotation: right, down, left, up or custom.
Original AngleCustom angle of the sprite's original orientation. Right is 0°, down 90°, left 180° and up -90°.

Example: If the image canon points up, select Up (-90°). The component will automatically apply the necessary correction for that tip to look at the target.

Look At Target API

FunctionUse
LookAtTarget.get(object)Returns the component.
LookAtTarget.setEnabled(object, enabled)Activates or deactivates the orientation.
LookAtTarget.setTarget(object, target)Directly assigns another object as a target.
LookAtTarget.setTarget(object, "Enemy", "tag")Looks for the target by tag.
LookAtTarget.setTurnSpeed(object, speed)Change the rotation speed in degrees per second.
LookAtTarget.setReactionDelay(object, seconds)Change thereaction delay.
LookAtTarget.setOriginalAngle(object, angle)Indicates the original orientation of the sprite.
LookAtTarget.refresh(object)Forces an immediate update of the direction.

Example: turret that follows the player

export function start(object) {
    LookAtTarget.setTarget(object, "Player", "tag");
    LookAtTarget.setTurnSpeed(object, 120);
    LookAtTarget.setReactionDelay(object, 0.1);

    // The original cannon image points upward.
    LookAtTarget.setOriginalAngle(object, -90);
}

Physics Body

Physics Body adds gravity, speed and simple physical response to an object. Use it for boxes, enemies, projectiles, falling objects or items you want to move with force. For playable platform characters it is still better to use Character Controller.

The component is only updated during Play. When you add it, the object automatically activates Collision and stops being Static, because it needs to be able to move. Objects with Body Type: Dynamic can be pushed laterally by the player, by another Character Controller or by another Physics Body. The more Mass the object has, the more it will cost to move it.

PropertyUse
Body TypeDynamic receives gravity and collisions. Kinematic moves by speed/script, but does not receive gravity.
Use GravityActivates or disables the gravity of the component.
Gravity ScaleMultiplies the gravity of the motor. 1 is normal, 0.5 falls slower and 2 falls faster.
MassMass usedby Physics.addForce and by the pushes. More mass means that the same force or push changes the speed less.
Velocity X/YCurrent speed in pixels per second.
DragGradual brake applied to the speed.
Max Fall SpeedSpeed ​​limit when falling.
Freeze X/YBlocks physical movement in one axis.
BounceBounce when colliding. 0 does not bounce;Larger values return part of the speed.
FrictionReduces horizontal speed when touching the ground.

Physics API

FunctionUseExample
Physics.get(object)Returns the Physics Body component.Physics.get(object)
Physics.has(object)Indicates whether the object has a Physics Body.Physics.has(box)
Physics.getVelocity(object)Returns { x, y }.Physics.getVelocity(object).y
Physics.setVelocity(object, x, y)Change the speed directly.Physics.setVelocity(object, 200, -350)
Physics.addVelocity(object, x, y)Adds speed to thecurrent.Physics.addVelocity(object, 0, -120)
Physics.addForce(object, x, y)Applies an instantaneous force taking into account the mass.Physics.addForce(object, 0, -500)
Physics.addForwardForce(object, amount, axis)Applies force towards where the object is facing. axis indicates which axis of the sprite is the front.Physics.addForwardForce(ship, 420, "x")
Physics.forward(object, axis)Returns the frontal direction vector of the object.Physics.forward(ship, "-y")
Physics.stop(object)Sets X/Y velocity to zero.Physics.stop(object)
Physics.setGravity(object, enabled, scale)Activates/disables gravity and optionally changes scale.Physics.setGravity(object, true, 1.5)
Physics.setKinematic(object, kinematic)Switches between kinematicdynamic.Physics.setKinematic(object, true)
Physics.setEnabled(object, enabled)Turns the component on or off.Physics.setEnabled(object, false)
Physics.isGrounded(object)Indicates if it is touching the ground.Physics.isGrounded(object)
export function start(object) {
    Physics.setVelocity(object, 120, -300);
}

export function update(object) {
    if (Input.getKeyDown("Space") && Physics.isGrounded(object)) {
        Physics.addForce(object, 0, -650);
    }

    if (object.isOutsideCamera(100)) {
        Destroy(object);
    }
}

Parallax

Parallax Move the texture of the object using the Play camera or a target object. For backgrounds, clouds and stage layers, parallax uses the Play camera when there is no target assigned. It will only move if the Play camera has Follow Player active.

In the editor the effect remains static. The Parallax move is only executed during Play. The object maintains its original position and size on the screen;the component offsets the camera and only shifts the texture. The manual target is for special cases where you want the layer to respond to a specific object instead of the camera.

PropertyUse
TargetObject that controls the displacement of the texture.
TargetOptional object that controls the parallax. If it is empty, the Play camera is used.
Speed X/YAxis displacement multiplier. 1 is a normal speed;can be negative.
Smooth X/YAxis smoothing. 0 is immediate;High values ​​smooth more.
Margin X/YDead zone per axis before moving the texture, useful for Mario-type cameras.
Repeat X/YRepeat the texture horizontally or vertically.
Lock X/YLocks the movement of the texture on that axis.
EnabledTurns the component on or off.

Parallax API

FunctionUseExample
Parallax.get(object)Returns the active Parallax component.Parallax.get(bg)
Parallax.setTarget(object, target)Change the target object.Parallax.setTarget(bg, player)
Parallax.setSpeed(object, x, y)Change X/Y speed.Parallax.setSpeed(bg, 1, 0)
Parallax.setSmooth(object, x, y)Changes X/Y smoothing.Parallax.setSmooth(bg, 0.85, 0)
Parallax.setMargin(object, x, y)Change X/Y margin in world pixels.Parallax.setMargin(bg, 120, 0)
Parallax.setRepeat(object, x, y)Activates X/Y repetition.Parallax.setRepeat(bg, true, false)
Parallax.setLock(object, x, y)Locks axes.Parallax.setLock(bg, false, true)
Parallax.setEnabled(object, enabled)Activate or deactivate.Parallax.setEnabled(bg, true)
export function start(object) {
    const player = FindByName("Player");

    Parallax.setTarget(object, player);
    Parallax.setSpeed(object, 1, 0);
    Parallax.setSmooth(object, 0.85, 0);
    Parallax.setMargin(object, 120, 0);
    Parallax.setRepeat(object, true, false);
    Parallax.setLock(object, false, true);
}

Character Controller

Character Controller move a 2D character without having to write all the movement code by hand. It is used for platform games and top-down free movement.

The component only runs during Play. In the editor it does not move the object. A summary card is displayed in the Inspector;Press Edit to open the full settings window in the center of the screen. The window changes depending on the chosen mode and hides the options that are not used in that type of controller.

Common parameters

ParameterTypeExplanation
ModeSelectorChoose the type of controller: Platformer for platforms with gravity or Top Down for free movement in top view.
Analog MovementSelectorProgressive preserves stick intensity, so a slight tilt moves more slowly. Fixed converts any tilt beyond the dead zone into full-speed input.
Gamepad Dead ZoneNumber 0-0.95Ignores small stick offsets to prevent drift. The default is 0.12; values between 0.10 and 0.20 are usually recommended.
EnabledCheckActivates or disables the component without removing it from the object.
Use CollisionsCheckUses the engine collision system. In Platformer used for floors, walls, platforms and stairs. In Top Down keeps the controller ready for world contacts.
Apply AnimationsCheckAutomatically changes the object's animation when the controller's state changes.
Flip X DirectionCheckFlips the texture in X when changing the horizontal direction. This is typical for left/right facing characters.
Flip Y DirectionCheckFlips the Y texture when changing the vertical direction. It is usually only used in top-down games or special cases.
HorizontalCheckAllows or blocks movement in the X axis.
VerticalCheckAllows or blocks movement in the Y axis. On platforms it is normally left active for jump/gravity;in top-down it controls going up and down.
Move SpeedNumberBase speed of the character in pixels per second.
Death StateCheckAllows the use of the death state from script with CharacterController.setDead(object, true).

Platformer type

Use Platformer for lateral games with gravity: platforms, jumps, floor, ramps, stairs and platformsmobiles. The controller applies horizontal motion, gravity, jump, and ground detection during Play.

ParameterTypeExplanation
RunCheckActivates an optional running speed while holding down the configured key.
Run SpeedNumberSpeed ​​used when running. It must be greater than Move Speed if you want the race to be noticed.
Run KeyTextRunning key. By default it is usually used Shift.
Run ButtonSelectorGamepad button held to run. The Xbox default is X.
JumpCheckAllows jumping. If disabled, the character does not respond to the jump key.
Jump KeyTextJump key. By default, Space.
Jump ButtonSelectorGamepad button used to jump. The Xbox default is A.
Jump ForceNumberInitial force of the jump is usually used. Higher values ​​make the character climb faster and higher.
GravityNumberForce that pushes the character down. Higher values ​​produce faster falls.
Max FallNumberMaximum fall speed. Prevents the character from accelerating indefinitely.
Double JumpCheckAllows you to jump again in the air.
Max JumpsNumberTotal number of jumps allowed before hitting the ground again. For double jump it is usually 2.
CrouchCheckActivates crouch state.
Crouch KeyTextCrouch key. By default it is usually used S.
Crouch ButtonSelectorGamepad button held to crouch. The Xbox default is B.
Crouch SpeedNumber 0-1Speed ​​multiplier when crouching. 0.5 means moving at half speed.
Use LaddersCheckAllows the use of objects with component Ladder. When touching a staircase the character loses gravity and can go up or down with the input.
Ladder SpeedNumberSpeed ​​when moving down a staircase.

For stairs to work, the staircase object must have the component Ladder. The character can jump from the ladder to get off it.

Top Down Type

Use Top Down for games seen from above or with free movement in X/Y: adventures, shooters, action RPGs or games where the character does not have gravity or jump. The controller normalizes the diagonal so that moving diagonally is not faster.

ParameterTypeExplanation
Move SpeedNumberBase speed for moving in any direction.
RunCheckActivates optional dash also in top-down.
Run SpeedNumberSpeed used while the dash key is pressed.
Run KeyTextRun key.
Run ButtonSelectorGamepad button used to run. Default: X.
CrouchCheckActivates a slow or stealth state if your game allows it.needs.
Crouch KeyTextKey to activate the crouch/stealth state.
Crouch ButtonSelectorGamepad button used for the crouch or stealth state. Default: B.
Crouch SpeedNumber 0-1Speed multiplier during the state crouch.
HorizontalCheckAllows you to move left/right.
VerticalCheckAllows you to move up/down.
Flip X DirectionCheckUseful for characters that look left/right according to the horizontal direction.
Flip Y DirectionCheckUseful for sprites that must be inverted when looking up/down.

Animations and sounds by state

ModeAvailable statesUse
PlatformerIdle, Move, Run, Jump, Fall, Crouch, Death, Ladder Idle, Ladder WalkAllows you to assign animation and sound to each platform state, includingstaircase.
Top DownIdle, Move, Run, Crouch, DeathOnly shows states that make sense without jump, gravity, or stairs.
ParameterExplanation
* AnimAnimation assigned to a state. For example, Run Anim played when running.
* SoundSound played when entering that state. Sounds do not inherit from other states to avoid double triggering.
VolVolume independent of the sound of that state, between 0 and 1.
LoopCauses the state sound to repeat until changing state or exiting Play.

Character Controller sounds use panel sounds Sounds. They are loaded when the project starts and kept in memory;the component only chooses which one to play when changing state. If Mute in Play is active, these sounds are also muted.

CharacterController API

FunctionUseExample
CharacterController.get(object)Returns the object component.CharacterController.get(object)
CharacterController.isGrounded(object)Indicates whether the character is touching the ground.CharacterController.isGrounded(object)
CharacterController.getVelocity(object)Returns { x, y } with the internal speed.CharacterController.getVelocity(object)
CharacterController.setVelocity(object, x, y)Change the internal speed.CharacterController.setVelocity(object, 0, -300)
CharacterController.setDead(object, dead)Turns the mute state on or off.death.CharacterController.setDead(object, true)
CharacterController.isDead(object)Check if it is in a state of death.CharacterController.isDead(object)
CharacterController.resetJumps(object)Resets available jumps.CharacterController.resetJumps(object)
CharacterController.setEnabled(object, enabled)Turns the component on or off.CharacterController.setEnabled(object, false)
export function update(object) {
    if (Input.getKeyDown("K")) {
        CharacterController.setDead(object, true);
    }

    if (CharacterController.isGrounded(object)) {
        debug("En suelo");
    }
}

18. Input

Input allows you to read keyboard, mouse, gamepad and touch from scripts. The API works on Play. In editor mode it does not control the scene or return keystrokes so as not to interfere with the editor tools.

Out of Play, Input returns neutral values: false on buttons/keys, 0 on axes and positions, and null on getTouch.

Keyboard

FunctionUseExample
Input.getKey(key)While a key is onpressed.Input.getKey("A")
Input.getKeyDown(key)Only the frame in which it is pressed.Input.getKeyDown("Space")
Input.getKeyUp(key)Only the frame in which it is released.Input.getKeyUp("Escape")
Input.anyKey()Some key is pressed.Input.anyKey()
Input.anyKeyDown()Some key has just been pressed.Input.anyKeyDown()

You can use letters like "A", special keys like "Escape", "Enter", "Shift", "Control", "Alt", "Space", arrows like "ArrowLeft" and also codes of KeyboardEvent.code like "KeyA".

Common keys supported: "A", "B", "Escape", "Enter", "Shift", "Control", "Alt", "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown" and "Space".

export function update(object, deltaTime) {
    if (Input.getKey("D")) {
        object.translate(160 * deltaTime, 0);
    }

    if (Input.getKeyDown("Space")) {
        debug("Salto");
    }
}

Mouse

Property or functionUse
Input.mouseX, Input.mouseYMouse position inscreen/canvas.
Input.mouseWorldX, Input.mouseWorldYMouse position in world coordinates.
Input.mouseDeltaX, Input.mouseDeltaYMouse movement during the frame.
Input.mouseWheelWheel movement during the frame.
Input.getMouseButton(0)Left button pressed.
Input.getMouseButtonDown(0)Left button pressed this frame.
Input.getMouseButtonUp(0)Left button released this frame.frame.
Input.hideCursor()Hides the mouse pointer during Play.
Input.showCursor()Redisplays the mouse pointer.
Input.setCursorVisible(false)Shows or hides the pointer with a boolean.
Input.isCursorVisible()Returns whether the pointer isvisible.

Buttons: 0 left, 1 center, 2 right.

export function update(object, deltaTime) {
    if (Input.getMouseButtonDown(0)) {
        object.x = Input.mouseWorldX;
        object.y = Input.mouseWorldY;
    }
}
export function start(object) {
    Input.hideCursor();
}

export function update(object, deltaTime) {
    if (Input.getKeyDown("Escape")) {
        Input.showCursor();
    }
}

Gamepad

Input uses the Gamepad API of the browser and normalizes Xbox, PlayStation, Nintendo, USB, Bluetooth and generic controllers. There may be several controls connected.

FunctionUseExample
Input.gamepadCountControls connected.Input.gamepadCount
Input.getButton(button)Button pressed.Input.getButton("A")
Input.getButtonDown(button)Button pressed this frame.Input.getButtonDown("Cross")
Input.getButtonUp(button)Button released this frame.Input.getButtonUp("Start")
Input.getAxis(axis, deadZone?)Axis value between -1 and 1. The optional second parameter sets the dead zone; its default is 0.12.Input.getAxis("LeftStickX", 0.15)
await Input.vibrate(ms, fuerte, suave, indice)Activates the vibration of the control and returns whether it is supported.await Input.vibrate(250, 1, 0.5, 0)
Input.stopVibration(indice)Stops the vibration of the controller.Input.stopVibration(0)

Supported buttons: A, B, X, Y, Cross, Circle, Square, Triangle, L1, R1, L2, R2, Start, Select, Back, Options, Share, LeftStick, RightStick, DPadUp, DPadDown, DPadLeft and DPadRight.

Supported axes: LeftStickX, LeftStickY, RightStickX, RightStickY, LeftTrigger and RightTrigger.

If there are several controllers, you can indicate the index as the second parameter: Input.getButton("A", 0). If you do not indicate an index, the first command that has that button pressed is accepted.

The vibration depends on the command, browser and operating system. Hard and soft intensity use values ​​between 0 and 1. If the device does not have an actuator, the function returns false without stopping the game.

Activate and stop the vibration

export async function update(object) {
    if (Input.getButtonDown("A")) {
        const supported = await Input.vibrate(
            300, // duration in milliseconds
            1,   // strong motor: 0 to 1
            0.4, // weak motor: 0 to 1
            0    // gamepad index
        );

        if (!supported) {
            debug("Este mando no soporta vibracion");
        }
    }

    if (Input.getButtonDown("B")) {
        Input.stopVibration(0);
    }
}
export function onPlayerHit() {
    // Short pulse.
    Input.vibrate(120, 0.8, 0.3);
}

export function onExplosionStart() {
    // Start a long vibration.
    Input.vibrate(2000, 1, 1);
}

export function onExplosionEnd() {
    // Stop it before the 2000 ms duration ends.
    Input.stopVibration();
}

Axes of movement

Horizontal and Vertical combine keyboard and gamepad. Default: A/D, left/right arrows, W/S and up/down arrows.

Vertical movement for Pong

export function update(object, deltaTime) {
    const vertical = Input.getAxis("Vertical");
    object.translate(0, -vertical * speed * deltaTime);
}

This example controls one axis with W/S, the up/down arrow keys and the left stick. Stick intensity is preserved, so a slight tilt produces slower movement.

export function update(object, deltaTime) {
    const move = Input.getMovementVector();

    object.translate(
        move.x * 180 * deltaTime,
        -move.y * 180 * deltaTime
    );
}

Input.getMovementVector() combines Horizontal and Vertical and normalizes the diagonal. This way it doesn't move faster when pressing two directions. In this engine Vertical returns positive upward;that's why the example uses -move.y.

Keyboard and gamepad use the same API in both Editor Play and Web/Windows builds. After an input-system update, generate a new build because existing builds keep the runtime they were created with.

Touch

FunctionUse
Input.touchCountNumber of fingers touching the screen.
Input.getTouch(index)Returns { id, x, y, worldX, worldY } or null.

Canvas UI on mobile

Interactive Canvas UI controls work with both mouse and touch: UI Button, UI Checkbox, UI Select and UI Slider respond to a finger. Tapping a UI Input opens the mobile virtual keyboard and GameCrom synchronizes its text with UI.getValue and UI.onChange.

In the Inspector, Input Type can be Text, Number, Email or Password. This asks the device for the most suitable keyboard. Password masks characters visually, while its value remains available to scripts as text. Visual-only elements—panels, text, images and progress bars—render normally on mobile but do not capture taps.

18.1. Mobile controls

GameCrom includes visual touch controls so Web games can be played on phones and tablets. They are Canvas UI objects, support simultaneous touches and feed the same Input API used by keyboard and gamepad. You do not need separate movement code for mobile.

Creating touch controls

  1. Create or select a UI Canvas.
  2. Open Add GameObject > Mobile Controls.
  3. Add a Touch Joystick, Touch D-Pad or Touch Button.
  4. Place movement controls at the bottom left and action buttons at the bottom right.
  5. Configure their axes or action in the Inspector.
  6. Optionally assign an image from the project Textures to each control.
  7. Test with the mouse in Play or create a new build to test multitouch on a device.
ControlPurposeCommon setup
Touch JoystickAnalog movement in any direction, producing values from -1 to 1.Horizontal and Vertical.
Touch D-PadDigital directional pad producing -1, 0 or 1.Horizontal and Vertical.
Touch ButtonAn action that can be held, newly pressed or newly released.Jump, Run, Crouch, Attack or Pause.

Inspector properties

PropertyPurpose
Horizontal AxisHorizontal axis fed by a joystick or D-pad. Usually Horizontal.
Vertical AxisVertical axis name. Usually Vertical; positive means up.
ActionAction sent by a Touch Button. Action names are case-sensitive.
ImageThe Touch Button normal image, complete D-pad image or joystick base image.
Pressed ImageImage displayed while a Touch Button is held. When set to None, the normal image remains in use.
Inner ImageImage for the moving inner circle of a Touch Joystick. It is automatically clipped to a circle.
Inner OpacityIndependent opacity for the joystick inner circle, from 0 to 1.
Visual StyleD-pad appearance: 4 Arrows, 8 Arrows or Classic Cross. This is visual only; every style keeps identical input behaviour and supports diagonals.
Joystick ModeFixed keeps the joystick at its scene position. Floating in Area hides it until the area is touched and centres it under the finger.
Activation AreaArea that can start a floating joystick: Left Half, Right Half, Full Screen or Custom Area.
Always VisibleWhen enabled, the joystick remains visible at rest and moves to the touched position. When disabled, it stays hidden and only appears while a finger holds its activation area.
Area Position %Custom area X/Y position as a percentage of the game screen.
Area Size %Custom area width and height percentages. For example, X 0, Y 0, W 50, H 100 covers the left half.
Dead ZoneIgnores small movements near the joystick centre. 0.12 is a good starting point.
SensitivityMultiplies joystick response before clamping it between -1 and 1.
Touch devices onlyHides the control on devices without touch support. Disable it while testing with a mouse in Play.
Background, Border, OpacityControl appearance. Moderate opacity keeps the game visible beneath it.
Anchor, position and sizeAttach controls to screen corners and adapt them to different displays.

Reading movement and actions

With Floating in Area, players do not need to hit a small fixed control. The first touch inside the activation area creates the joystick centre at that exact point. Movement is measured from that centre and the joystick disappears when the finger is released. Touch buttons placed over the area have priority, so they continue to work when areas overlap.

When a floating Touch Joystick is selected in the editor, its activation area is displayed with a dashed outline and a subtle blue fill. This guide is editor-only and is never rendered in the game.

export function update(object, deltaTime) {
    // Keyboard, gamepad, touch joystick and D-pad share these axes.
    const x = Input.getAxis("Horizontal");
    const y = Input.getAxis("Vertical");

    object.translate(x * 220 * deltaTime, -y * 220 * deltaTime);

    if (Input.isActionPressed("Attack")) {
        // Continuous attack while held.
    }

    if (Input.isActionDown("Jump")) {
        // Jump once when pressed.
    }

    if (Input.isActionUp("Pause")) {
        // Open or close the pause menu when released.
    }
}
FunctionResult
Input.isActionPressed(name)true while at least one button using that action is held.
Input.isActionDown(name)true only on the first frame of a press.
Input.isActionUp(name)true only on the release frame.
Input.isTouchDevice()Reports whether the device exposes touch support.

Character Controller

The Character Controller automatically reads the Horizontal and Vertical axes. It also recognises the touch actions Jump, Run and Crouch. For a basic character, add a joystick and a button whose action is Jump; no extra movement script is required.

Multitouch and builds

Each finger retains its own control, so players can move the joystick and press several buttons simultaneously. This works in Web and Windows builds on devices with touch input. Generate a new build after changing controls or updating the engine because existing builds retain their original runtime.

Visual controls and Input.getTouch(index) solve different needs. Use visual controls for regular movement and actions. Use getTouch when you need finger positions, finger drawing, world selection or custom gestures.

19.2D Collisions

The engine includes 2D collisions based on SAT. To have an object participate in collisions, activate Collision in the Collider 2D block of the Inspector. If you activate Trigger, the object detects contacts but does not push or block other objects.

OptionWhat it does
CollisionIncludes the object in the collision system during Play.
TriggerDetects contact without physically resolving the collision.
One Way PlatformAllows you to cross the platform by jumping from below and fall on it from above.
ShapeCollider shape. Square objects use Box by default;Circle objects use Circle and can also use Capsule.
OffsetMoves the collider with respect to the center of the object without moving the render.
SizeWidth and height of the collider for Box and Capsule.
RadiusRadius of the collider when the shape is Circle.
StaticThe object does not move when resolving collisions. It works for floors, walls and platforms.

Collisions work with rotation, scale and hierarchies. The collider appears blue in the scene when the object is selected and Collision is active. They only update in Play.

Scenery Components

ComponentUse
LadderTurns the object into a stair area. Adding it activates Collision and Trigger. The Character Controller suspends gravity while touching it and can jump from it.
Moving PlatformMoves the object between its initial position and an X/Y offset. When selecting the object in the editor, a visual reference is drawn with START, END, path arrow and destination silhouette without moving the platform.
Conveyor BeltConverts a solid collider into a conveyor belt that moves the characters and physical bodies resting on it to the left or right.
Texture ScrollerAnimates the X/Y offset of the object's texture during Play, with configurable speed and control from scripts.

Conveyor Belt

Conveyor Belt creates the classic conveyor belt effect. While a compatible object is resting on it, the belt moves it horizontally at the configured speed. It works both in the Play editor and in the exported game.

To use it, select the floor or platform, press Add Component > Conveyor Belt and adjust its properties. When you add it, the editor automatically turns on Collision and off Trigger on the ribbon.

PropertyUse
EnabledTurns ribbon movement on or off.
DirectionChoose whether the ribbon drags toward Left or Right.
SpeedHorizontal speed in pixels per second.
Affect CharactersDrags objects that have a component Character Controller active.
Affect Physics BodiesDrags objects that have a component Physics Body active.

The transported object must be resting on the top of the belt and have Character Controller or Physics Body, according to the activated filters. The belt does not move decorative objects without one of those components.

Conveyor Belt API

FunctionUseExample
ConveyorBelt.get(object)Returns the component.ConveyorBelt.get(object)
ConveyorBelt.setEnabled(object, enabled)Activates or stops the belt.ConveyorBelt.setEnabled(object, false)
ConveyorBelt.setSpeed(object, speed)Change the speed in pixels per second.ConveyorBelt.setSpeed(object, 160)
ConveyorBelt.setDirection(object, direction)Change the direction to "left" or "right".ConveyorBelt.setDirection(object, "left")
ConveyorBelt.setAffects(object, characters, physicsBodies)Choose the types of object it carries.ConveyorBelt.setAffects(object, true, false)

TextureScroller

TextureScroller continuously modifies Texture Offset X and Texture Offset Y during Play. It works for animated tapes, water, lava, clouds, moving backgrounds or any repeating texture. The texture must have proper tiling so that the scroll is visible continuously.

PropertyUse
EnabledTurns the offset animation on or off.
Speed XPositive horizontal speed of the offset per second.
Speed YPositive vertical speed of the offset per second.
Scroll RightMarking shifts the texture to the right;unchecked moves it to the left.
Scroll DownChecked moves the texture down;unchecked moves it up.

Texture Scroller API

FunctionUseExample
TextureScroller.get(object)Returns the component.TextureScroller.get(object)
TextureScroller.setEnabled(object, enabled)Activates or stops the scroll.TextureScroller.setEnabled(object, true)
TextureScroller.setSpeed(object, x, y)Change the speed of the two axes.TextureScroller.setSpeed(object, 0.5, 0)
TextureScroller.setDirection(object, right, down)Change the direction of each axis with booleans.TextureScroller.setDirection(object, true, false)
TextureScroller.setOffset(object, x, y)Immediately sets the texture offset.TextureScroller.setOffset(object, 0, 0)
TextureScroller.getOffset(object)Returns { x, y } with the offsetcurrent.const offset = TextureScroller.getOffset(object)
export function start(object) {
    TextureScroller.setSpeed(object, 0.4, 0);
}

export function update(object) {
    if (Input.getKeyDown("Space")) {
        const component = TextureScroller.get(object);
        TextureScroller.setEnabled(object, !component.enabled);
    }
}

Callbacks in scripts

If your object has a script assigned to it, you can export these functions. The engine calls them when the object's collider enters, remains or leaves contact with another.

FunctionWhen called
onCollisionEnter(object, collision)First frame of contact with a normal collider.
onCollisionStay(object, collision)Each frame while contact continues.
onCollisionExit(object, collision)When contact ends.
onTriggerEnter(object, collision)First frame of contact with a trigger.
onTriggerStay(object, collision)Each frame while still within thetrigger.
onTriggerExit(object, collision)When the trigger exits.
export function onCollisionEnter(object, collision) {
    debug(object.name + " choca con " + collision.other.name);
}

export function onTriggerEnter(object, collision) {
    if (collision.other.tag === "Coin") {
        Destroy(collision.other);
    }
}

Collision data

PropertyContent
collision.otherThe other object of the contact.
collision.selfThe object that receives the callback.
collision.normalSeparation address from the point of view of self.
collision.overlapOverlap depth.
collision.pointApproximate point of the contact.
collision.isTriggertrue if the contact includes a trigger.

Collision API

FunctionUseExample
Collision.check(a, b)Checks if two objects are colliding now.Collision.check(player, enemy)
Collision.all(object)Returns the current contacts of an object.Collision.all(object)
Collision.contacts()Returns all contacts in the frame.Collision.contacts()
export function update(object, deltaTime) {
    const enemy = FindByName("Enemy");
    const hit = Collision.check(object, enemy);

    if (hit) {
        debug("Tocando enemigo");
    }
}

Events and Time

Events

Events communicates scripts withoutsearch or directly reference other objects. Events are cleared when changing scenes.

Events.on(name, callback)Listen to an event and return a function to stop listening to it.
Events.once(name, callback)Listen only to the next broadcast.
Events.emit(name, data)Send data to all listeners.
Events.off(name, callback)Delete a specific callback.
Events.clear(name)Clear an event;no name cleans all.
Events.count(name)Number of listeners.
export function start(object) {
    Events.on("player-hit", data => {
        UI.setText("HealthText", `Vida: ${data.health}`);
    });
}

export function hitPlayer(health) {
    Events.emit("player-hit", { health });
}

Time

Time.deltaTimeFrame scaling delta.
Time.unscaledDeltaTimeActual delta, even with pause or slow motion.
Time.fixedDeltaTimeFixed motor step.
Time.time, Time.unscaledTimeScaled and real accumulated time.
Time.frameCountFrames processed.
Time.timeScaleGlobal scale:1 normal, 0.5 slow motion, 0 stopped.
Time.pause(), resume(), isPaused()Pause control.
export function update(object) {
    if (Input.getKeyDown("P")) {
        if (Time.isPaused()) Time.resume();
        else Time.pause();
    }

    if (Input.getKeyDown("T")) {
        Time.timeScale = 0.35;
    }
}

Time.pause() only stops scaled time. To stop the complete game in a coordinated way, use the global Game API described below.

Global game pause

Game.pause() applies a complete, safe pause in both Editor Play and builds. It stops normal scripts, physics, collisions, animations, particles, tweens, pathfinding, camera and audio. Rendering continues and Input remains available for controlling the pause menu.

Game.pause()Pauses the game. Returns true when the state changes.
Game.resume()Resumes without animation or particle jumps.
Game.togglePause()Toggles pause and resume.
Game.isPaused()Reports whether global pause is active.

How to pause and resume

export function update(object, deltaTime) {
    // update stops running after the game is paused.
    if (Input.getKeyDown("Escape") || Input.getButtonDown("Start")) {
        Game.pause();
        UI.show("PauseMenu");
    }
}

export function pausedUpdate(object, unscaledDeltaTime) {
    // Runs only during the global pause.
    if (Input.getKeyDown("Escape") || Input.getButtonDown("Start")) {
        UI.hide("PauseMenu");
        Game.resume();
    }
}

To resume from a script, use pausedUpdate(object, unscaledDeltaTime), because update, fixedUpdate and lateUpdate remain stopped. Do not place Game.togglePause() only inside update: that callback no longer runs after pausing. unscaledDeltaTime can be used to animate a pause interface manually.

Additional Component APIs

MovingPlatform.get(object)Gets the component.
MovingPlatform.setEnabled(object, value)Activate or deactivate.
MovingPlatform.setSpeed(object, speed)Change speed.
MovingPlatform.setMovement(object, x, y)Change traversal.
MovingPlatform.setPingPong(object, value)Controls round trip.
MovingPlatform.reset(object)Resets its state.
Rotation.get(object)Gets Rotation.
Rotation.setEnabled(object, value)Activate or deactivate.
Rotation.setSpeed(object, speed)Change degrees per second.
Rotation.setPivot(object, x, y)Change pivot.
Rotation.reset(object)Resets the accumulated rotation.
Ladder.get(object), Ladder.setEnabled(object, value)Queries or activates a ladder.
Light.get(object), Light.setEnabled(object, value)Queries or activates alight.
Light.setColor(object, color)Change hexadecimal color.
Light.setIntensity(object, value)Intensity between 0 and 1.
Light.setRadius(object, radius)Change radius.
Light.setEffect(object, effect, options)Effect and options speed, amount and color.
const platform = FindByName("Lift");
MovingPlatform.setSpeed(platform, 120);
MovingPlatform.setMovement(platform, 0, -300);

const alarm = FindByName("AlarmLight");
Light.setColor(alarm, "#ff2020");
Light.setEffect(alarm, "alarm", { speed: 3, amount: 0.8 });

Save games with Save

Save saves complete objects per slot and project. For small options it is still suitable PlayerPrefs;for games uses Save.

Save.write(slot, data, metadata)Saves optional data and metadata.
Save.read(slot, fallback)Read the data.
Save.info(slot)Date and metadata without loading the game.
Save.exists(slot)Check the slot.
Save.delete(slot)Delete a slot.
Save.list()List slots sorted by date.
Save.clear()Delete all games in the project.
Save.write("slot1", {
    scene: Scene.current,
    score: Project.vars.score,
    lives: 3,
    player: { x: object.x, y: object.y }
}, {
    title: "Main save"
});

const game = Save.read("slot1", null);
if (game) {
    Project.vars.score = game.score;
    object.x = game.player.x;
    object.y = game.player.y;
}

The data must be able to be converted to JSON. Do not save features, HTML elements, Audio or circular references.

TXT and JSON files

GameCrom uses the same Files API for TXT and JSON, but separates files into two areas with different purposes and permissions. Choosing the correct area keeps original project content separate from data generated by each player.

AreaPurposeWhile playingExamples
assets/data/Internal content prepared by the developer.Read-onlyTranslations, dialogue, configuration, levels and data tables.
user/Local data created or changed at runtime.Read and writeProfiles, generated content, logs and custom game data.

Case 1: internal project data — assets/data/

Open the Data tab in the Assets panel. You can import .txt and .json files, or create one with New TXT and New JSON. Files are stored in assets/data/; Open in VS Code opens them directly in Visual Studio Code. Subfolders can be included in the name, for example dialogues/en.json.

assets/data/ is always read-only while the game is running. Its files belong to the project and are included in builds, but scripts cannot change or delete them. To change this content, return to the project, edit it with VS Code and create a new build.

// Read content prepared by the developer
const translations = await Files.readJSON("assets/data/translations/en.json", {});
const dialogues = await Files.readText("assets/data/dialogues.txt", "");

// This is forbidden because assets/data is read-only:
// await Files.writeJSON("assets/data/config.json", newConfig);

Case 2: writable player files — user/

Use user/ when the game needs to create, read, change or delete TXT and JSON files at runtime. These files are not part of the original project and are independent for each game, browser or installation.

// Create or overwrite a player file
await Files.writeJSON("user/profile.json", {
    name: "Player",
    level: 3
}, { pretty: true });

// Read it, change it and save it again
const profile = await Files.readJSON("user/profile.json", { level: 1 });
profile.level += 1;
await Files.writeJSON("user/profile.json", profile);

await Files.writeText("user/notes.txt", "Level completed");
const files = await Files.list("user/");
await Files.delete("user/notes.txt");

Where user/ is stored

  • Editor Play: in the editor's local storage.
  • Build Web: in the browser, associated with the domain running the game. It does not create visible files beside the website.
  • Windows Build: in the application's local data, separately for each game. It is not stored beside the EXE or inside assets/data/.
MethodDescription
await Files.readText(path, fallback?)Reads a .txt file.
await Files.readJSON(path, fallback?)Reads and parses a .json file.
await Files.writeText(path, content)Writes text inside user/.
await Files.writeJSON(path, value, options?)Writes JSON. Use { pretty: true } to format it.
await Files.exists(path)Checks whether a file exists.
await Files.list(path)Lists files in a folder.
await Files.delete(path)Deletes a file from user/.

Handle errors with try/catch and inspect error.code: NOT_FOUND, INVALID_JSON, ACCESS_DENIED or QUOTA_EXCEEDED.

Only .txt and .json files are accepted, up to 5 MB per file. Absolute paths and ../ are blocked. Use PlayerPrefs for simple preferences, Save for slot-based save games and Files for custom auxiliary files.

Local saving

Which system should you use?

SystemRecommended usePersistence
PlayerPrefsVolume, language, controls, graphics quality and other preferences.Local storage, separated by project.
SaveSave games, levels, inventory, score, campaign and checkpoints.Local storage, organized into slots and separated by project.

GameCrom 2D Studio does not use accounts or cloud saving. Data is not synchronized between browsers, computers or devices.

Where data is stored

  • Editor Play: in the editor's local storage.
  • Build Web: in the local storage of the browser and domain where the game is running.
  • Build Windows: in the application's local storage.

On the Web, each browser and domain keeps an independent copy. Clearing site data, using private browsing or running the game from another domain may make a save unavailable. On Windows, deleting the application's local data also deletes its preferences and save games.

Recommended use

// Device preferences
PlayerPrefs.setNumber("volume", 0.8);
PlayerPrefs.setString("language", "en");

// Game progress
Save.write("autosave", {
    level: 4,
    score: 12500,
    player: { x: object.x, y: object.y }
});

const data = Save.read("autosave", null);

Save at checkpoints and after important changes. Do not wait only for the browser tab or application to close, because a forced shutdown may prevent the final write.

Pathfinding

Pathfinding.findPath use A* on a temporal grid. Objects with active collision lock cells;Triggers do not block. Does not require Tilemap.

Pathfinding.findPath(start, end, options)Returns world points or an empty array.
Pathfinding.follow(object, path, speed, options)Makes the object follow the path.
Pathfinding.stop(object)Stops tracking.
Pathfinding.isFollowing(object)Checks if it follows a path.

Main options: cellSize, diagonal, padding, marginCells, maxNodes e ignore. A small cellSize finds more precise routes but costs more CPU.

export function start(object) {
    const player = FindByTag("Player");
    const path = Pathfinding.findPath(object, player, {
        cellSize: 32,
        diagonal: true,
        padding: 6,
        ignore: [object, player]
    });

    Pathfinding.follow(object, path, 110, {
        arriveDistance: 3,
        onComplete(enemy) {
            debug(enemy.name + " ha llegado");
        }
    });
}

export function update(object) {
    if (Input.getKeyDown("Escape")) {
        Pathfinding.stop(object);
    }
}

Pixel Canvas

The object Pixel Canvas It is a dynamic and scalable image whose content comes from a script-controlled framebuffer. It is used for emulators, drawing programs, minimaps, screens, procedural effects and games based directly on pixels.

Create Add GameObject > Pixel Canvas and configure its internal resolution. The size and scale of the object control the visible size;its resolution controls how many pixels the framebuffer contains.

PixelCanvas.create(object, width, height, options)Creates or replaces the surface.
PixelCanvas.get(object)Returns the existing surface.
PixelCanvas.getOrCreate(object)Gets or creates using the object's configuration.
surface.getBuffer()RGBA buffer Uint8ClampedArray;four bytes per pixel.
surface.getIndexBuffer()Buffer Uint8Array of indices for palettes of up to 256 colors.
surface.setPixel(x, y, color)Draws a pixel.
surface.clear(color)Cleans the entire surface.
surface.fillRect(x, y, w, h, color)Fills a rectangle.
surface.drawLine(x0, y0, x1, y1, color)Draws a line.
surface.setPalette(colors)Defines the indexed mode palette.
surface.present()Publishes buffer changes torender them.
let screen;

export function start(object) {
    screen = PixelCanvas.create(object, 256, 192, {
        indexed: true
    });
    screen.setPalette([
        "#000000", "#0000d7", "#d70000", "#d700d7",
        "#00d700", "#00d7d7", "#d7d700", "#d7d7d7"
    ]);
    screen.clear(0).present();
}

export function update(object) {
    const pixels = screen.getIndexBuffer();
    pixels[40 * screen.width + 80] = 6;
    screen.markDirty();
    screen.present();
}

For maximum performance directly modify the buffer and call markDirty() before present(). With Auto Present active, the renderer automatically publishes any surface marked as modified.

Engine, types and API contract

Engine.versionEngine version.
Engine.apiVersionScript contract version.
Engine.isEditorTrue in Editor Play and false in compiled.
Engine.platformSystem Communicated Platform.
export function start(object) {
    debug({
        engine: Engine.version,
        api: Engine.apiVersion,
        editor: Engine.isEditor,
        platform: Engine.platform
    });
}

The file DOCUMENTOS/gamecrom-2d-studio-api.d.ts provides autocompletion and types for new APIs. The test node TESTS/runtimeApiContract.mjs validates math, events, time, Random, Save, Pathfinding and PixelCanvas.

API Application: exit the game

Use Application.quit() to leave the game from any script. The same call works during Play in the editor, in a web version published in GameCrom, and in a Windows executable. Application.exit() is an equivalent alias.

EnvironmentResult
Editor PlayStops Play and returns to the scene without closing the editor.
Web game in GameCromClose the web player and end the game session.
Game EXECleanly close the window and the native game process.

Exit directly

export async function salirDelJuego() {
    await Application.quit();
}

You can call this function fromthe logic of a menu button, a Game Over screen or any other script. The promise returns true if the request has been sent and false if other code has canceled the exit.

Exit on Escape

export function start(object) {
    // No setup is required at startup.
}

export async function update(object, deltaTime) {
    if (Input.getKeyDown("Escape")) {
        await Application.quit("escape-key");
    }
}

Save before exit

export async function salirGuardando(object) {
    PlayerPrefs.setInt("record", Project.vars.record || 0);
    PlayerPrefs.setJSON("configuracion", Project.vars.configuracion || {});
    PlayerPrefs.save();

    await Application.quit("main-menu");
}

Save first and request exit later. Do not place long trades after Application.quit(), because the game can close immediately.

Temporarily cancel exit

let hasUnsavedChanges = true;

export async function intentarSalir() {
    if (hasUnsavedChanges) {
        window.addEventListener("gamecrom:before-quit", event => {
            event.preventDefault();
            debug("Save the game before quitting");
        }, { once: true });
    }

    const quitting = await Application.quit("main-menu");
    debug({ quitting }); // false when cancelled
}

export async function saveAndQuit() {
    PlayerPrefs.setInt("nivel", Project.vars.nivel || 1);
    hasUnsavedChanges = false;
    await Application.quit("saved-game");
}

The cancelable event gamecrom:before-quitis emitted before closing. Its property event.detail.reason contains the reason sent to quit. The listener must synchronously decide whether to cancel the output using event.preventDefault().

Available Methods

MethodUse
await Application.quit(reason?)Request a clean output and return true or false.
await Application.exit(reason?)Alias ​​of Application.quit().

20. Compile and export the game

From Project Settings you can locally generate different versions of the game. Before building, the editor saves the current scene and project settings.

The Builds field above the build buttons selects the output folder. The default is C:\GAMECROM_BUILDS. After a successful build, Open Folder opens the generated folder directly; the button stays hidden until a valid output path exists.

ButtonOutputRecommended use
Build Web<BUILDS_ROOT>/<Project>/webMinified and protected web version for publishing.
Build Windows<BUILDS_ROOT>/<Project>/windowsProtected portable Windows executable.

Build Web

The protected version does not leave the folders visible scripts, scenes, assets, prefabs nor ENGINE. The game is packaged in a few files and is rebuilt in memory upon startup.

The engine is bundled into a single module and minified together with the boot code and project scripts. Game scripts also receive moderate identifier renaming, without aggressive control-flow transforms, junk code or per-frame decoders. The shared physics and collision core receives safe minification and local identifier renaming only; it uses no control-flow obfuscation or extra runtime work, preserving performance and stability. Original editor and project files are never modified; the process works only on copies inside the build output folder.

C:\GAMECROM_BUILDS\PONG\web\
  index.html
  p.js
  s.css
  m.json
  d.json
  r/
    e.js

There is no absolute protection on the web: the browser always needs to download the game data. This output makes analysis and copying more difficult, but should not be used to store secrets, private keys, or sensitive logic.

Build Windows

Builds the game as an executable application without an installer, for example PONG.exe.

It is ideal for running the game directly, distributing it in a ZIP file, or publishing it on platforms that accept Windows applications.

The necessary resources are packaged with the application andthey do not appear as separate folders next to the executable.

Which one should I use?

To publish in a browser: Build Web

To distribute a protected executable: Build Windows

For Steam and other stores: consult the corresponding publishing guide.

21. Usage tips

  • Use deltaTime so that movement does not depend on FPS.
  • Always check if FindByName or FindByTag return null.
  • Use tags for categories like Enemy, Player, Pickup or Target.
  • If a script is assigned to multiple objects, each object will receive its own call to start and update.
  • Changes made during Play are temporary and are restored when exiting Play.

Video in games and Canvas UI

Import .mp4, .webm or .ogv files from the Videos tab. MP4 encoded with H.264 video and AAC audio is recommended for the widest Web and Windows compatibility.

UI Video

Use Add GameObject > Canvas UI > UI Video for cutscenes, tutorials, menu backgrounds, or video anchored to the screen. It supports Contain, Cover and Stretch fitting, play on start, looping, mute and volume.

Video Renderer

Add the Video Renderer component to a regular object to draw video inside its bounds and transform it as part of the world.

Browsers may block autoplay with sound. New videos therefore start muted; enable sound after user interaction. Imported videos are included in the build and do not depend on an external URL.