← GameCrom Studio

GAMECROM 2D STUDIO

Referencia de scripting

Aprende a programar el comportamiento de tus juegos con JavaScript. Consulta la API de GameCrom, ciclos de ejecución, objetos, componentes, propiedades, eventos y ejemplos prácticos.

1. Crear y asignar un script

Cada proyecto tiene una carpeta scripts. Puedes crear, editar, renombrar y eliminar scripts desde la pestana Scripts del panel inferior. Cada objeto puede tener un script asignado desde el Inspector. Un mismo script puede asignarse a varios objetos.

Usa Refresh, situado a la derecha de la pestaña Scripts, después de crear, eliminar o cambiar el nombre de un archivo directamente desde VS Code o el Explorador. Si utilizas Rename desde el editor, GameCrom cambia el archivo y actualiza automáticamente sus asignaciones en los objetos, escenas guardadas y prefabs.

  1. Selecciona un objeto en la escena o en la jerarquia.
  2. En el Inspector busca el componente Script o abre la pestana Scripts.
  3. Pulsa Create para crear uno nuevo o elige uno existente en File.
  4. Pulsa Edit para abrirlo en Visual Studio Code.
  5. Pulsa Play para ejecutar el script.

Los scripts solo se ejecutan en Play. Al salir de Play, la escena vuelve al estado de edicion.

Prefabs

Un prefab es una plantilla reutilizable de un objeto. Sirve para guardar un objeto de la escena con sus propiedades y sus hijos, y despues crear copias nuevas cuando las necesites.

  1. Selecciona el objeto que quieres convertir en prefab.
  2. Abre la pestana Prefabs en el panel inferior.
  3. Pulsa Create From Selection.
  4. Escribe el nombre del prefab y confirma.
  5. Usa Instantiate para crear una copia del prefab en la escena.
  6. Usa Delete para eliminar el archivo del prefab del proyecto.

La lista de prefabs muestra una miniatura del objeto raiz. Si el objeto tiene textura se ve la imagen; si no, se muestra una forma con su color.

En la barra superior del editor, Snap conserva el desplazamiento por pasos. El check Snap to Grid encaja la esquina superior izquierda del objeto directamente en la rejilla.

Los prefabs se guardan dentro de la carpeta prefabs del proyecto. Al instanciar uno, el motor crea objetos nuevos con IDs nuevos para no modificar el prefab original ni pisar objetos de la escena.

Se guardaDetalle
Objeto raizNombre, tag, posicion, escala, rotacion, color, textura, colision, visibilidad y Static.
HijosLa jerarquia completa que cuelga del objeto seleccionado.
ScriptLa referencia al script asignado al objeto.
AnimacionLa animacion asignada y sus opciones de reproduccion.
ParticulasEl sistema de particulas asignado y sus opciones.
ComponentesComponentes anadidos al objeto, como Audio Source, Parallax o Character Controller.

De momento el prefab funciona como plantilla reutilizable. Si editas el objeto instanciado en la escena, esos cambios pertenecen a esa copia. No se aplican automaticamente al prefab guardado.

Luces 2D

Puedes crear un objeto Light desde Add GameObject. En Play no se dibuja como sprite normal: ilumina la escena con una luz radial sobre el canvas. Los objetos Light no muestran Sprite Renderer ni Collider 2D porque no son objetos fisicos ni sprites del juego. La luz solo afecta a las capas que estan por debajo de ella en el orden de dibujo; los objetos colocados por encima se dibujan despues y no quedan iluminados por esa luz.

PropiedadUso
EnabledActiva o desactiva la luz.
Light ColorColor de la luz.
RadiusAlcance de la luz en pixeles de mundo.
IntensityFuerza de la luz, de 0 a 1.
OpacityTransparencia global de la luz, de 0 a 1.
SoftnessSuavizado del borde, de 0 a 1.
EffectAnimacion de luz: None, Torch, Candle, Alarm, Fluorescent o Pulse.
Effect SpeedVelocidad del efecto. 0 deja la luz practicamente fija.
Effect AmountCantidad de variacion de intensidad del efecto.
Radius AmountCantidad de variacion del radio durante el efecto.
Effect ColorColor secundario usado por efectos como Alarm y Pulse.

Los efectos se animan durante Play. Torch y Candle simulan parpadeo organico, Alarm alterna hacia un color secundario, Fluorescent crea pequenos cortes de intensidad y Pulse respira suavemente. El boton Play del componente permite previsualizar el efecto en el editor sin ejecutar el juego.

Recortar sprites

El recortador sirve para separar una textura grande que contiene muchos sprites mezclados, como una hoja de sprites. Los recortes se guardan como texturas PNG nuevas dentro del proyecto.

  1. Abre la pestana Slice Sprite del panel inferior.
  2. Elige la textura fuente.
  3. Configura Cell W y Cell H con el tamano de cada sprite.
  4. Ajusta Offset X/Y si la hoja tiene margen exterior.
  5. Ajusta Spacing X/Y si hay separacion entre sprites.
  6. Usa Columns y Rows para limitar el area, o deja 0 para calcularlo automaticamente.
  7. Pulsa Save Slices para guardar cada recorte como textura nueva.

La textura original no se modifica. Si Empty esta desactivado, los recortes totalmente transparentes se saltan.

2. Ciclo de ejecucion

Un script puede exportar funciones de ciclo. Todas reciben el objeto que tiene asignado el script. Si no declaras una funcion, simplemente no se llama.

FuncionCuando se llamaParametros
start(object)Una vez al entrar en Play.object: objeto dueño del script.
fixedUpdate(object, fixedDeltaTime)A paso fijo, 60 veces por segundo si el rendimiento lo permite.Movimiento estable, fisica y empujes.
update(object, deltaTime)Cada frame durante Play.Input, logica normal, movimiento visual y UI.
lateUpdate(object, deltaTime)Al final del frame, despues de update y colisiones.Camara, UI dependiente de posiciones finales y ajustes finales.
export function start(object) {
    debug("Empieza: " + object.name);
}

export function fixedUpdate(object, fixedDeltaTime) {
    // Paso fijo: ideal para fisica.
}

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

export function lateUpdate(object, deltaTime) {
    // Se ejecuta cuando todos los update del frame han terminado.
}

3. El objeto recibido

El parametro object es el objeto real de la escena durante Play. Puedes leer sus datos y cambiar propiedades como posicion, rotacion, escala, color, opacidad o estado activo.

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

Si quieres ver todo lo que tiene un objeto, puedes enviarlo completo a la consola:

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

4. Manejo de variables

En los scripts puedes crear variables normales de JavaScript. Segun donde las guardes, duran solo dentro de una funcion, pertenecen a un objeto, a la escena actual o a toda la partida del proyecto.

Tipos habituales

TipoEjemploUso
numberlet vida = 100;Numeros, velocidad, tiempo, puntuacion.
stringlet estado = "idle";Texto, nombres, estados.
booleanlet vivo = true;Valores verdadero/falso.
objectlet datos = { vida: 100 };Agrupar datos.
arraylet inventario = [];Listas de valores.

Variables locales

Viven solo dentro de la funcion donde se crean. Se pierden al terminar esa llamada.

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

Variables del script

Si las creas fuera de start y update, se conservan mientras ese script esta cargado en Play. Si el mismo script se asigna a varios objetos, esa variable se comparte entre ellos.

let totalUpdates = 0;

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

Variables locales de un objeto

Para guardar datos de un objeto concreto, crea tus propias propiedades dentro de object. Cada objeto tendra sus propios valores.

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

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

Variables globales de escena

Usa Scene.vars para datos compartidos por todos los scripts de la escena actual. Se reinicia al entrar en Play y tambien cuando cargas otra escena con Scene.load.

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

Variables globales de proyecto

Usa Project.vars para datos que deben sobrevivir al cambiar de escena durante la misma partida, como puntuacion, vidas o progreso.

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);
}

Datos guardados con PlayerPrefs

Usa PlayerPrefs para guardar datos que deben seguir existiendo aunque cierres el juego, como récord, opciones, volumen, monedas o el último nivel desbloqueado. Los datos se guardan separados por proyecto.

Project.vars se borra al salir de Play. PlayerPrefs se queda guardado en el navegador/Tauri hasta que borres la clave o llames a PlayerPrefs.deleteAll().

FuncionUsoEjemplo
PlayerPrefs.setString(key, value)Guarda texto.PlayerPrefs.setString("playerName", "Alex")
PlayerPrefs.getString(key, defaultValue)Lee texto.PlayerPrefs.getString("playerName", "Player")
PlayerPrefs.setNumber(key, value)Guarda un numero.PlayerPrefs.setNumber("volume", 0.8)
PlayerPrefs.getNumber(key, defaultValue)Lee un numero.PlayerPrefs.getNumber("volume", 1)
PlayerPrefs.setInt(key, value)Guarda un entero.PlayerPrefs.setInt("coins", 25)
PlayerPrefs.getInt(key, defaultValue)Lee un entero.PlayerPrefs.getInt("coins", 0)
PlayerPrefs.setBool(key, value)Guarda verdadero/falso.PlayerPrefs.setBool("music", true)
PlayerPrefs.getBool(key, defaultValue)Lee verdadero/falso.PlayerPrefs.getBool("music", true)
PlayerPrefs.setJSON(key, value)Guarda objetos o arrays.PlayerPrefs.setJSON("inventory", ["key"])
PlayerPrefs.getJSON(key, defaultValue)Lee objetos o arrays.PlayerPrefs.getJSON("inventory", [])
PlayerPrefs.hasKey(key)Comprueba si existe una clave.PlayerPrefs.hasKey("record")
PlayerPrefs.deleteKey(key)Borra una clave.PlayerPrefs.deleteKey("record")
PlayerPrefs.deleteAll()Borra todos los datos guardados del proyecto actual.PlayerPrefs.deleteAll()
PlayerPrefs.keys()Devuelve las claves guardadas del proyecto actual.PlayerPrefs.keys()
PlayerPrefs.save()Existe por compatibilidad. En este motor el guardado es inmediato.PlayerPrefs.save()

Ejemplo: guardar 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
    });
}

Ejemplo: guardar opciones

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);
    }
}

Matematicas disponibles

Los scripts pueden usar directamente el objeto estandar Math de JavaScript. El motor tambien incluye las APIs Random, Mathf y Vector2.

Operacion actualEjemplo
Minimo, maximo y valor absolutoMath.min(a, b), Math.max(a, b), Math.abs(x)
RedondeoMath.floor(x), Math.ceil(x), Math.round(x)
Potencias y raizMath.pow(x, 2), Math.sqrt(x)
Distancia 2DMath.hypot(dx, dy)
Angulos y trigonometriaMath.atan2(y, x), Math.sin(x), Math.cos(x)
SignoMath.sign(x)
Aleatorio entre 0 y 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

FuncionUsoEjemplo
Random.value()Decimal entre 0 incluido y 1 excluido.Random.value()
Random.range(min, max)Decimal entre los dos valores.Random.range(10, 20)
Random.int(min, max)Entero entre min y max, incluyendo ambos.Random.int(1, 6)
Random.choose(array)Elemento aleatorio o null si el array esta vacio.Random.choose(["red", "blue"])
Random.chance(probability)Devuelve true con una probabilidad entre 0 y 1.Random.chance(0.25)
Random.sign()Devuelve aleatoriamente -1 o 1.Random.sign()
Random.shuffle(array)Devuelve una copia mezclada sin modificar el array original.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 trabaja con numeros y angulos. Vector2 devuelve objetos nuevos { x, y }; no modifica los vectores recibidos.

API Mathf

Mathf.clamp(value, min, max)Limita un valor.
Mathf.clamp01(value)Limita entre 0 y 1.
Mathf.lerp(a, b, t)Interpola usando t entre 0 y 1.
Mathf.inverseLerp(a, b, value)Calcula la proporcion de value entre a y b.
Mathf.moveTowards(current, target, step)Acerca un numero sin sobrepasarlo.
Mathf.repeat(value, length)Repite un valor dentro de un intervalo.
Mathf.pingPong(value, length)Oscila entre 0 y length.
Mathf.degToRad(degrees), radToDeg(radians)Convierte angulos.
Mathf.deltaAngle(a, b)Menor diferencia angular con signo.
Mathf.lerpAngle(a, b, t)Interpola por el camino angular mas corto.

API Vector2

Vector2.create(x, y)Crea un vector.
Vector2.add(a, b), subtract(a, b)Suma o resta.
Vector2.multiply(v, scalar), divide(v, scalar)Escala un vector.
Vector2.length(v)Longitud.
Vector2.distance(a, b)Distancia entre puntos.
Vector2.normalize(v)Vector de longitud 1.
Vector2.dot(a, b)Producto escalar.
Vector2.angle(a, b)Angulo en grados.
Vector2.lerp(a, b, t)Interpola dos vectores.
Vector2.moveTowards(a, b, distance)Acerca un punto a otro.
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. Movimiento de objetos

Durante Play los objetos tienen metodos utiles para moverse y orientarse. Estos metodos devuelven el propio objeto, asi que puedes encadenarlos si te resulta comodo.

MetodoUsoEjemplo
object.translate(x, y)Mueve el objeto en sus coordenadas locales.player.translate(10, 0)
object.lookAt(target, eje)Rota el objeto mirando a otro objeto o punto usando el eje indicado.player.lookAt(enemy, "x")
object.moveTowards(target, speed, deltaTime)Mueve el objeto hacia un objetivo.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 y moveTowards aceptan un objeto o un punto como { x: 100, y: 50 }. En lookAt, el eje por defecto es "x". Tambien puedes usar "-x", "y" o "-y". Por ejemplo, si tu sprite mira hacia arriba, usa object.lookAt(enemy, "-y").

6. Jerarquia de objetos

Durante Play puedes consultar y cambiar relaciones padre/hijo. Al cambiar de padre, el motor intenta mantener la posicion visual del objeto en el mundo.

MetodoUsoEjemplo
object.addChild(child)Hace que otro objeto sea hijo de este objeto.player.addChild(gun)
object.removeChild(child)Quita un hijo directo y lo deja sin padre.player.removeChild(gun)
object.parent()Devuelve el padre del objeto o null.const p = gun.parent()
object.root()Devuelve el objeto raiz de la jerarquia.const root = gun.root()
object.children()Devuelve un array con los hijos directos.const hijos = player.children()
object.destroyAllChildren(tiempo)Destruye todos los hijos directos, al momento o tras un tiempo.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 no permite crear bucles de jerarquia. Por ejemplo, no puedes hacer hijo a un objeto de uno de sus propios descendientes.

7. Propiedades del objeto

Estas son las propiedades principales que puedes leer y modificar desde un script.

PropiedadTipoUsoEjemplo
idstring/numberIdentificador unico del objeto.debug(object.id)
namestringNombre visible en el editor.object.name = "Player"
tagstringEtiqueta para buscar objetos por categoria.object.tag = "Enemy"
parentIdstring/nullID del padre en la jerarquia.debug(object.parentId)
typestringTipo visual: square o circle.debug(object.type)
activebooleanActiva o desactiva el objeto.object.active = false
isStaticbooleanMarca el objeto como estatico para optimizaciones futuras.object.isStatic = true
visibleInPlaybooleanControla si se ve durante Play.object.visibleInPlay = true
x, ynumberPosicion local del objeto.object.x += 10
w, hnumberTamano base del objeto.object.w = 80
rotationnumberRotacion en grados.object.rotation += 90 * deltaTime
scaleX, scaleYnumberEscala horizontal y vertical.object.scaleX = 2
znumberCapa de orden visual.object.z = 5
colorstringColor en formato hexadecimal.object.color = "#ff0000"
opacitynumberOpacidad entre 0 y 1.object.opacity = 0.5
texturestringNombre de la textura asignada.object.texture = "player.png"
textureTilingX, textureTilingYnumberRepeticion de la textura.object.textureTilingX = 2
textureOffsetX, textureOffsetYnumberDesplazamiento de la textura.object.textureOffsetX += deltaTime
textureFlipX, textureFlipYbooleanVoltea la textura.object.textureFlipX = true
pixelPerfectbooleanRender de textura con aspecto pixel art.object.pixelPerfect = true
animationstringID de animacion asignada.debug(object.animation)
animationPlayingbooleanActiva o pausa la animacion.object.animationPlaying = true
animationRunInPlaybooleanIndica si la animacion arranca en Play.object.animationRunInPlay = true
particleSystemstringID del sistema de particulas asignado.debug(object.particleSystem)
particlesPlayingbooleanActiva o pausa particulas.object.particlesPlaying = true
particlesRunInPlaybooleanIndica si las particulas arrancan en Play.object.particlesRunInPlay = true
particlesDetachedbooleanPermite que la estela de particulas quede separada del objeto.object.particlesDetached = true
collisionEnabledbooleanMarca el collider como activo.object.collisionEnabled = true
isTriggerbooleanMarca el collider como trigger.object.isTrigger = true
colliderobjectDatos del collider: shape, offsetX/Y, width/height y radius.object.collider.shape = "capsule"
scriptstringNombre del script asignado.debug(object.script)

Si un objeto tiene isStatic = true, se recomienda no moverlo, rotarlo, escalarlo ni cambiar su jerarquia durante Play. Esta marca sirve para que el motor pueda optimizar render, colisiones, navegacion y otros sistemas en el futuro.

Ciclo de activacion: si active es false, no se ejecutan los componentes, las colisiones ni el script del objeto. Tambien se aplica cuando uno de sus padres esta inactivo. Si se activa despues de iniciar la escena, start(object) se ejecuta entonces una sola vez y antes del primer update(object, deltaTime). Los componentes automaticos, como Audio Source / Play On Start, arrancan al activarse.

8. API de debug

Los mensajes aparecen en la pestaña Console del panel inferior del editor.

FuncionUsoEjemplo
debug(value)Muestra cualquier valor.debug("Hola")
Debug.log(value)Mensaje normal.Debug.log(object.name)
Debug.warn(value)Mensaje de aviso.Debug.warn("Vida baja")
Debug.error(value)Mensaje de error.Debug.error("No hay objetivo")
Debug.clear()Limpia la consola.Debug.clear()
export function start(object) {
    Debug.log({ nombre: object.name, posicion: { x: object.x, y: object.y } });
}

9. Esperas con Wait

Wait permite pausar una funcion asincrona, parecido a una corrutina. Para usarlo, la funcion debe declararse con async.

FuncionUsoEjemplo
await Wait.seconds(segundos)Espera una cantidad de segundos.await Wait.seconds(0.2)
await Wait.frames(frames)Espera una cantidad de 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");
}

Animaciones de propiedades con Tween

Tween cambia suavemente propiedades numericas durante Play. Sirve para mover, rotar, escalar o desvanecer objetos sin programar la interpolacion dentro de update. La duracion y los retrasos se expresan en segundos.

FuncionUsoEjemplo
Tween.to(target, values, duration, options)Anima desde los valores actuales hasta los indicados.Tween.to(object, { x: 400 }, 1)
Tween.from(target, values, duration, options)Coloca los valores iniciales y anima hasta los que tenia el objeto.Tween.from(object, { opacity: 0 }, 0.5)
Tween.cancel(target)Cancela todos los tweens de un objeto.Tween.cancel(object)
Tween.cancel(target, property)Cancela solo los tweens de una propiedad.Tween.cancel(object, "x")
Tween.cancelAll()Cancela todos los tweens activos.Tween.cancelAll()
Tween.isTweening(target, property)Comprueba si existe un tween activo.Tween.isTweening(object, "x")
Tween.pauseAll()Pausa todos los tweens.Tween.pauseAll()
Tween.resumeAll()Reanuda todos los 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
    });
}

Opciones disponibles: ease, delay, repeat, repeatDelay, yoyo, paused, overwrite, onStart, onUpdate, onRepeat, onComplete y onCancel. Por defecto, un tween nuevo cancela tweens anteriores que modifiquen las mismas propiedades del mismo objeto. Usa overwrite: false para permitirlos.

Curvas incluidas: linear, easeIn, easeOut, easeInOut, quadIn, quadOut, quadInOut, cubicIn, cubicOut, cubicInOut, backIn, backOut, sineIn, sineOut y 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" o "cancelled"
}

El valor devuelto permite pause(), resume(), cancel() y complete(). Tambien se puede esperar directamente con await. Los tweens se cancelan automaticamente al salir de Play, destruir su objeto o cambiar de escena.

Tween solo interpola propiedades numericas. Si un componente fisico o un script modifica al mismo tiempo la misma propiedad, ambos sistemas competiran por el valor.

10. Buscar objetos

FuncionDevuelveEjemplo
FindByName(name)El primer objeto con ese nombre o null.FindByName("Player")
FindByTag(tag)El primer objeto con ese tag o null.FindByTag("Enemy")
FindAllByName(name)Array con todos los objetos activos que tengan ese nombre.FindAllByName("Coin")
FindAllByTag(tag)Array con todos los objetos activos que tengan ese tag.FindAllByTag("Enemy")
FindAllByComponent(type)Array de objetos activos con ese componente.FindAllByComponent("PhysicsBody")
FindAllInArea(x, y, w, h)Objetos activos cuyos limites se solapan con el rectangulo indicado.FindAllInArea(0, 0, 800, 600)
export function start(object) {
    const player = FindByName("Player");

    if (player) {
        debug("Jugador encontrado en 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;
}

Grupos temporales

Groups permite reunir objetos durante Play sin cambiar su nombre, tag o jerarquia. Los grupos se vacian automaticamente al cambiar de escena.

Groups.create(name, objects)Crea un grupo y anade una lista opcional.
Groups.add(name, object)Anade un objeto.
Groups.remove(name, object)Quita un objeto.
Groups.get(name)Devuelve los miembros validos.
Groups.has(name, object)Comprueba si pertenece al grupo.
Groups.forEach(name, callback)Ejecuta una funcion para cada miembro.
Groups.setActive(name, active)Activa o desactiva todos sus miembros.
Groups.clear(name)Vacia el grupo.
Groups.delete(name)Elimina el grupo.
Groups.names()Devuelve todos los nombres de grupo.
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. Destruir objetos

FuncionUsoEjemplo
Destroy(object)Destruye un objeto al momento.Destroy(enemy)
Destroy(object, tiempo)Destruye un objeto tras unos segundos.Destroy(object, 2)

Si destruyes un objeto que tiene hijos, tambien se destruyen sus hijos. Destroy solo debe usarse durante Play.

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

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

Instanciar prefabs desde codigo

Prefab permite crear copias de prefabs durante Play. El prefab debe existir en la pestana Prefabs del proyecto.

FuncionUsoEjemplo
await Prefab.instantiate(nombre)Crea una copia del prefab.await Prefab.instantiate("Enemy")
await Prefab.instantiate(nombre, opciones)Crea una copia con posicion, nombre o padre.await Prefab.instantiate("Bullet", { x: 100, y: 40 })
await Prefab.create(nombre, opciones)Alias de instantiate.await Prefab.create("Coin")
await Prefab.spawn(nombre, opciones)Alias de instantiate.await Prefab.spawn("Explosion")

Si el prefab tiene un solo objeto raiz, la funcion devuelve ese objeto. Si el prefab tiene varios objetos raiz, devuelve una lista. Los scripts del prefab se cargan y empiezan a ejecutarse en Play.

OpcionTipoDescripcion
xnumberPosicion X del objeto raiz.
ynumberPosicion Y del objeto raiz.
offsetXnumberDesplazamiento X si no indicas x e y.
offsetYnumberDesplazamiento Y si no indicas x e y.
namestringNombre base para la copia creada.
parentobjectObjeto que sera el padre del prefab instanciado.
rotationnumberRotacion inicial del objeto raiz.
scaleXnumberEscala X inicial del objeto raiz.
scaleYnumberEscala Y inicial del objeto raiz.
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 solo se usa durante Play y necesita Tauri para leer el prefab guardado en el proyecto.

Pool de prefabs

Pool precarga copias inactivas y las reutiliza. Es recomendable para balas, enemigos, monedas y explosiones que aparecen muchas veces.

await Pool.create(name, prefab, size)Crea el pool y precarga la cantidad indicada.
await Pool.spawn(name, { x, y })Obtiene y activa una copia. Si no queda ninguna, amplía el pool por defecto.
Pool.release(object)Desactiva y devuelve el objeto a su pool.
Pool.releaseAll(name)Devuelve todos los miembros activos.
Pool.get(name)Devuelve tamaño, activos y disponibles.
Pool.has(name)Comprueba si existe.
Pool.clear(name)Elimina el registro del 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);
}

Los pools son temporales y se limpian al cambiar de escena. Usa Pool.release en vez de Destroy para devolver una instancia reutilizable.

12. Cargar escenas

Scene.load carga una escena del proyecto por nombre. Durante Play mantiene el juego en marcha, cambia a la nueva escena y arranca los scripts de los objetos de esa escena.

FuncionUsoEjemplo
await Scene.load(nombre)Carga una escena por nombre.await Scene.load("Level1")
await Scene.load(nombre, opciones)Permite una transicion de fundido.await Scene.load("Boss", { transition: "fade", duration: 0.4 })
await Scene.reload()Recarga la escena actual.await Scene.reload()
await Scene.preload(nombre)Lee y deja preparada una escena para acelerar el siguiente load.await Scene.preload("Boss")
Scene.currentNombre de la escena actual.debug(Scene.current)
Scene.getCurrent()Devuelve el nombre de la escena actual.Scene.getCurrent()
Scene.onLoad(callback)Registra una funcion al terminar una carga y devuelve una funcion para cancelarla.Scene.onLoad(name => debug(name))
Scene.onUnload(callback)Registra una funcion antes de abandonar la escena.Scene.onUnload(name => debug(name))
export async function start(object) {
    await Wait.seconds(2);
    await Scene.load("Level1");
}

Transicion Fade

Puedes pasar opciones como segundo parametro. Con transition: "fade", la pantalla se funde a negro, el motor cambia de escena cuando ya esta cubierta y despues muestra gradualmente la nueva escena. Usa duration para indicar los segundos de cada fase del fundido.

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

Usa await para esperar hasta que la carga y el fundido hayan terminado. Si omites duration, se usan 0.3 segundos. Sin opciones, el cambio es inmediato: await Scene.load("Level2").

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

El nombre debe coincidir con una escena existente del proyecto. No escribas la extension del archivo. Scene.vars, los grupos y los pools se reinician al cambiar de escena.

13. API de animaciones

Animaciones Sprite y Property

El editor separa los dos sistemas para que no se mezclen. La pestana Animations contiene exclusivamente clips Sprite con texturas y FPS. La pestana Timeline contiene exclusivamente clips Property organizados mediante pistas y fotogramas clave.

Para crear un clip de propiedades abre Timeline y pulsa New Property. Asigna despues ese clip desde el campo Animation Timeline del Inspector del objeto. Timeline usa automaticamente ese objeto como Target Object; no se selecciona dentro del editor. El nombre y el ID indican siempre que objeto se esta editando. Elige una pista y coloca el cursor en el tiempo deseado. Pulsa Add/Update Key para capturar el valor actual del objeto. Modifica el objeto, mueve el tiempo y anade otra clave; el motor interpolara los valores entre ambas.

Para asignarlo a un objeto usa el campo Animation Timeline de la seccion Timeline Animator del Inspector. El campo Animation queda reservado exclusivamente para animaciones Sprite. Al abrir la pestana Timeline con ese objeto seleccionado, el editor carga su clip asignado y permite verlo con Play.

PistaPropiedad animada
Position X / YPosicion local x e y.
RotationRotacion del objeto en grados.
Scale X / YEscala independiente de cada eje.
OpacityOpacidad interpolada del objeto.
ColorColor interpolado entre dos claves.
  • Duration define la duracion total del clip en segundos.
  • Target Object muestra automaticamente el objeto que tiene el clip asignado en su campo Animation Timeline.
  • Local Position marcado aplica el desplazamiento del clip desde la posicion inicial de cada objeto; desmarcado usa los valores X/Y absolutos del clip.
  • El panel Timeline se acopla en la parte inferior del editor para mantener visible la escena mientras transformas el objeto.
  • La linea roja es el cabezal de reproduccion: indica el instante actual y avanza sobre las pistas durante la previsualizacion.
  • Play reproduce desde el tiempo actual, Pause y Stop conservan la posicion, y Rewind vuelve al inicio.
  • Los controles de reproduccion conservan el zoom y la zona visible del Timeline.
  • Activa Follow Playhead para que la vista horizontal siga automaticamente la linea roja durante la reproduccion.
  • Al mover el cursor se actualizan en vivo posicion, escala, rotacion, opacidad y color del objeto objetivo.
  • Al cerrar Timeline, cambiar de pestana o entrar en Play se restaura automaticamente el estado original.
  • Loop repite el clip continuamente.
  • Pingpong reproduce de ida y vuelta cuando Loop esta activo.
  • Pulsa un rombo para seleccionar su tiempo.
  • Arrastra un rombo horizontalmente con el raton para cambiar el tiempo de ese fotograma clave y previsualizar el resultado.
  • Selecciona un rombo y pulsa Duplicate Key para copiarlo 0,10 segundos mas adelante.
  • Usa Zoom - y Zoom + para comprimir o ampliar horizontalmente el Timeline entre 50% y 400%.
  • Pulsa con el boton derecho sobre un rombo para eliminar esa clave.

Los clips Property se asignan y reproducen desde el Inspector igual que los clips Sprite. Tambien funcionan con la misma API Animations y se incluyen en el juego exportado.

Control desde scripts

Animations permite asignar y controlar animaciones desde un script. Puedes usar el ID o el nombre de la animacion.

FuncionUsoEjemplo
Animations.find(nombreOId)Busca una animacion.Animations.find("Run")
Animations.assign(object, nombreOId)Asigna una animacion al objeto.Animations.assign(object, "Run")
Animations.play(object)Reproduce la animacion asignada.Animations.play(object)
Animations.play(object, nombreOId)Asigna y reproduce una animacion.Animations.play(object, "Jump")
Animations.stop(object)Detiene la animacion.Animations.stop(object)
Animations.enable(object)Activa que arranque automaticamente en Play.Animations.enable(object)
Animations.disable(object)Desactiva el arranque automatico y la detiene.Animations.disable(object)
Animations.activate(object)Alias de enable.Animations.activate(object)
Animations.deactivate(object)Alias de 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. API de particulas

Particles permite asignar y controlar sistemas de particulas desde un script. Puedes usar el ID o el nombre del sistema.

FuncionUsoEjemplo
Particles.find(nombreOId)Busca un sistema de particulas.Particles.find("Explosion")
Particles.assign(object, nombreOId)Asigna particulas al objeto.Particles.assign(object, "Smoke")
Particles.play(object)Reproduce las particulas asignadas.Particles.play(object)
Particles.play(object, nombreOId)Asigna y reproduce particulas.Particles.play(object, "Explosion")
Particles.stop(object)Detiene las particulas.Particles.stop(object)
Particles.enable(object)Activa que arranquen automaticamente en Play.Particles.enable(object)
Particles.disable(object)Desactiva el arranque automatico y las detiene.Particles.disable(object)
Particles.activate(object)Alias de enable.Particles.activate(object)
Particles.deactivate(object)Alias de 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. Ejemplos completos

Mover un objeto

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

Rotar constantemente

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

Parpadear cambiando opacidad

let time = 0;

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

Seguir al jugador

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;
}

Eliminar enemigos por tag

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

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

Cambiar de escena tras una espera

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

Follow Camera

La camara de Play puede seguir automaticamente a un objeto por tag. En el panel izquierdo Scene > Camera, activa Follow Player y elige el tag del objeto que quieres seguir, por ejemplo Player.

PropiedadUso
Follow PlayerActiva el seguimiento de camara durante Play.
TagTag del objeto que seguira la camara. La lista sale de los tags de la escena.
Dead Zone X/YZona muerta antes de mover la camara. Sirve para que el personaje pueda moverse un poco sin arrastrar la camara.
SmoothRespuesta del seguimiento entre 0 y 1. 0 no mueve la camara, 1 sigue inmediatamente.
Lock X/YBloquea el seguimiento en un eje.
Offset X/YDesplaza el punto de seguimiento respecto al centro del objeto.
BoundsLimita la camara dentro de un rectangulo de mundo con min/max X/Y.
EffectFiltro visual aplicado solo durante Play: None, Scanlines, CRT, Noir, Sepia o Dream.
FXIntensidad del efecto entre 0 y 1.
Scanline SizeSeparacion de las lineas cuando usas Scanlines o CRT.
VignetteOscurece suavemente los bordes de la camara.
NoiseAnade ruido ligero tipo pantalla antigua. Tambien se activa con CRT.

Los fondos con componente Parallax usan esta camara cuando no tienen target manual. Por eso el parallax se mueve de forma natural al activar Follow Player.

API de Camera

Camera permite mover la camara de juego desde scripts durante Play. Si Follow Player esta activo, el seguimiento puede volver a moverla en el siguiente frame; usa { disableFollow: true } cuando quieras colocarla manualmente.

FuncionUsoEjemplo
Camera.moveTo(x, y)Mueve la esquina superior izquierda de la camara a una posicion del mundo.Camera.moveTo(400, 120)
Camera.setPosition(x, y)Alias de moveTo.Camera.setPosition(0, 0)
Camera.centerOn(x, y)Centra la camara en un punto del mundo.Camera.centerOn(player.x, player.y)
Camera.getPosition()Devuelve { x, y } con la posicion actual de la camara.const pos = Camera.getPosition()
Camera.getRect(margen)Devuelve el rectangulo visible de camara con margen opcional.const rect = Camera.getRect(32)
Camera.isObjectOutside(object, margen)Indica si el objeto completo esta fuera de camara. El margen opcional amplía el rectangulo.Camera.isObjectOutside(enemy, 64)
object.isOutsideCamera(margen)Metodo directo del objeto para saber si salio de camara.object.isOutsideCamera(64)
await Camera.fadeOut(tiempo, color)Oscurece la camara hasta cubrirla con el color indicado. El color por defecto es negro.await Camera.fadeOut(1)
await Camera.fadeIn(tiempo, color)Quita el color de fade y vuelve a mostrar la escena.await Camera.fadeIn(0.8, "#000")
await Camera.fade(tipo, tiempo, color)Funcion generica. tipo puede ser "in" o "out".await Camera.fade("out", 1, "black")
Camera.cutToBlack(color)Corte instantaneo a color, por defecto negro.Camera.cutToBlack()
Camera.clearFade()Quita cualquier fade activo de forma instantanea.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 });
    }
}

Detectar salida de camara

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

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

Fade para cambio de escena

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

16. UI Canvas

La UI de usuario se dibuja dentro del canvas del juego. En el editor se coloca dentro del rectangulo de camara y en Play aparece como Screen Space Overlay, encima de la escena y sin moverse con la camara del mundo.

Desde Add GameObject puedes crear: UI Canvas, UI Panel, UI Text, UI Image, UI Button, UI Input, UI Checkbox, UI Select, UI Progress Bar y UI Slider.

ControlUso
UI PanelFondo o contenedor visual. Los hijos UI se colocan relativos al panel en Play.
UI TextTexto para puntuacion, mensajes, nombres o etiquetas.
UI ImageImagen desde Textures o bloque de color si no tiene imagen asignada. No usa texto ni fuente.
UI ButtonBoton interactivo. Tiene color normal, color Hover al pasar el puntero y color Pressed mientras se pulsa. Desde script puedes escuchar click con UI.onClick.
UI InputCampo editable durante Play. En móvil abre automáticamente el teclado virtual del sistema.
UI CheckboxValor verdadero/falso interactivo. Tiene color Hover al pasar el puntero por encima.
UI SelectLista desplegable estilo HTML select. En Play abre sus opciones, resalta la opcion bajo el puntero, permite elegir una y dispara UI.onChange al cambiar. Si hay demasiadas opciones muestra barra de desplazamiento.
UI Progress BarBarra no interactiva para vida, energia, carga o experiencia. Usa Value, Min, Max y color Fill.
UI SliderControl interactivo de valor numerico. En Play se puede arrastrar y dispara UI.onChange.

Canvas UI en móvil

Los controles interactivos de Canvas UI funcionan tanto con ratón como con pantalla táctil: UI Button, UI Checkbox, UI Select y UI Slider responden al dedo. Al tocar un UI Input, GameCrom abre el teclado virtual del móvil y sincroniza el texto con UI.getValue y UI.onChange.

En el Inspector, Input Type permite elegir Text, Number, Email o Password. Esta opción solicita al dispositivo el teclado más adecuado. Password oculta visualmente los caracteres, aunque el valor continúa disponible para el script como texto. Los elementos puramente visuales —paneles, textos, imágenes y barras de progreso— se muestran normalmente en móvil, pero no capturan pulsaciones.

La UI usa Rect Transform: Anchor, Pivot, offset X/Y, tamano y orden Z. Para crear ventanas, haz un UI Panel y mete textos, botones, inputs, checks, selects, sliders o barras como hijos en la jerarquia. Anchor funciona como preset: al elegir Center, Top Right, Bottom, etc. el control se coloca en esa zona, ajusta su Pivot y deja el offset X/Y a cero. Despues puedes moverlo con X/Y como margen desde ese anchor. En Play los hijos UI se dibujan encima de su padre aunque tengan menor Z. Todos los controles tienen Opacity. El campo Font permite elegir Arial o cualquier fuente importada en Fonts. Los controles con texto tienen Align y V Align para alinear el texto a izquierda, centro, derecha, arriba, medio o abajo. UI Text puede activar Multiline para trabajar como bloque de texto: acepta saltos de linea con \n, Word Wrap, Line Height, Max Lines y Overflow en modo Clip, Visible o Ellipsis. Los objetos UI tambien pueden llevar un Script igual que cualquier otro objeto: reciben start(object) y update(object, deltaTime) solo durante Play. En UI Select, las opciones se editan en el Inspector como una lista: puedes añadir, borrar y cambiar cada opción por separado. Visible Rows controla cuantas opciones se ven antes de activar scroll y Row Height permite ajustar la altura de cada fila del desplegable. UI Panel y UI Button tienen Corner Radius para redondear bordes.

API de UI

FuncionUsoEjemplo
UI.find(name)Busca un objeto UI por nombre.UI.find("ScoreText")
UI.show(target)Muestra y activa un control.UI.show("PausePanel")
UI.hide(target)Oculta un control en Play.UI.hide("PausePanel")
UI.setText(target, text)Cambia el texto visible.UI.setText(score, "100")
UI.getValue(target)Lee input, checkbox, select, slider, progress bar o texto.UI.getValue("VolumeSlider")
UI.setValue(target, value)Cambia el valor interno.UI.setValue("MusicCheck", true)
UI.setRange(target, min, max, value)Cambia rango y valor de slider o progress bar.UI.setRange("HealthBar", 0, 100, 75)
UI.setImage(target, texture)Cambia la textura de una imagen UI.UI.setImage(icon, "coin.png")
UI.setButtonColors(target, normal, hover, pressed)Cambia los colores normal, hover y pulsado de un boton.UI.setButtonColors("PlayButton", "#1f8fff", "#2fb0ff", "#0d4f9a")
UI.clear(target)Limpia el valor de un input.UI.clear("NameInput")
UI.onClick(target, fn)Escucha clicks de botones.UI.onClick(button, fn)
UI.onChange(target, fn)Escucha cambios de input, checkbox, select o slider.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 asignado directamente a un UI Button.
export function start(object) {
    UI.onClick(object, () => {
        debug("Boton pulsado");
    });
}
// Progress Bar: mostrar vida del jugador.
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");

    // Ejemplo: la vida baja poco a poco.
    vida = Math.max(vida - 5 * deltaTime, 0);

    UI.setValue(healthBar, vida);
    UI.setText(healthText, `Vida: ${Math.round(vida)}`);
}
// Slider: mostrar el valor en un 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. Componentes

Los componentes anaden comportamiento o datos extra a un objeto. Selecciona un objeto, pulsa Add Component en el Inspector y busca el componente que quieres anadir.

Audio Source

Audio Source reproduce sonidos del proyecto desde un objeto. Sus parametros son: sonido, volumen, pitch, loop, play on start y enabled.

Los sonidos del proyecto se cargan en memoria al abrir/refrescar el proyecto. Audio Source no carga sonidos en caliente durante Play; si un sonido no esta precargado, se mostrara un error.

PropiedadUso
SoundArchivo de sonido importado en la pestana Sounds.
VolumeVolumen entre 0 y 1.
PitchTono y velocidad entre 0.1 y 4. Menos de 1 suena más grave y más lento; más de 1 suena más agudo y rápido. El valor 1 conserva el sonido original.
LoopRepite el sonido automaticamente.
Play On StartReproduce el sonido al entrar en Play.
EnabledActiva o desactiva el componente.

API de AudioSource

FuncionUsoEjemplo
AudioSource.get(object)Devuelve el componente Audio Source del objeto.AudioSource.get(object)
await AudioSource.play(object)Reproduce el sonido asignado.await AudioSource.play(object)
AudioSource.pause(object)Pausa la reproduccion actual.AudioSource.pause(object)
AudioSource.stop(object)Detiene y vuelve al inicio.AudioSource.stop(object)
AudioSource.isPlaying(object)Indica si esta sonando.AudioSource.isPlaying(object)
AudioSource.setSound(object, sound)Cambia el sonido.AudioSource.setSound(object, "jump.wav")
AudioSource.setVolume(object, volume)Cambia el volumen.AudioSource.setVolume(object, 0.5)
AudioSource.getPitch(object)Devuelve el pitch actual.AudioSource.getPitch(object)
AudioSource.setPitch(object, pitch)Cambia velocidad y tono entre 0.1 y 4.AudioSource.setPitch(object, 1.5)
AudioSource.setLoop(object, loop)Activa o desactiva loop.AudioSource.setLoop(object, true)
AudioSource.setEnabled(object, enabled)Activa o desactiva el componente.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 procesa el sonido del Audio Source que esta en el mismo objeto. Se pueden anadir varios Audio Effect: el motor los conecta en el mismo orden en que aparecen en la lista de componentes.

El objeto necesita un Audio Source. Por ejemplo, puedes encadenar Filter → Delay → Reverb. En equipos de poca potencia conviene limitar el numero de reverbs y delays que suenan simultaneamente.

EfectoParametrosUso habitual
ReverbMix, Duration y DecayHabitaciones, cuevas, salas y espacios grandes.
Delay / EchoMix, Delay Time y FeedbackEcos y repeticiones. Feedback alto produce mas repeticiones.
FilterLow/High/Band Pass, Frequency, Resonance y MixSonido bajo el agua, detras de paredes, radios o telefonos.
DistortionAmount y MixMotores, armas, impactos y sonido saturado.
Stereo PanPan de -1 a 1 y MixColoca el sonido a la izquierda o derecha.
PitchPitch de 0.1 a 4Cambia velocidad y tono; 1 conserva el sonido original.

API de Audio Effect

FuncionUso
AudioEffect.getAll(object)Devuelve todos los efectos en el orden de la cadena.
AudioEffect.get(object, index)Devuelve un efecto por su indice, empezando en 0.
AudioEffect.setEnabled(object, index, enabled)Activa o desactiva un efecto.
AudioEffect.setMix(object, index, mix)Cambia la mezcla seca/procesada entre 0 y 1.
AudioEffect.setReverb(object, index, options)Configura duration, decay y mix.
AudioEffect.setDelay(object, index, options)Configura time, feedback y mix.
AudioEffect.setFilter(object, index, options)Configura type, frequency, resonance y mix.
AudioEffect.setDistortion(object, index, amount, mix)Configura la distorsion.
AudioEffect.setPan(object, index, pan)Configura panorama entre -1 y 1.
AudioEffect.setPitch(object, index, pitch)Configura pitch entre 0.1 y 4.

Ejemplo: delay y reverb

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

    // Segundo 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);
    }
}

Empuje directo en objetos

Para aplicar fuerza no necesitas anadir Physics Body manualmente. Puedes llamar a estas funciones directamente desde el objeto y el motor creara el componente fisico automaticamente si hace falta.

FuncionUsoEjemplo
object.addForwardForce(amount, axis)Empuja el objeto hacia donde mira. axis indica que eje del sprite es el frente.object.addForwardForce(500, "x")
object.addForce(x, y)Aplica fuerza en una direccion concreta.object.addForce(0, -650)
object.setGravity(enabled, scale)Activa/desactiva gravedad. Crea Physics Body si falta.object.setGravity(false)
object.forward(axis)Devuelve el vector frontal del objeto.object.forward("-y")

Anade Physics Body en el editor solo cuando quieras configurar masa, drag, rebote, friccion, gravedad o bloqueo de ejes visualmente.

Ejemplo: nave tipo Asteroids

Para una nave tipo Asteroids, desactiva la gravedad y aplica empuje en la direccion hacia la que mira la nave. Si quieres que no acelere infinitamente, anade Physics Body en el editor y sube un poco 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")) {
        // Usa "x" si el sprite mira a la derecha por defecto.
        // Usa "-y" si el sprite mira hacia arriba por defecto.
        object.addForwardForce(520 * deltaTime, "x");
    }
}

Bouncy Ball

Bouncy Ball convierte un objeto en una bola tipo Pong o Arkanoid. No necesita Physics Body: usa su propia velocidad interna y rebota contra los colliders de la escena.

Al anadir este componente, el motor activa Collision, desactiva Trigger y marca el objeto como no Static. Usa colliders en paredes, palas, bloques y limites para que la bola pueda rebotar.

PropiedadUso
EnabledActiva o desactiva el componente.
Start On PlaySi esta activo, la bola empieza a moverse al entrar en Play.
SpeedVelocidad de la bola en pixeles por segundo.
AngleDireccion inicial de salida en grados. 0 derecha, 90 abajo, -90 arriba y 180 izquierda.
Constant SpeedMantiene la misma velocidad despues de cada rebote.

API de Bouncy Ball

FuncionUsoEjemplo
BouncyBall.get(object)Devuelve el componente Bouncy Ball.BouncyBall.get(ball)
BouncyBall.setSpeed(object, speed)Cambia la velocidad.BouncyBall.setSpeed(ball, 420)
BouncyBall.getSpeed(object)Devuelve la velocidad actual.BouncyBall.getSpeed(ball)
BouncyBall.launch(object, angle, speed)Lanza la bola con angulo y velocidad opcional.BouncyBall.launch(ball, -45, 360)
BouncyBall.stop(object)Detiene la bola.BouncyBall.stop(ball)
object.setBouncySpeed(speed)Version directa desde el objeto.object.setBouncySpeed(500)
object.launchBouncy(angle, speed)Lanza la bola desde el propio objeto.object.launchBouncy(-45, 360)

Ejemplo: bola de Pong o Arkanoid

Crea una bola, anade el componente Bouncy Ball y activa Start On Play. Despues coloca colliders en las paredes, la pala y los bloques. Para Pong suele funcionar bien salir en diagonal. Para Arkanoid puedes relanzarla desde abajo cuando pierdes una vida.

// Script de la bola
export function start(object) {
    // Sale hacia arriba y a la derecha.
    object.launchBouncy(-45, 360);
}

export function update(object) {
    // Relanzar la bola durante pruebas.
    if (Input.getKeyDown("R")) {
        object.launchBouncy(-45, 360);
    }

    // Subir velocidad poco a poco.
    if (Input.getKeyDown("Space")) {
        const speed = BouncyBall.getSpeed(object);
        BouncyBall.setSpeed(object, speed + 40);
    }
}

Ejemplo: pala de Arkanoid

La pala solo necesita moverse y tener Collision activo. La bola rebotara contra ella porque el componente Bouncy Ball gestiona su propia direccion despues del choque.

// Script de la pala
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 Mover

Waypoint Mover mueve un objeto siguiendo una lista de puntos de mundo. Sirve para patrullas, plataformas, enemigos voladores, camaras, decoracion en movimiento o cualquier objeto que deba recorrer una ruta durante Play.

En el editor, al seleccionar el objeto, veras los puntos WP y las flechas de ruta. El componente solo mueve el objeto durante Play.

PropiedadUso
SpeedVelocidad en pixeles por segundo.
LoopAl llegar al final vuelve a empezar.
Ping PongRecorre la ruta hacia delante y luego hacia atras.
RandomElige el siguiente waypoint al azar, evitando repetir el punto actual cuando hay mas de uno.
Move Points With ObjectAl mover el objeto en el editor, desplaza todos sus waypoints por la misma distancia. Es util para recolocar de una vez el objeto y su ruta completa. Funciona al arrastrar el objeto y al cambiar sus valores X/Y en el inspector; no modifica el movimiento durante Play.
Rotate To TargetRota el objeto mirando al waypoint al que se mueve.
Flip XInvierte la textura en X cuando el objeto se mueve hacia la izquierda y la restaura al moverse hacia la derecha.
Flip YInvierte la textura en Y cuando el objeto se mueve hacia arriba y la restaura al moverse hacia abajo.
Pause Min/MaxPausa aleatoria general entre puntos.
Waypoint P Min/P MaxPausa aleatoria especifica para ese punto.
Rotation OffsetAjuste en grados si el sprite no mira hacia la derecha por defecto.
Arrive DistanceDistancia a la que se considera que el objeto ya ha llegado.

Para recolocar una patrulla completa, activa Move Points With Object antes de mover el objeto. Desactivalo si quieres cambiar la posicion inicial del objeto sin desplazar la ruta.

API de Waypoint Mover

FuncionUsoEjemplo
WaypointMover.get(object)Devuelve el componente.WaypointMover.get(enemy)
WaypointMover.setSpeed(object, speed)Cambia la velocidad.WaypointMover.setSpeed(enemy, 180)
WaypointMover.setLoop(object, loop, pingPong)Cambia loop y opcionalmente ping pong.WaypointMover.setLoop(enemy, true, true)
WaypointMover.setRandom(object, random)Activa o desactiva el modo aleatorio.WaypointMover.setRandom(enemy, true)
WaypointMover.setRotateToWaypoint(object, enabled, offset)Activa rotacion hacia el objetivo.WaypointMover.setRotateToWaypoint(enemy, true, 0)
WaypointMover.setFlip(object, flipX, flipY)Activa flip automatico segun direccion.WaypointMover.setFlip(enemy, true, false)
WaypointMover.setPause(object, min, max)Cambia pausa aleatoria general.WaypointMover.setPause(enemy, 0.2, 1)
WaypointMover.setWaypoints(object, points)Reemplaza la ruta completa.WaypointMover.setWaypoints(enemy, points)
WaypointMover.addWaypoint(object, x, y)Anade un punto por codigo.WaypointMover.addWaypoint(enemy, 400, 120)
WaypointMover.clearWaypoints(object)Borra la ruta.WaypointMover.clearWaypoints(enemy)
WaypointMover.goTo(object, index)Fuerza el siguiente waypoint.WaypointMover.goTo(enemy, 2)
WaypointMover.pause(object, seconds)Pausa temporalmente.WaypointMover.pause(enemy, 2)
WaypointMover.resume(object)Reanuda el movimiento.WaypointMover.resume(enemy)
WaypointMover.reset(object)Reinicia el ciclo.WaypointMover.reset(enemy)
object.setWaypointSpeed(speed)Version directa desde el objeto.object.setWaypointSpeed(200)
object.goToWaypoint(index)Version directa para cambiar objetivo.object.goToWaypoint(1)

Ejemplo: patrulla con ping pong

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);
}

Ejemplo: enemigo que elige puntos al azar

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

Ejemplo: cambiar movimiento durante 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 convierte un objeto en un agente capaz de buscar y seguir automaticamente una ruta alrededor de los objetos con colision. Es util para enemigos que persiguen al player, NPC, unidades de estrategia o personajes que deben llegar a un punto sin atravesar muros.

Anade el componente desde Add Component > Pathfinding Agent. Los colliders activos forman los obstaculos; los objetos marcados como trigger no bloquean la ruta. Activa Debug Path para ver la ruta en color magenta durante Play en el editor.

PropiedadUso
Target ModeBusca el destino por tag, por nombre o usa unas coordenadas fijas.
Target Tag / NameTag o nombre del objeto que el agente debe perseguir.
Destination X/YDestino fijo cuando el modo seleccionado es Position.
SpeedVelocidad de movimiento en pixeles por segundo.
Cell SizeTamano de cada celda de busqueda. Un valor pequeno da rutas mas precisas, pero necesita mas calculo.
PaddingMargen adicional alrededor de los obstaculos para evitar rozarlos.
Arrive DistanceDistancia a la que el destino se considera alcanzado.
Repath IntervalSegundos entre recalculos mientras el objetivo se mueve. Bajarlo mejora la reaccion y aumenta el trabajo de CPU.
Max NodesLimite de celdas que puede explorar una busqueda.
DiagonalPermite rutas y movimiento diagonal.
Rotate To TargetOrienta el objeto en la direccion de movimiento.
Flip X/YInvierte automaticamente el sprite segun la direccion.
Rotation OffsetCorrige la orientacion si el sprite no mira hacia la derecha por defecto.

API de Pathfinding Agent

FuncionUso
PathfindingAgent.get(object)Devuelve el componente del objeto.
PathfindingAgent.setEnabled(object, enabled)Activa o desactiva el agente.
PathfindingAgent.setTarget(object, target)Hace que persiga un objeto concreto.
PathfindingAgent.setDestination(object, x, y)Cambia a modo Position y busca esas coordenadas.
PathfindingAgent.setSpeed(object, speed)Cambia la velocidad.
PathfindingAgent.pause(object)Pausa el movimiento sin borrar el destino.
PathfindingAgent.resume(object)Reanuda y recalcula la ruta.
PathfindingAgent.stop(object)Detiene el agente y borra su ruta actual.
PathfindingAgent.recalculate(object)Fuerza un nuevo calculo de ruta.
PathfindingAgent.hasPath(object)Indica si existe una ruta activa.
PathfindingAgent.hasArrived(object)Indica si ha alcanzado el destino.

Ejemplo: perseguir al player

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

Ejemplo: enviar un objeto a una posicion

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

    if (PathfindingAgent.hasArrived(object)) {
        // El objeto ya ha llegado.
    }
}

Waypoint Mover sigue una ruta dibujada manualmente. Pathfinding Agent calcula la ruta y la modifica para rodear obstaculos.

Look At Target

Look At Target mantiene un objeto orientado hacia otro. Esta pensado para torretas, canones, focos, ojos, enemigos y cualquier objeto que deba seguir visualmente a un objetivo sin cambiar su posicion.

PropiedadUso
Target ModeLocaliza el objetivo por tag o por nombre.
Target Tag / NameTag o nombre del objeto al que debe mirar.
Turn SpeedVelocidad maxima de giro en grados por segundo. Con 0 gira instantaneamente.
Reaction DelayTiempo en segundos entre actualizaciones de la direccion objetivo. Con 0 sigue al target en cada frame.
Original DirectionDireccion hacia la que apunta el dibujo sin ninguna rotacion: derecha, abajo, izquierda, arriba o personalizada.
Original AngleAngulo personalizado de la orientacion original del sprite. Derecha es 0°, abajo 90°, izquierda 180° y arriba -90°.

Ejemplo: si el canon de la imagen apunta hacia arriba, selecciona Up (-90°). El componente aplicara automaticamente la correccion necesaria para que esa punta mire al target.

API de Look At Target

FuncionUso
LookAtTarget.get(object)Devuelve el componente.
LookAtTarget.setEnabled(object, enabled)Activa o desactiva la orientacion.
LookAtTarget.setTarget(object, target)Asigna directamente otro objeto como objetivo.
LookAtTarget.setTarget(object, "Enemy", "tag")Busca el objetivo por tag.
LookAtTarget.setTurnSpeed(object, speed)Cambia la velocidad de giro en grados por segundo.
LookAtTarget.setReactionDelay(object, seconds)Cambia el retardo de reaccion.
LookAtTarget.setOriginalAngle(object, angle)Indica la orientacion original del sprite.
LookAtTarget.refresh(object)Fuerza una actualizacion inmediata de la direccion.

Ejemplo: torreta que sigue al player

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

    // La imagen original del canon apunta hacia arriba.
    LookAtTarget.setOriginalAngle(object, -90);
}

Physics Body

Physics Body anade gravedad, velocidad y respuesta fisica sencilla a un objeto. Usalo para cajas, enemigos, proyectiles, objetos que caen o elementos que quieras mover con fuerzas. Para personajes jugables de plataformas sigue siendo mejor usar Character Controller.

El componente solo se actualiza durante Play. Al anadirlo, el objeto activa automaticamente Collision y deja de ser Static, porque necesita poder moverse. Los objetos con Body Type: Dynamic pueden ser empujados lateralmente por el player, por otro Character Controller o por otro Physics Body. Cuanta mas Mass tenga el objeto, mas costara moverlo.

PropiedadUso
Body TypeDynamic recibe gravedad y colisiones. Kinematic se mueve por velocidad/script, pero no recibe gravedad.
Use GravityActiva o desactiva la gravedad del componente.
Gravity ScaleMultiplica la gravedad del motor. 1 es normal, 0.5 cae mas lento y 2 cae mas rapido.
MassMasa usada por Physics.addForce y por los empujes. Mas masa significa que la misma fuerza o empuje cambia menos la velocidad.
Velocity X/YVelocidad actual en pixeles por segundo.
DragFreno gradual aplicado a la velocidad.
Max Fall SpeedLimite de velocidad al caer.
Freeze X/YBloquea el movimiento fisico en un eje.
BounceRebote al chocar. 0 no rebota; valores mayores devuelven parte de la velocidad.
FrictionReduce velocidad horizontal al tocar suelo.

API de Physics

FuncionUsoEjemplo
Physics.get(object)Devuelve el componente Physics Body.Physics.get(object)
Physics.has(object)Indica si el objeto tiene Physics Body.Physics.has(box)
Physics.getVelocity(object)Devuelve { x, y }.Physics.getVelocity(object).y
Physics.setVelocity(object, x, y)Cambia la velocidad directamente.Physics.setVelocity(object, 200, -350)
Physics.addVelocity(object, x, y)Suma velocidad a la actual.Physics.addVelocity(object, 0, -120)
Physics.addForce(object, x, y)Aplica una fuerza instantanea teniendo en cuenta la masa.Physics.addForce(object, 0, -500)
Physics.addForwardForce(object, amount, axis)Aplica fuerza hacia donde mira el objeto. axis indica que eje del sprite es el frente.Physics.addForwardForce(ship, 420, "x")
Physics.forward(object, axis)Devuelve el vector de direccion frontal del objeto.Physics.forward(ship, "-y")
Physics.stop(object)Pone velocidad X/Y a cero.Physics.stop(object)
Physics.setGravity(object, enabled, scale)Activa/desactiva gravedad y opcionalmente cambia escala.Physics.setGravity(object, true, 1.5)
Physics.setKinematic(object, kinematic)Cambia entre kinematic y dynamic.Physics.setKinematic(object, true)
Physics.setEnabled(object, enabled)Activa o desactiva el componente.Physics.setEnabled(object, false)
Physics.isGrounded(object)Indica si esta tocando suelo.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 desplaza la textura del objeto usando la camara de Play o un objeto target. Para fondos, nubes y capas de escenario, el parallax usa la camara de Play cuando no hay target asignado. Solo se movera si la camara de Play tiene Follow Player activo.

En el editor el efecto permanece estatico. El movimiento de Parallax solo se ejecuta durante Play. El objeto mantiene su posicion original y su tamano en pantalla; el componente compensa la camara y solo desplaza la textura. El target manual queda para casos especiales donde quieras que la capa responda a un objeto concreto en vez de a la camara.

PropiedadUso
TargetObjeto que controla el desplazamiento de la textura.
TargetObjeto opcional que controla el parallax. Si esta vacio se usa la camara de Play.
Speed X/YMultiplicador de desplazamiento por eje. 1 es una velocidad normal; puede ser negativo.
Smooth X/YSuavizado por eje. 0 es inmediato; valores altos suavizan mas.
Margin X/YZona muerta por eje antes de mover la textura, util para camaras tipo Mario.
Repeat X/YRepite la textura horizontal o verticalmente.
Lock X/YBloquea el movimiento de la textura en ese eje.
EnabledActiva o desactiva el componente.

API de Parallax

FuncionUsoEjemplo
Parallax.get(object)Devuelve el componente Parallax activo.Parallax.get(bg)
Parallax.setTarget(object, target)Cambia el objeto target.Parallax.setTarget(bg, player)
Parallax.setSpeed(object, x, y)Cambia velocidad X/Y.Parallax.setSpeed(bg, 1, 0)
Parallax.setSmooth(object, x, y)Cambia suavizado X/Y.Parallax.setSmooth(bg, 0.85, 0)
Parallax.setMargin(object, x, y)Cambia margen X/Y en pixeles de mundo.Parallax.setMargin(bg, 120, 0)
Parallax.setRepeat(object, x, y)Activa repeticion X/Y.Parallax.setRepeat(bg, true, false)
Parallax.setLock(object, x, y)Bloquea ejes.Parallax.setLock(bg, false, true)
Parallax.setEnabled(object, enabled)Activa o desactiva.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 mueve un personaje 2D sin tener que escribir todo el codigo de movimiento a mano. Sirve para juegos de plataformas y movimiento libre tipo top-down.

El componente solo se ejecuta durante Play. En el editor no mueve el objeto. En el Inspector se muestra una tarjeta resumida; pulsa Edit para abrir la ventana completa de configuracion en el centro de la pantalla. La ventana cambia segun el modo elegido y oculta las opciones que no se usan en ese tipo de controlador.

Parametros comunes

ParametroTipoExplicacion
ModeSelectorElige el tipo de controlador: Platformer para plataformas con gravedad o Top Down para movimiento libre en vista superior.
Analog MovementSelectorProgressive conserva la intensidad del stick: una inclinacion pequeña mueve mas despacio. Fixed convierte cualquier inclinacion que supere la zona muerta en movimiento a velocidad completa.
Gamepad Dead ZoneNumero 0-0.95Ignora pequeñas desviaciones del stick para evitar movimiento involuntario. El valor predeterminado es 0.12; normalmente se recomienda entre 0.10 y 0.20.
EnabledCheckActiva o desactiva el componente sin quitarlo del objeto.
Use CollisionsCheckUsa el sistema de colisiones del motor. En Platformer sirve para suelo, paredes, plataformas y escaleras. En Top Down mantiene el controlador preparado para contactos de mundo.
Apply AnimationsCheckCambia automaticamente la animacion del objeto cuando cambia el estado del controlador.
Flip X DirectionCheckVoltea la textura en X al cambiar la direccion horizontal. Es lo habitual para personajes que miran izquierda/derecha.
Flip Y DirectionCheckVoltea la textura en Y al cambiar la direccion vertical. Solo suele usarse en juegos top-down o casos especiales.
HorizontalCheckPermite o bloquea el movimiento en el eje X.
VerticalCheckPermite o bloquea el movimiento en el eje Y. En plataformas normalmente se deja activo para salto/gravedad; en top-down controla subir y bajar.
Move SpeedNumeroVelocidad base del personaje en pixeles por segundo.
Death StateCheckPermite usar el estado de muerte desde script con CharacterController.setDead(object, true).

Tipo Platformer

Usa Platformer para juegos laterales con gravedad: plataformas, saltos, suelo, rampas, escaleras y plataformas moviles. El controlador aplica movimiento horizontal, gravedad, salto y deteccion de suelo durante Play.

ParametroTipoExplicacion
RunCheckActiva una velocidad de carrera opcional mientras se mantiene pulsada la tecla configurada.
Run SpeedNumeroVelocidad usada al correr. Debe ser mayor que Move Speed si quieres que se note la carrera.
Run KeyTextoTecla para correr. Por defecto suele usarse Shift.
Run ButtonSelectorBoton del mando que se mantiene pulsado para correr. El valor predeterminado para Xbox es X.
JumpCheckPermite saltar. Si esta desactivado, el personaje no responde a la tecla de salto.
Jump KeyTextoTecla de salto. Por defecto suele usarse Space.
Jump ButtonSelectorBoton del mando para saltar. El valor predeterminado para Xbox es A.
Jump ForceNumeroFuerza inicial del salto. Valores mas altos hacen que el personaje suba mas rapido y mas alto.
GravityNumeroFuerza que empuja al personaje hacia abajo. Valores altos producen caidas mas rapidas.
Max FallNumeroVelocidad maxima de caida. Evita que el personaje acelere indefinidamente.
Double JumpCheckPermite saltar de nuevo en el aire.
Max JumpsNumeroTotal de saltos permitidos antes de volver a tocar suelo. Para doble salto normalmente es 2.
CrouchCheckActiva estado de agacharse.
Crouch KeyTextoTecla para agacharse. Por defecto suele usarse S.
Crouch ButtonSelectorBoton del mando que se mantiene pulsado para agacharse. El valor predeterminado para Xbox es B.
Crouch SpeedNumero 0-1Multiplicador de velocidad al agacharse. 0.5 significa moverse a la mitad de velocidad.
Use LaddersCheckPermite usar objetos con componente Ladder. Al tocar una escalera el personaje pierde la gravedad y puede subir o bajar con el input.
Ladder SpeedNumeroVelocidad al moverse por una escalera.

Para que las escaleras funcionen, el objeto escalera debe tener el componente Ladder. El personaje puede saltar desde la escalera para salir de ella.

Tipo Top Down

Usa Top Down para juegos vistos desde arriba o con movimiento libre en X/Y: aventuras, shooters, RPG de accion o juegos donde el personaje no tiene gravedad ni salto. El controlador normaliza la diagonal para que moverse en diagonal no sea mas rapido.

ParametroTipoExplicacion
Move SpeedNumeroVelocidad base para moverse en cualquier direccion.
RunCheckActiva carrera opcional tambien en top-down.
Run SpeedNumeroVelocidad usada mientras la tecla de carrera esta pulsada.
Run KeyTextoTecla para correr.
Run ButtonSelectorBoton del mando para correr. Por defecto, X.
CrouchCheckActiva un estado lento o de sigilo si tu juego lo necesita.
Crouch KeyTextoTecla para activar el estado de agachado/sigilo.
Crouch ButtonSelectorBoton del mando para activar el estado de agachado o sigilo. Por defecto, B.
Crouch SpeedNumero 0-1Multiplicador de velocidad durante el estado crouch.
HorizontalCheckPermite moverse izquierda/derecha.
VerticalCheckPermite moverse arriba/abajo.
Flip X DirectionCheckUtil para personajes que miran izquierda/derecha segun la direccion horizontal.
Flip Y DirectionCheckUtil para sprites que deban invertirse al mirar arriba/abajo.

Animaciones y sonidos por estado

ModoEstados disponiblesUso
PlatformerIdle, Move, Run, Jump, Fall, Crouch, Death, Ladder Idle, Ladder WalkPermite asignar animacion y sonido a cada estado de plataformas, incluyendo escalera.
Top DownIdle, Move, Run, Crouch, DeathSolo muestra los estados que tienen sentido sin salto, gravedad ni escaleras.
ParametroExplicacion
* AnimAnimacion asignada a un estado. Por ejemplo, Run Anim se reproduce al correr.
* SoundSonido que se reproduce al entrar en ese estado. Los sonidos no heredan de otros estados para evitar dobles disparos.
VolVolumen independiente del sonido de ese estado, entre 0 y 1.
LoopHace que el sonido del estado se repita hasta cambiar de estado o salir de Play.

Los sonidos del Character Controller usan los sonidos del panel Sounds. Se cargan al iniciar el proyecto y se mantienen en memoria; el componente solo elige cual reproducir al cambiar de estado. Si Mute in Play esta activo, estos sonidos tambien se silencian.

API de CharacterController

FuncionUsoEjemplo
CharacterController.get(object)Devuelve el componente del objeto.CharacterController.get(object)
CharacterController.isGrounded(object)Indica si el personaje esta tocando suelo.CharacterController.isGrounded(object)
CharacterController.getVelocity(object)Devuelve { x, y } con la velocidad interna.CharacterController.getVelocity(object)
CharacterController.setVelocity(object, x, y)Cambia la velocidad interna.CharacterController.setVelocity(object, 0, -300)
CharacterController.setDead(object, dead)Activa o desactiva el estado de muerte.CharacterController.setDead(object, true)
CharacterController.isDead(object)Consulta si esta en estado de muerte.CharacterController.isDead(object)
CharacterController.resetJumps(object)Restablece los saltos disponibles.CharacterController.resetJumps(object)
CharacterController.setEnabled(object, enabled)Activa o desactiva el componente.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 permite leer teclado, ratón, gamepad y touch desde scripts. La API funciona en Play. En modo editor no controla la escena ni devuelve pulsaciones para no interferir con las herramientas del editor.

Fuera de Play, Input devuelve valores neutros: false en botones/teclas, 0 en ejes y posiciones, y null en getTouch.

Teclado

FuncionUsoEjemplo
Input.getKey(key)Mientras una tecla esta pulsada.Input.getKey("A")
Input.getKeyDown(key)Solo el frame en que se pulsa.Input.getKeyDown("Space")
Input.getKeyUp(key)Solo el frame en que se suelta.Input.getKeyUp("Escape")
Input.anyKey()Alguna tecla esta pulsada.Input.anyKey()
Input.anyKeyDown()Alguna tecla se acaba de pulsar.Input.anyKeyDown()

Puedes usar letras como "A", teclas especiales como "Escape", "Enter", "Shift", "Control", "Alt", "Space", flechas como "ArrowLeft" y tambien codigos de KeyboardEvent.code como "KeyA".

Teclas habituales soportadas: "A", "B", "Escape", "Enter", "Shift", "Control", "Alt", "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown" y "Space".

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

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

Raton

Propiedad o funcionUso
Input.mouseX, Input.mouseYPosicion del raton en pantalla/canvas.
Input.mouseWorldX, Input.mouseWorldYPosicion del raton en coordenadas de mundo.
Input.mouseDeltaX, Input.mouseDeltaYMovimiento del raton durante el frame.
Input.mouseWheelMovimiento de la rueda durante el frame.
Input.getMouseButton(0)Boton izquierdo pulsado.
Input.getMouseButtonDown(0)Boton izquierdo pulsado este frame.
Input.getMouseButtonUp(0)Boton izquierdo soltado este frame.
Input.hideCursor()Oculta el puntero del raton durante Play.
Input.showCursor()Vuelve a mostrar el puntero del raton.
Input.setCursorVisible(false)Muestra u oculta el puntero con un booleano.
Input.isCursorVisible()Devuelve si el puntero esta visible.

Botones: 0 izquierdo, 1 central, 2 derecho.

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 usa la Gamepad API del navegador y normaliza mandos Xbox, PlayStation, Nintendo, USB, Bluetooth y genericos. Puede haber varios mandos conectados.

FuncionUsoEjemplo
Input.gamepadCountMandos conectados.Input.gamepadCount
Input.getButton(button)Boton pulsado.Input.getButton("A")
Input.getButtonDown(button)Boton pulsado este frame.Input.getButtonDown("Cross")
Input.getButtonUp(button)Boton soltado este frame.Input.getButtonUp("Start")
Input.getAxis(axis, deadZone?)Valor de eje entre -1 y 1. El segundo parametro permite ajustar la zona muerta; por defecto es 0.12.Input.getAxis("LeftStickX", 0.15)
await Input.vibrate(ms, fuerte, suave, indice)Activa la vibracion del mando y devuelve si esta soportada.await Input.vibrate(250, 1, 0.5, 0)
Input.stopVibration(indice)Detiene la vibracion del mando.Input.stopVibration(0)

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

Ejes soportados: LeftStickX, LeftStickY, RightStickX, RightStickY, LeftTrigger y RightTrigger.

Si hay varios mandos, puedes indicar el indice como segundo parametro: Input.getButton("A", 0). Si no indicas indice, se acepta el primer mando que tenga ese boton pulsado.

La vibracion depende del mando, navegador y sistema operativo. La intensidad fuerte y suave usa valores entre 0 y 1. Si el dispositivo no dispone de actuador, la funcion devuelve false sin detener el juego.

Activar y detener la vibracion

export async function update(object) {
    if (Input.getButtonDown("A")) {
        const supported = await Input.vibrate(
            300, // duracion en milisegundos
            1,   // motor fuerte: 0 a 1
            0.4, // motor suave: 0 a 1
            0    // indice del mando
        );

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

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

export function onExplosionStart() {
    // Empieza una vibracion larga.
    Input.vibrate(2000, 1, 1);
}

export function onExplosionEnd() {
    // La detiene antes de que terminen los 2000 ms.
    Input.stopVibration();
}

Ejes de movimiento

Horizontal y Vertical combinan teclado y gamepad. Por defecto: A/D, flechas izquierda/derecha, W/S y flechas arriba/abajo.

Movimiento vertical para Pong

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

Este ejemplo controla un solo eje con W/S, las flechas arriba/abajo y el stick izquierdo. La intensidad del stick se conserva, por lo que una inclinacion pequeña produce un movimiento mas lento.

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

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

Input.getMovementVector() combina Horizontal y Vertical y normaliza la diagonal. Asi no se mueve mas rapido al pulsar dos direcciones. En este motor Vertical devuelve positivo hacia arriba; por eso el ejemplo usa -move.y.

El teclado y el mando funcionan con la misma API tanto en Play como en los builds Web y Windows. Si pruebas una correccion del sistema de entrada, genera un build nuevo: los builds anteriores conservan el runtime con el que fueron creados.

Touch

FuncionUso
Input.touchCountNumero de dedos tocando la pantalla.
Input.getTouch(index)Devuelve { id, x, y, worldX, worldY } o null.

18.1. Controles moviles

GameCrom incluye controles tactiles visuales para que los juegos Web puedan jugarse desde moviles y tabletas. Los controles forman parte de Canvas UI, admiten varias pulsaciones a la vez y alimentan la misma API Input que el teclado y el mando. No necesitas crear una version diferente del movimiento para movil.

Crear controles tactiles

  1. Crea o selecciona un UI Canvas.
  2. Abre Add GameObject > Mobile Controls.
  3. Anade Touch Joystick, Touch D-Pad o Touch Button.
  4. Coloca el joystick o la cruceta en la parte inferior izquierda y los botones en la derecha.
  5. Configura sus ejes o su accion desde el Inspector.
  6. Opcionalmente, asigna una imagen de Textures a cada control.
  7. Pruebalo en Play con el raton o genera un build nuevo para probar multitouch en el dispositivo.
ControlFuncionConfiguracion habitual
Touch JoystickMovimiento analogico en cualquier direccion. Devuelve valores entre -1 y 1.Horizontal y Vertical.
Touch D-PadCruceta digital. Cada direccion devuelve -1, 0 o 1.Horizontal y Vertical.
Touch ButtonBoton mantenido, recien pulsado o recien soltado.Acciones como Jump, Run, Crouch, Attack o Pause.

Propiedades del Inspector

PropiedadUso
Horizontal AxisNombre del eje horizontal que recibe el joystick o la cruceta. Normalmente Horizontal.
Vertical AxisNombre del eje vertical. Normalmente Vertical; positivo significa arriba.
ActionNombre de la accion enviada por un Touch Button. Distingue mayusculas y minusculas.
ImageImagen normal del Touch Button, imagen completa del D-Pad o imagen de base del joystick.
Pressed ImageImagen que muestra un Touch Button mientras permanece pulsado. Si se deja en None, conserva la imagen normal.
Inner ImageImagen del circulo interior movil del Touch Joystick. Se recorta automaticamente con forma circular.
Inner OpacityOpacidad independiente del circulo interior del joystick, entre 0 y 1.
Visual StyleAspecto del D-Pad: 4 Arrows, 8 Arrows o Classic Cross. Solo cambia el dibujo; los tres estilos conservan el mismo funcionamiento y permiten diagonales.
Joystick ModeFixed mantiene el joystick en su posicion. Floating in Area lo oculta hasta tocar la zona y lo centra bajo el dedo.
Activation AreaZona que puede iniciar un joystick flotante: Left Half, Right Half, Full Screen o Custom Area.
Always VisibleSi esta marcado, el joystick se ve en reposo y se desplaza al punto tocado. Si no esta marcado, permanece oculto y solo aparece mientras un dedo mantiene pulsada su zona.
Area Position %Posicion X/Y del area personalizada como porcentaje de la pantalla del juego.
Area Size %Anchura y altura del area personalizada como porcentaje. Por ejemplo, X 0, Y 0, W 50, H 100 ocupa la mitad izquierda.
Dead ZoneIgnora movimientos pequenos cerca del centro del joystick. El valor recomendado inicial es 0.12.
SensitivityMultiplica la respuesta del joystick antes de limitarla al intervalo de -1 a 1.
Touch devices onlyOculta el control en equipos sin pantalla tactil. Desactivalo mientras quieras probarlo con raton en Play.
Background, Border, OpacityPersonalizan el aspecto visual. Una opacidad moderada evita tapar el juego.
Anchor, posicion y tamanoMantienen cada control unido a una esquina y permiten adaptarlo a diferentes pantallas.

Leer movimiento y acciones

En modo Floating in Area no hace falta acertar sobre un control pequeno: el primer toque dentro de la zona crea el centro del joystick en ese punto. El dedo puede desplazarse desde ese centro y, al soltarlo, el joystick vuelve a ocultarse. Los botones tactiles colocados sobre la zona tienen prioridad, por lo que siguen funcionando aunque las areas se solapen.

Al seleccionar un Touch Joystick flotante en el editor, su zona de activacion aparece marcada con lineas discontinuas y un relleno azul tenue. La guia solo pertenece al editor y no se dibuja en el juego.

export function update(object, deltaTime) {
    // Teclado, mando, joystick tactil y cruceta usan los mismos ejes.
    const x = Input.getAxis("Horizontal");
    const y = Input.getAxis("Vertical");

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

    // Verdadero mientras el boton tactil permanezca pulsado.
    if (Input.isActionPressed("Attack")) {
        // Ataque continuo.
    }

    // Solo durante el frame inicial de la pulsacion.
    if (Input.isActionDown("Jump")) {
        // Saltar una vez.
    }

    // Solo durante el frame en que se suelta.
    if (Input.isActionUp("Pause")) {
        // Abrir o cerrar el menu de pausa.
    }
}
FuncionResultado
Input.isActionPressed(name)true mientras al menos un boton de esa accion siga pulsado.
Input.isActionDown(name)true solamente en el primer frame de la pulsacion.
Input.isActionUp(name)true solamente en el frame de liberacion.
Input.isTouchDevice()Indica si el dispositivo informa de soporte tactil.

Character Controller

El Character Controller usa automaticamente los ejes Horizontal y Vertical. Tambien reconoce las acciones tactiles Jump, Run y Crouch. Para un personaje basico basta con crear un joystick y un boton cuya accion sea Jump; no hace falta modificar el componente ni escribir movimiento adicional.

Multitouch y builds

Cada dedo mantiene su propio control: el jugador puede mover el joystick y pulsar varios botones al mismo tiempo. Funciona en los builds Web y Windows cuando el dispositivo dispone de entrada tactil. Despues de modificar controles o actualizar el motor, genera un build nuevo porque un build anterior conserva el runtime con el que fue creado.

Los controles visuales y Input.getTouch(index) resuelven casos distintos. Usa los controles visuales para movimiento y acciones habituales. Usa getTouch cuando necesites posiciones de dedos, dibujar con el dedo, seleccionar objetos del mundo o implementar un gesto personalizado.

19. Colisiones 2D

El motor incluye colisiones 2D basadas en SAT. Para que un objeto participe en colisiones, activa Collision en el bloque Collider 2D del Inspector. Si activas Trigger, el objeto detecta contactos pero no empuja ni bloquea a otros objetos.

OpcionQue hace
CollisionIncluye el objeto en el sistema de colisiones durante Play.
TriggerDetecta contacto sin resolver fisicamente la colision.
One Way PlatformPermite atravesar la plataforma saltando desde abajo y caer encima desde arriba.
ShapeForma del collider. Los objetos Square usan Box por defecto; los objetos Circle usan Circle y tambien pueden usar Capsule.
OffsetDesplaza el collider respecto al centro del objeto sin mover el render.
SizeAncho y alto del collider para Box y Capsule.
RadiusRadio del collider cuando la forma es Circle.
StaticEl objeto no se mueve al resolver colisiones. Sirve para suelos, paredes y plataformas.

Las colisiones funcionan con rotacion, escala y jerarquias. El collider se ve en azul en la escena cuando el objeto esta seleccionado y Collision esta activo. Solo se actualizan en Play.

Componentes de escenario

ComponenteUso
LadderConvierte el objeto en una zona de escalera. Al anadirlo activa Collision y Trigger. El Character Controller suspende la gravedad mientras la esta tocando y puede saltar desde ella.
Moving PlatformMueve el objeto entre su posicion inicial y un offset X/Y. Al seleccionar el objeto en editor se dibuja una referencia visual con START, END, flecha de recorrido y silueta de destino sin mover la plataforma.
Conveyor BeltConvierte un collider solido en una cinta transportadora que desplaza hacia la izquierda o derecha los personajes y cuerpos fisicos apoyados encima.
Texture ScrollerAnima el offset X/Y de la textura del objeto durante Play, con velocidad configurable y control desde scripts.

Conveyor Belt

Conveyor Belt crea el efecto clasico de cinta transportadora. Mientras un objeto compatible esta apoyado encima, la cinta lo desplaza horizontalmente a la velocidad configurada. Funciona tanto en el Play del editor como en el juego exportado.

Para usarlo, selecciona el suelo o plataforma, pulsa Add Component > Conveyor Belt y ajusta sus propiedades. Al anadirlo, el editor activa automaticamente Collision y desactiva Trigger en la cinta.

PropiedadUso
EnabledActiva o desactiva el movimiento de la cinta.
DirectionElige si la cinta arrastra hacia Left o Right.
SpeedVelocidad horizontal en pixeles por segundo.
Affect CharactersArrastra objetos que tengan un componente Character Controller activo.
Affect Physics BodiesArrastra objetos que tengan un componente Physics Body activo.

El objeto transportado debe estar apoyado sobre la parte superior de la cinta y tener Character Controller o Physics Body, segun los filtros activados. La cinta no desplaza objetos decorativos sin uno de esos componentes.

API de Conveyor Belt

FuncionUsoEjemplo
ConveyorBelt.get(object)Devuelve el componente.ConveyorBelt.get(object)
ConveyorBelt.setEnabled(object, enabled)Activa o detiene la cinta.ConveyorBelt.setEnabled(object, false)
ConveyorBelt.setSpeed(object, speed)Cambia la velocidad en pixeles por segundo.ConveyorBelt.setSpeed(object, 160)
ConveyorBelt.setDirection(object, direction)Cambia la direccion a "left" o "right".ConveyorBelt.setDirection(object, "left")
ConveyorBelt.setAffects(object, characters, physicsBodies)Elige los tipos de objeto que transporta.ConveyorBelt.setAffects(object, true, false)

Texture Scroller

Texture Scroller modifica continuamente Texture Offset X y Texture Offset Y durante Play. Sirve para cintas animadas, agua, lava, nubes, fondos en movimiento o cualquier textura repetida. La textura debe tener un tiling adecuado para que el desplazamiento sea visible de forma continua.

PropiedadUso
EnabledActiva o desactiva la animacion del offset.
Speed XVelocidad horizontal positiva del offset por segundo.
Speed YVelocidad vertical positiva del offset por segundo.
Scroll RightMarcado desplaza la textura hacia la derecha; desmarcado la desplaza hacia la izquierda.
Scroll DownMarcado desplaza la textura hacia abajo; desmarcado la desplaza hacia arriba.

API de Texture Scroller

FuncionUsoEjemplo
TextureScroller.get(object)Devuelve el componente.TextureScroller.get(object)
TextureScroller.setEnabled(object, enabled)Activa o detiene el scroll.TextureScroller.setEnabled(object, true)
TextureScroller.setSpeed(object, x, y)Cambia la velocidad de los dos ejes.TextureScroller.setSpeed(object, 0.5, 0)
TextureScroller.setDirection(object, right, down)Cambia la direccion de cada eje con booleanos.TextureScroller.setDirection(object, true, false)
TextureScroller.setOffset(object, x, y)Fija inmediatamente el offset de la textura.TextureScroller.setOffset(object, 0, 0)
TextureScroller.getOffset(object)Devuelve { x, y } con el offset actual.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 en scripts

Si tu objeto tiene un script asignado, puedes exportar estas funciones. El motor las llama cuando el collider del objeto entra, permanece o sale de contacto con otro.

FuncionCuando se llama
onCollisionEnter(object, collision)Primer frame de contacto con un collider normal.
onCollisionStay(object, collision)Cada frame mientras sigue el contacto.
onCollisionExit(object, collision)Cuando termina el contacto.
onTriggerEnter(object, collision)Primer frame de contacto con un trigger.
onTriggerStay(object, collision)Cada frame mientras sigue dentro del trigger.
onTriggerExit(object, collision)Cuando sale del trigger.
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);
    }
}

Datos de collision

PropiedadContenido
collision.otherEl otro objeto del contacto.
collision.selfEl objeto que recibe el callback.
collision.normalDireccion de separacion desde el punto de vista de self.
collision.overlapProfundidad de solapamiento.
collision.pointPunto aproximado del contacto.
collision.isTriggertrue si el contacto incluye un trigger.

API Collision

FuncionUsoEjemplo
Collision.check(a, b)Comprueba si dos objetos estan colisionando ahora.Collision.check(player, enemy)
Collision.all(object)Devuelve los contactos actuales de un objeto.Collision.all(object)
Collision.contacts()Devuelve todos los contactos del frame.Collision.contacts()
export function update(object, deltaTime) {
    const enemy = FindByName("Enemy");
    const hit = Collision.check(object, enemy);

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

Events y Time

Events

Events comunica scripts sin buscar ni referenciar directamente otros objetos. Los eventos se limpian al cambiar de escena.

Events.on(name, callback)Escucha un evento y devuelve una funcion para dejar de escucharlo.
Events.once(name, callback)Escucha solamente la siguiente emision.
Events.emit(name, data)Envia datos a todos los oyentes.
Events.off(name, callback)Elimina un callback concreto.
Events.clear(name)Limpia un evento; sin nombre limpia todos.
Events.count(name)Numero de oyentes.
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.deltaTimeDelta escalado del frame.
Time.unscaledDeltaTimeDelta real, incluso con pausa o camara lenta.
Time.fixedDeltaTimePaso fijo del motor.
Time.time, Time.unscaledTimeTiempo acumulado escalado y real.
Time.frameCountFrames procesados.
Time.timeScaleEscala global: 1 normal, 0.5 camara lenta, 0 detenido.
Time.pause(), resume(), isPaused()Control de pausa.
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() solo detiene el tiempo escalado. Para detener de forma coordinada todo el juego utiliza la API global Game explicada a continuación.

Pausa global del juego

Game.pause() aplica una pausa completa y segura tanto en Editor Play como en las builds. Detiene scripts normales, física, colisiones, animaciones, partículas, tweens, pathfinding, cámara y audio. El juego continúa dibujándose y Input sigue disponible para controlar el menú.

Game.pause()Pausa el juego. Devuelve true si cambió el estado.
Game.resume()Reanuda sin saltos en animaciones ni partículas.
Game.togglePause()Alterna pausa y reanudación.
Game.isPaused()Indica si la pausa global está activa.

Cómo pausar y reanudar

export function update(object, deltaTime) {
    // update deja de ejecutarse después de pausar.
    if (Input.getKeyDown("Escape") || Input.getButtonDown("Start")) {
        Game.pause();
        UI.show("PauseMenu");
    }
}

export function pausedUpdate(object, unscaledDeltaTime) {
    // Solo se ejecuta durante la pausa global.
    if (Input.getKeyDown("Escape") || Input.getButtonDown("Start")) {
        UI.hide("PauseMenu");
        Game.resume();
    }
}

Para reanudar desde un script usa pausedUpdate(object, unscaledDeltaTime), porque update, fixedUpdate y lateUpdate permanecen detenidos. No uses Game.togglePause() solamente dentro de update: después de pausar ese callback ya no se ejecutará. unscaledDeltaTime permite animar manualmente una interfaz de pausa.

APIs de componentes adicionales

MovingPlatform.get(object)Obtiene el componente.
MovingPlatform.setEnabled(object, value)Activa o desactiva.
MovingPlatform.setSpeed(object, speed)Cambia velocidad.
MovingPlatform.setMovement(object, x, y)Cambia recorrido.
MovingPlatform.setPingPong(object, value)Controla ida y vuelta.
MovingPlatform.reset(object)Reinicia su estado.
Rotation.get(object)Obtiene Rotation.
Rotation.setEnabled(object, value)Activa o desactiva.
Rotation.setSpeed(object, speed)Cambia grados por segundo.
Rotation.setPivot(object, x, y)Cambia pivote.
Rotation.reset(object)Reinicia la rotacion acumulada.
Ladder.get(object), Ladder.setEnabled(object, value)Consulta o activa una escalera.
Light.get(object), Light.setEnabled(object, value)Consulta o activa una luz.
Light.setColor(object, color)Cambia color hexadecimal.
Light.setIntensity(object, value)Intensidad entre 0 y 1.
Light.setRadius(object, radius)Cambia radio.
Light.setEffect(object, effect, options)Efecto y opciones speed, amount y 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 });

Guardar partidas con Save

Save guarda objetos completos por slot y proyecto. Para opciones pequeñas sigue siendo adecuado PlayerPrefs; para partidas usa Save.

Save.write(slot, data, metadata)Guarda datos y metadatos opcionales.
Save.read(slot, fallback)Lee los datos.
Save.info(slot)Fecha y metadatos sin cargar la partida.
Save.exists(slot)Comprueba el slot.
Save.delete(slot)Borra un slot.
Save.list()Lista slots ordenados por fecha.
Save.clear()Borra todas las partidas del proyecto.
Save.write("slot1", {
    scene: Scene.current,
    score: Project.vars.score,
    lives: 3,
    player: { x: object.x, y: object.y }
}, {
    title: "Partida principal"
});

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

Los datos deben poder convertirse a JSON. No guardes funciones, elementos HTML, Audio ni referencias circulares.

Archivos TXT y JSON

GameCrom utiliza la misma API Files para trabajar con TXT y JSON, pero separa los archivos en dos zonas con finalidades y permisos diferentes. Elegir la zona correcta evita confundir el contenido original del proyecto con los datos que genera cada jugador.

ZonaFinalidadDurante el juegoEjemplos
assets/data/Contenido interno preparado por el desarrollador.Solo lecturaTraducciones, diálogos, configuración, niveles y tablas de datos.
user/Datos locales creados o modificados durante la ejecución.Lectura y escrituraPerfiles, contenido generado, registros y datos personalizados de la partida.

Caso 1: datos internos del proyecto — assets/data/

Abre la pestaña Data del panel de Recursos. Desde ella puedes importar archivos .txt y .json, o crear uno nuevo con New TXT y New JSON. Los archivos se guardan en assets/data/ y el botón Open in VS Code los abre directamente en Visual Studio Code. También puedes usar subcarpetas escribiéndolas en el nombre, por ejemplo dialogues/es.json.

assets/data/ es siempre de solo lectura durante el juego. Sus archivos forman parte del proyecto y se incluyen en la compilación, pero un script no puede modificarlos ni eliminarlos. Para cambiar su contenido debes volver al proyecto, editarlo con VS Code y generar una nueva build.

// Leer contenido preparado por el desarrollador
const traducciones = await Files.readJSON("assets/data/translations/es.json", {});
const dialogos = await Files.readText("assets/data/dialogos.txt", "");

// Esto está prohibido porque assets/data es de solo lectura:
// await Files.writeJSON("assets/data/config.json", nuevaConfig);

Caso 2: archivos modificables del jugador — user/

Usa user/ cuando el juego necesite crear, leer, modificar o eliminar TXT y JSON durante la ejecución. Estos archivos no forman parte del proyecto original y son independientes para cada juego, navegador o instalación.

// Crear o sobrescribir un archivo del jugador
await Files.writeJSON("user/perfil.json", {
    name: "Player",
    level: 3
}, { pretty: true });

// Leerlo, modificarlo y volverlo a guardar
const perfil = await Files.readJSON("user/perfil.json", { level: 1 });
perfil.level += 1;
await Files.writeJSON("user/perfil.json", perfil);

await Files.writeText("user/notas.txt", "Nivel completado");
const archivos = await Files.list("user/");
await Files.delete("user/notas.txt");

Dónde se guarda user/

  • Editor Play: en el almacenamiento local del editor.
  • Build Web: en el navegador y asociado al dominio desde el que se ejecuta el juego. No crea archivos visibles junto a la web.
  • Build Windows: en los datos locales de la aplicación, separado por juego. No se guarda junto al EXE ni dentro de assets/data/.
MétodoDescripción
await Files.readText(path, fallback?)Lee un archivo .txt.
await Files.readJSON(path, fallback?)Lee y convierte un archivo .json.
await Files.writeText(path, content)Escribe texto dentro de user/.
await Files.writeJSON(path, value, options?)Guarda JSON. Usa { pretty: true } para formatearlo.
await Files.exists(path)Comprueba si existe.
await Files.list(path)Lista los archivos de una carpeta.
await Files.delete(path)Elimina un archivo de user/.

Para controlar errores, usa try/catch y consulta error.code: NOT_FOUND, INVALID_JSON, ACCESS_DENIED o QUOTA_EXCEEDED.

Solo se admiten archivos .txt y .json, con un máximo de 5 MB por archivo. Las rutas absolutas y ../ están bloqueadas. Usa PlayerPrefs para preferencias sencillas, Save para partidas organizadas en slots y Files para archivos auxiliares personalizados.

Guardado local

Qué sistema debes utilizar

SistemaUso recomendadoPersistencia
PlayerPrefsVolumen, idioma, controles, calidad gráfica y otras preferencias.Almacenamiento local, separado por proyecto.
SavePartidas, niveles, inventario, puntuación, campaña y puntos de control.Almacenamiento local, organizado en slots y separado por proyecto.

GameCrom 2D Studio no utiliza cuentas ni guardado en la nube. Los datos no se sincronizan entre navegadores, equipos o dispositivos.

Dónde se guardan los datos

  • Editor Play: en el almacenamiento local del editor.
  • Build Web: en el almacenamiento local del navegador y del dominio desde el que se ejecuta el juego.
  • Build Windows: en el almacenamiento local de la aplicación.

En Web, cada navegador y cada dominio mantienen una copia independiente. Borrar los datos del sitio, usar navegación privada o abrir el juego desde otro dominio puede hacer que la partida no esté disponible. En Windows, eliminar los datos locales de la aplicación también elimina sus preferencias y partidas.

Uso recomendado

// Preferencias del dispositivo
PlayerPrefs.setNumber("volume", 0.8);
PlayerPrefs.setString("language", "es");

// Progreso de la partida
Save.write("autosave", {
    level: 4,
    score: 12500,
    player: { x: object.x, y: object.y }
});

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

Guarda en puntos de control y después de cambios importantes. No esperes únicamente al cierre de la pestaña o de la aplicación, porque un cierre forzado puede impedir la última escritura.

Pathfinding

Pathfinding.findPath usa A* sobre una cuadricula temporal. Los objetos con collider activo bloquean celdas; los triggers no bloquean. No requiere Tilemap.

Pathfinding.findPath(start, end, options)Devuelve puntos de mundo o un array vacio.
Pathfinding.follow(object, path, speed, options)Hace que el objeto siga la ruta.
Pathfinding.stop(object)Detiene el seguimiento.
Pathfinding.isFollowing(object)Comprueba si sigue una ruta.

Opciones principales: cellSize, diagonal, padding, marginCells, maxNodes e ignore. Un cellSize pequeño encuentra rutas mas precisas pero cuesta mas 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

El objeto Pixel Canvas es una imagen dinamica y escalable cuyo contenido procede de un framebuffer controlado por scripts. Sirve para emuladores, programas de dibujo, minimapas, pantallas, efectos procedurales y juegos basados directamente en pixeles.

Crea Add GameObject > Pixel Canvas y configura su resolucion interna. El tamano y la escala del objeto controlan el tamano visible; su resolucion controla cuantos pixeles contiene el framebuffer.

PixelCanvas.create(object, width, height, options)Crea o reemplaza la superficie.
PixelCanvas.get(object)Devuelve la superficie existente.
PixelCanvas.getOrCreate(object)Obtiene o crea usando la configuracion del objeto.
surface.getBuffer()Buffer RGBA Uint8ClampedArray; cuatro bytes por pixel.
surface.getIndexBuffer()Buffer Uint8Array de indices para paletas de hasta 256 colores.
surface.setPixel(x, y, color)Dibuja un pixel.
surface.clear(color)Limpia toda la superficie.
surface.fillRect(x, y, w, h, color)Rellena un rectangulo.
surface.drawLine(x0, y0, x1, y1, color)Dibuja una linea.
surface.setPalette(colors)Define la paleta del modo indexado.
surface.present()Publica los cambios del buffer para renderizarlos.
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();
}

Para maximo rendimiento modifica directamente el buffer y llama a markDirty() antes de present(). Con Auto Present activo, el renderer publica automaticamente cualquier superficie marcada como modificada.

Engine, tipos y contrato de API

Engine.versionVersion del motor.
Engine.apiVersionVersion del contrato de scripts.
Engine.isEditorTrue en Editor Play y false en compilados.
Engine.platformPlataforma comunicada por el sistema.
export function start(object) {
    debug({
        engine: Engine.version,
        api: Engine.apiVersion,
        editor: Engine.isEditor,
        platform: Engine.platform
    });
}

El archivo DOCUMENTOS/gamecrom-2d-studio-api.d.ts ofrece autocompletado y tipos para las APIs nuevas. La prueba node TESTS/runtimeApiContract.mjs valida matematicas, eventos, tiempo, Random, Save, Pathfinding y PixelCanvas.

API Application: salir del juego

Usa Application.quit() para abandonar el juego desde cualquier script. La misma llamada funciona durante Play en el editor, en una version web publicada en GameCrom y en un ejecutable de Windows. Application.exit() es un alias equivalente.

EntornoResultado
Play del editorDetiene Play y vuelve a la escena sin cerrar el editor.
Juego web en GameCromCierra el reproductor web y finaliza la sesion de partida.
Juego EXECierra limpiamente la ventana y el proceso nativo del juego.

Salir directamente

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

Puedes llamar a esta funcion desde la logica de un boton de menu, una pantalla de Game Over o cualquier otro script. La promesa devuelve true si la solicitud se ha enviado y false si otro codigo ha cancelado la salida.

Salir al pulsar Escape

export function start(object) {
    // No hace falta preparar nada al iniciar.
}

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

Guardar antes de salir

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");
}

Guarda primero y solicita la salida despues. No pongas operaciones largas despues de Application.quit(), porque el juego puede cerrarse inmediatamente.

Cancelar temporalmente la salida

let hayCambiosSinGuardar = true;

export async function intentarSalir() {
    if (hayCambiosSinGuardar) {
        window.addEventListener("gamecrom:before-quit", event => {
            event.preventDefault();
            debug("Guarda la partida antes de salir");
        }, { once: true });
    }

    const saliendo = await Application.quit("main-menu");
    debug({ saliendo }); // false si se ha cancelado
}

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

Antes de cerrar se emite el evento cancelable gamecrom:before-quit. Su propiedad event.detail.reason contiene el motivo enviado a quit. El listener debe decidir de forma sincrona si cancela la salida mediante event.preventDefault().

Metodos disponibles

MetodoUso
await Application.quit(reason?)Solicita una salida limpia y devuelve true o false.
await Application.exit(reason?)Alias de Application.quit().

20. Compilar y exportar el juego

Desde Project Settings puedes generar localmente diferentes versiones del juego. Antes de compilar, el editor guarda la escena actual y la configuracion del proyecto.

El campo Builds, situado encima de los botones de compilacion, permite elegir la carpeta de salida. Por defecto se usa C:\GAMECROM_BUILDS. Cuando termina correctamente una compilacion, Open Folder abre directamente la carpeta generada; el boton permanece oculto mientras no exista una ruta de salida valida.

BotonSalidaUso recomendado
Build Web<RAIZ_BUILDS>/<Proyecto>/webVersión web minificada y protegida para publicar.
Build Windows<RAIZ_BUILDS>/<Proyecto>/windowsEjecutable Windows protegido y portable.

Build Web

La version protegida no deja visibles las carpetas scripts, scenes, assets, prefabs ni ENGINE. El juego se empaqueta en pocos archivos y se reconstruye en memoria al arrancar.

El motor se agrupa en un único módulo y, junto con el código de arranque y los scripts del proyecto, se minifica. Los scripts del juego reciben además un renombrado moderado de identificadores, sin transformaciones agresivas de flujo, código basura ni decodificadores que se ejecuten en cada frame. El núcleo compartido de física y colisiones recibe únicamente minificación segura y renombrado de identificadores locales; no utiliza ofuscación de flujo ni operaciones adicionales en ejecución, para preservar su rendimiento. Los archivos originales del editor y del proyecto nunca se modifican; el proceso trabaja únicamente sobre las copias de la carpeta compilada.

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

En web no existe proteccion absoluta: el navegador siempre necesita descargar los datos del juego. Esta salida dificulta el análisis y la copia, pero no debe usarse para guardar secretos, claves privadas o logica sensible.

Build Windows

Genera el juego como una aplicación ejecutable sin instalador, por ejemplo PONG.exe.

Es ideal para ejecutar el juego directamente, distribuirlo en un archivo ZIP o publicarlo en plataformas que acepten aplicaciones de Windows.

Los recursos necesarios quedan empaquetados con la aplicación y no aparecen como carpetas sueltas junto al ejecutable.

¿Cuál debo utilizar?

Para publicar en navegador: Build Web

Para distribuir un ejecutable protegido: Build Windows

Para Steam y otras tiendas: consulta la guía de publicación correspondiente.

21. Consejos de uso

  • Usa deltaTime para que el movimiento no dependa de los FPS.
  • Comprueba siempre si FindByName o FindByTag devuelven null.
  • Usa tags para categorias como Enemy, Player, Pickup o Target.
  • Si un script se asigna a varios objetos, cada objeto recibira su propia llamada a start y update.
  • Los cambios hechos durante Play son temporales y se restauran al salir de Play.

Vídeo en juegos y Canvas UI

Importa archivos .mp4, .webm u .ogv desde la pestaña Videos. Para la compatibilidad más amplia en Web y Windows se recomienda MP4 codificado con H.264 y audio AAC.

UI Video

Usa Add GameObject > Canvas UI > UI Video para cinemáticas, tutoriales, fondos de menú o cualquier vídeo anclado a la pantalla. Puedes elegir ajuste Contain, Cover o Stretch, reproducción inicial, bucle, silencio y volumen.

Video Renderer

Añade el componente Video Renderer a un objeto normal para dibujar el vídeo dentro de sus límites y transformarlo como parte del mundo. Sus opciones de reproducción son las mismas.

El autoplay con sonido puede ser bloqueado por el navegador. Por eso los vídeos nuevos comienzan silenciados; activa el sonido después de una interacción del usuario. Los recursos de vídeo forman parte de la compilación y no dependen de una URL externa.