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.
- Selecciona un objeto en la escena o en la jerarquia.
- En el Inspector busca el componente Script o abre la pestana Scripts.
- Pulsa Create para crear uno nuevo o elige uno existente en File.
- Pulsa Edit para abrirlo en Visual Studio Code.
- 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.
- Selecciona el objeto que quieres convertir en prefab.
- Abre la pestana Prefabs en el panel inferior.
- Pulsa Create From Selection.
- Escribe el nombre del prefab y confirma.
- Usa Instantiate para crear una copia del prefab en la escena.
- 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 guarda | Detalle |
|---|---|
| Objeto raiz | Nombre, tag, posicion, escala, rotacion, color, textura, colision, visibilidad y Static. |
| Hijos | La jerarquia completa que cuelga del objeto seleccionado. |
| Script | La referencia al script asignado al objeto. |
| Animacion | La animacion asignada y sus opciones de reproduccion. |
| Particulas | El sistema de particulas asignado y sus opciones. |
| Componentes | Componentes 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.
| Propiedad | Uso |
|---|---|
Enabled | Activa o desactiva la luz. |
Light Color | Color de la luz. |
Radius | Alcance de la luz en pixeles de mundo. |
Intensity | Fuerza de la luz, de 0 a 1. |
Opacity | Transparencia global de la luz, de 0 a 1. |
Softness | Suavizado del borde, de 0 a 1. |
Effect | Animacion de luz: None, Torch, Candle, Alarm, Fluorescent o Pulse. |
Effect Speed | Velocidad del efecto. 0 deja la luz practicamente fija. |
Effect Amount | Cantidad de variacion de intensidad del efecto. |
Radius Amount | Cantidad de variacion del radio durante el efecto. |
Effect Color | Color 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.
- Abre la pestana Slice Sprite del panel inferior.
- Elige la textura fuente.
- Configura Cell W y Cell H con el tamano de cada sprite.
- Ajusta Offset X/Y si la hoja tiene margen exterior.
- Ajusta Spacing X/Y si hay separacion entre sprites.
- Usa Columns y Rows para limitar el area, o deja
0para calcularlo automaticamente. - 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.
| Funcion | Cuando se llama | Parametros |
|---|---|---|
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
| Tipo | Ejemplo | Uso |
|---|---|---|
| number | let vida = 100; | Numeros, velocidad, tiempo, puntuacion. |
| string | let estado = "idle"; | Texto, nombres, estados. |
| boolean | let vivo = true; | Valores verdadero/falso. |
| object | let datos = { vida: 100 }; | Agrupar datos. |
| array | let 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().
| Funcion | Uso | Ejemplo |
|---|---|---|
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 actual | Ejemplo |
|---|---|
| Minimo, maximo y valor absoluto | Math.min(a, b), Math.max(a, b), Math.abs(x) |
| Redondeo | Math.floor(x), Math.ceil(x), Math.round(x) |
| Potencias y raiz | Math.pow(x, 2), Math.sqrt(x) |
| Distancia 2D | Math.hypot(dx, dy) |
| Angulos y trigonometria | Math.atan2(y, x), Math.sin(x), Math.cos(x) |
| Signo | Math.sign(x) |
| Aleatorio entre 0 y 1 | Math.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
| Funcion | Uso | Ejemplo |
|---|---|---|
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.
| Metodo | Uso | Ejemplo |
|---|---|---|
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.
| Metodo | Uso | Ejemplo |
|---|---|---|
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.
| Propiedad | Tipo | Uso | Ejemplo |
|---|---|---|---|
id | string/number | Identificador unico del objeto. | debug(object.id) |
name | string | Nombre visible en el editor. | object.name = "Player" |
tag | string | Etiqueta para buscar objetos por categoria. | object.tag = "Enemy" |
parentId | string/null | ID del padre en la jerarquia. | debug(object.parentId) |
type | string | Tipo visual: square o circle. | debug(object.type) |
active | boolean | Activa o desactiva el objeto. | object.active = false |
isStatic | boolean | Marca el objeto como estatico para optimizaciones futuras. | object.isStatic = true |
visibleInPlay | boolean | Controla si se ve durante Play. | object.visibleInPlay = true |
x, y | number | Posicion local del objeto. | object.x += 10 |
w, h | number | Tamano base del objeto. | object.w = 80 |
rotation | number | Rotacion en grados. | object.rotation += 90 * deltaTime |
scaleX, scaleY | number | Escala horizontal y vertical. | object.scaleX = 2 |
z | number | Capa de orden visual. | object.z = 5 |
color | string | Color en formato hexadecimal. | object.color = "#ff0000" |
opacity | number | Opacidad entre 0 y 1. | object.opacity = 0.5 |
texture | string | Nombre de la textura asignada. | object.texture = "player.png" |
textureTilingX, textureTilingY | number | Repeticion de la textura. | object.textureTilingX = 2 |
textureOffsetX, textureOffsetY | number | Desplazamiento de la textura. | object.textureOffsetX += deltaTime |
textureFlipX, textureFlipY | boolean | Voltea la textura. | object.textureFlipX = true |
pixelPerfect | boolean | Render de textura con aspecto pixel art. | object.pixelPerfect = true |
animation | string | ID de animacion asignada. | debug(object.animation) |
animationPlaying | boolean | Activa o pausa la animacion. | object.animationPlaying = true |
animationRunInPlay | boolean | Indica si la animacion arranca en Play. | object.animationRunInPlay = true |
particleSystem | string | ID del sistema de particulas asignado. | debug(object.particleSystem) |
particlesPlaying | boolean | Activa o pausa particulas. | object.particlesPlaying = true |
particlesRunInPlay | boolean | Indica si las particulas arrancan en Play. | object.particlesRunInPlay = true |
particlesDetached | boolean | Permite que la estela de particulas quede separada del objeto. | object.particlesDetached = true |
collisionEnabled | boolean | Marca el collider como activo. | object.collisionEnabled = true |
isTrigger | boolean | Marca el collider como trigger. | object.isTrigger = true |
collider | object | Datos del collider: shape, offsetX/Y, width/height y radius. | object.collider.shape = "capsule" |
script | string | Nombre 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.
| Funcion | Uso | Ejemplo |
|---|---|---|
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.
| Funcion | Uso | Ejemplo |
|---|---|---|
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.
| Funcion | Uso | Ejemplo |
|---|---|---|
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
| Funcion | Devuelve | Ejemplo |
|---|---|---|
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
| Funcion | Uso | Ejemplo |
|---|---|---|
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.
| Funcion | Uso | Ejemplo |
|---|---|---|
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.
| Opcion | Tipo | Descripcion |
|---|---|---|
x | number | Posicion X del objeto raiz. |
y | number | Posicion Y del objeto raiz. |
offsetX | number | Desplazamiento X si no indicas x e y. |
offsetY | number | Desplazamiento Y si no indicas x e y. |
name | string | Nombre base para la copia creada. |
parent | object | Objeto que sera el padre del prefab instanciado. |
rotation | number | Rotacion inicial del objeto raiz. |
scaleX | number | Escala X inicial del objeto raiz. |
scaleY | number | Escala 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.
| Funcion | Uso | Ejemplo |
|---|---|---|
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.current | Nombre 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.
| Pista | Propiedad animada |
|---|---|
Position X / Y | Posicion local x e y. |
Rotation | Rotacion del objeto en grados. |
Scale X / Y | Escala independiente de cada eje. |
Opacity | Opacidad interpolada del objeto. |
Color | Color 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.
| Funcion | Uso | Ejemplo |
|---|---|---|
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.
| Funcion | Uso | Ejemplo |
|---|---|---|
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.
| Propiedad | Uso |
|---|---|
Follow Player | Activa el seguimiento de camara durante Play. |
Tag | Tag del objeto que seguira la camara. La lista sale de los tags de la escena. |
Dead Zone X/Y | Zona muerta antes de mover la camara. Sirve para que el personaje pueda moverse un poco sin arrastrar la camara. |
Smooth | Respuesta del seguimiento entre 0 y 1. 0 no mueve la camara, 1 sigue inmediatamente. |
Lock X/Y | Bloquea el seguimiento en un eje. |
Offset X/Y | Desplaza el punto de seguimiento respecto al centro del objeto. |
Bounds | Limita la camara dentro de un rectangulo de mundo con min/max X/Y. |
Effect | Filtro visual aplicado solo durante Play: None, Scanlines, CRT, Noir, Sepia o Dream. |
FX | Intensidad del efecto entre 0 y 1. |
Scanline Size | Separacion de las lineas cuando usas Scanlines o CRT. |
Vignette | Oscurece suavemente los bordes de la camara. |
Noise | Anade 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.
| Funcion | Uso | Ejemplo |
|---|---|---|
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.
| Control | Uso |
|---|---|
UI Panel | Fondo o contenedor visual. Los hijos UI se colocan relativos al panel en Play. |
UI Text | Texto para puntuacion, mensajes, nombres o etiquetas. |
UI Image | Imagen desde Textures o bloque de color si no tiene imagen asignada. No usa texto ni fuente. |
UI Button | Boton 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 Input | Campo editable durante Play. En móvil abre automáticamente el teclado virtual del sistema. |
UI Checkbox | Valor verdadero/falso interactivo. Tiene color Hover al pasar el puntero por encima. |
UI Select | Lista 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 Bar | Barra no interactiva para vida, energia, carga o experiencia. Usa Value, Min, Max y color Fill. |
UI Slider | Control 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
| Funcion | Uso | Ejemplo |
|---|---|---|
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.
| Propiedad | Uso |
|---|---|
Sound | Archivo de sonido importado en la pestana Sounds. |
Volume | Volumen entre 0 y 1. |
Pitch | Tono 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. |
Loop | Repite el sonido automaticamente. |
Play On Start | Reproduce el sonido al entrar en Play. |
Enabled | Activa o desactiva el componente. |
API de AudioSource
| Funcion | Uso | Ejemplo |
|---|---|---|
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.
| Efecto | Parametros | Uso habitual |
|---|---|---|
Reverb | Mix, Duration y Decay | Habitaciones, cuevas, salas y espacios grandes. |
Delay / Echo | Mix, Delay Time y Feedback | Ecos y repeticiones. Feedback alto produce mas repeticiones. |
Filter | Low/High/Band Pass, Frequency, Resonance y Mix | Sonido bajo el agua, detras de paredes, radios o telefonos. |
Distortion | Amount y Mix | Motores, armas, impactos y sonido saturado. |
Stereo Pan | Pan de -1 a 1 y Mix | Coloca el sonido a la izquierda o derecha. |
Pitch | Pitch de 0.1 a 4 | Cambia velocidad y tono; 1 conserva el sonido original. |
API de Audio Effect
| Funcion | Uso |
|---|---|
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.
| Funcion | Uso | Ejemplo |
|---|---|---|
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.
| Propiedad | Uso |
|---|---|
Enabled | Activa o desactiva el componente. |
Start On Play | Si esta activo, la bola empieza a moverse al entrar en Play. |
Speed | Velocidad de la bola en pixeles por segundo. |
Angle | Direccion inicial de salida en grados. 0 derecha, 90 abajo, -90 arriba y 180 izquierda. |
Constant Speed | Mantiene la misma velocidad despues de cada rebote. |
API de Bouncy Ball
| Funcion | Uso | Ejemplo |
|---|---|---|
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.
| Propiedad | Uso |
|---|---|
Speed | Velocidad en pixeles por segundo. |
Loop | Al llegar al final vuelve a empezar. |
Ping Pong | Recorre la ruta hacia delante y luego hacia atras. |
Random | Elige el siguiente waypoint al azar, evitando repetir el punto actual cuando hay mas de uno. |
Move Points With Object | Al 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 Target | Rota el objeto mirando al waypoint al que se mueve. |
Flip X | Invierte la textura en X cuando el objeto se mueve hacia la izquierda y la restaura al moverse hacia la derecha. |
Flip Y | Invierte la textura en Y cuando el objeto se mueve hacia arriba y la restaura al moverse hacia abajo. |
Pause Min/Max | Pausa aleatoria general entre puntos. |
Waypoint P Min/P Max | Pausa aleatoria especifica para ese punto. |
Rotation Offset | Ajuste en grados si el sprite no mira hacia la derecha por defecto. |
Arrive Distance | Distancia 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
| Funcion | Uso | Ejemplo |
|---|---|---|
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.
| Propiedad | Uso |
|---|---|
Target Mode | Busca el destino por tag, por nombre o usa unas coordenadas fijas. |
Target Tag / Name | Tag o nombre del objeto que el agente debe perseguir. |
Destination X/Y | Destino fijo cuando el modo seleccionado es Position. |
Speed | Velocidad de movimiento en pixeles por segundo. |
Cell Size | Tamano de cada celda de busqueda. Un valor pequeno da rutas mas precisas, pero necesita mas calculo. |
Padding | Margen adicional alrededor de los obstaculos para evitar rozarlos. |
Arrive Distance | Distancia a la que el destino se considera alcanzado. |
Repath Interval | Segundos entre recalculos mientras el objetivo se mueve. Bajarlo mejora la reaccion y aumenta el trabajo de CPU. |
Max Nodes | Limite de celdas que puede explorar una busqueda. |
Diagonal | Permite rutas y movimiento diagonal. |
Rotate To Target | Orienta el objeto en la direccion de movimiento. |
Flip X/Y | Invierte automaticamente el sprite segun la direccion. |
Rotation Offset | Corrige la orientacion si el sprite no mira hacia la derecha por defecto. |
API de Pathfinding Agent
| Funcion | Uso |
|---|---|
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.
| Propiedad | Uso |
|---|---|
Target Mode | Localiza el objetivo por tag o por nombre. |
Target Tag / Name | Tag o nombre del objeto al que debe mirar. |
Turn Speed | Velocidad maxima de giro en grados por segundo. Con 0 gira instantaneamente. |
Reaction Delay | Tiempo en segundos entre actualizaciones de la direccion objetivo. Con 0 sigue al target en cada frame. |
Original Direction | Direccion hacia la que apunta el dibujo sin ninguna rotacion: derecha, abajo, izquierda, arriba o personalizada. |
Original Angle | Angulo 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
| Funcion | Uso |
|---|---|
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.
| Propiedad | Uso |
|---|---|
Body Type | Dynamic recibe gravedad y colisiones. Kinematic se mueve por velocidad/script, pero no recibe gravedad. |
Use Gravity | Activa o desactiva la gravedad del componente. |
Gravity Scale | Multiplica la gravedad del motor. 1 es normal, 0.5 cae mas lento y 2 cae mas rapido. |
Mass | Masa usada por Physics.addForce y por los empujes. Mas masa significa que la misma fuerza o empuje cambia menos la velocidad. |
Velocity X/Y | Velocidad actual en pixeles por segundo. |
Drag | Freno gradual aplicado a la velocidad. |
Max Fall Speed | Limite de velocidad al caer. |
Freeze X/Y | Bloquea el movimiento fisico en un eje. |
Bounce | Rebote al chocar. 0 no rebota; valores mayores devuelven parte de la velocidad. |
Friction | Reduce velocidad horizontal al tocar suelo. |
API de Physics
| Funcion | Uso | Ejemplo |
|---|---|---|
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.
| Propiedad | Uso |
|---|---|
Target | Objeto que controla el desplazamiento de la textura. |
Target | Objeto opcional que controla el parallax. Si esta vacio se usa la camara de Play. |
Speed X/Y | Multiplicador de desplazamiento por eje. 1 es una velocidad normal; puede ser negativo. |
Smooth X/Y | Suavizado por eje. 0 es inmediato; valores altos suavizan mas. |
Margin X/Y | Zona muerta por eje antes de mover la textura, util para camaras tipo Mario. |
Repeat X/Y | Repite la textura horizontal o verticalmente. |
Lock X/Y | Bloquea el movimiento de la textura en ese eje. |
Enabled | Activa o desactiva el componente. |
API de Parallax
| Funcion | Uso | Ejemplo |
|---|---|---|
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
| Parametro | Tipo | Explicacion |
|---|---|---|
Mode | Selector | Elige el tipo de controlador: Platformer para plataformas con gravedad o Top Down para movimiento libre en vista superior. |
Analog Movement | Selector | Progressive 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 Zone | Numero 0-0.95 | Ignora pequeñas desviaciones del stick para evitar movimiento involuntario. El valor predeterminado es 0.12; normalmente se recomienda entre 0.10 y 0.20. |
Enabled | Check | Activa o desactiva el componente sin quitarlo del objeto. |
Use Collisions | Check | Usa 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 Animations | Check | Cambia automaticamente la animacion del objeto cuando cambia el estado del controlador. |
Flip X Direction | Check | Voltea la textura en X al cambiar la direccion horizontal. Es lo habitual para personajes que miran izquierda/derecha. |
Flip Y Direction | Check | Voltea la textura en Y al cambiar la direccion vertical. Solo suele usarse en juegos top-down o casos especiales. |
Horizontal | Check | Permite o bloquea el movimiento en el eje X. |
Vertical | Check | Permite 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 Speed | Numero | Velocidad base del personaje en pixeles por segundo. |
Death State | Check | Permite 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.
| Parametro | Tipo | Explicacion |
|---|---|---|
Run | Check | Activa una velocidad de carrera opcional mientras se mantiene pulsada la tecla configurada. |
Run Speed | Numero | Velocidad usada al correr. Debe ser mayor que Move Speed si quieres que se note la carrera. |
Run Key | Texto | Tecla para correr. Por defecto suele usarse Shift. |
Run Button | Selector | Boton del mando que se mantiene pulsado para correr. El valor predeterminado para Xbox es X. |
Jump | Check | Permite saltar. Si esta desactivado, el personaje no responde a la tecla de salto. |
Jump Key | Texto | Tecla de salto. Por defecto suele usarse Space. |
Jump Button | Selector | Boton del mando para saltar. El valor predeterminado para Xbox es A. |
Jump Force | Numero | Fuerza inicial del salto. Valores mas altos hacen que el personaje suba mas rapido y mas alto. |
Gravity | Numero | Fuerza que empuja al personaje hacia abajo. Valores altos producen caidas mas rapidas. |
Max Fall | Numero | Velocidad maxima de caida. Evita que el personaje acelere indefinidamente. |
Double Jump | Check | Permite saltar de nuevo en el aire. |
Max Jumps | Numero | Total de saltos permitidos antes de volver a tocar suelo. Para doble salto normalmente es 2. |
Crouch | Check | Activa estado de agacharse. |
Crouch Key | Texto | Tecla para agacharse. Por defecto suele usarse S. |
Crouch Button | Selector | Boton del mando que se mantiene pulsado para agacharse. El valor predeterminado para Xbox es B. |
Crouch Speed | Numero 0-1 | Multiplicador de velocidad al agacharse. 0.5 significa moverse a la mitad de velocidad. |
Use Ladders | Check | Permite usar objetos con componente Ladder. Al tocar una escalera el personaje pierde la gravedad y puede subir o bajar con el input. |
Ladder Speed | Numero | Velocidad 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.
| Parametro | Tipo | Explicacion |
|---|---|---|
Move Speed | Numero | Velocidad base para moverse en cualquier direccion. |
Run | Check | Activa carrera opcional tambien en top-down. |
Run Speed | Numero | Velocidad usada mientras la tecla de carrera esta pulsada. |
Run Key | Texto | Tecla para correr. |
Run Button | Selector | Boton del mando para correr. Por defecto, X. |
Crouch | Check | Activa un estado lento o de sigilo si tu juego lo necesita. |
Crouch Key | Texto | Tecla para activar el estado de agachado/sigilo. |
Crouch Button | Selector | Boton del mando para activar el estado de agachado o sigilo. Por defecto, B. |
Crouch Speed | Numero 0-1 | Multiplicador de velocidad durante el estado crouch. |
Horizontal | Check | Permite moverse izquierda/derecha. |
Vertical | Check | Permite moverse arriba/abajo. |
Flip X Direction | Check | Util para personajes que miran izquierda/derecha segun la direccion horizontal. |
Flip Y Direction | Check | Util para sprites que deban invertirse al mirar arriba/abajo. |
Animaciones y sonidos por estado
| Modo | Estados disponibles | Uso |
|---|---|---|
Platformer | Idle, Move, Run, Jump, Fall, Crouch, Death, Ladder Idle, Ladder Walk | Permite asignar animacion y sonido a cada estado de plataformas, incluyendo escalera. |
Top Down | Idle, Move, Run, Crouch, Death | Solo muestra los estados que tienen sentido sin salto, gravedad ni escaleras. |
| Parametro | Explicacion |
|---|---|
* Anim | Animacion asignada a un estado. Por ejemplo, Run Anim se reproduce al correr. |
* Sound | Sonido que se reproduce al entrar en ese estado. Los sonidos no heredan de otros estados para evitar dobles disparos. |
Vol | Volumen independiente del sonido de ese estado, entre 0 y 1. |
Loop | Hace 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
| Funcion | Uso | Ejemplo |
|---|---|---|
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
| Funcion | Uso | Ejemplo |
|---|---|---|
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 funcion | Uso |
|---|---|
Input.mouseX, Input.mouseY | Posicion del raton en pantalla/canvas. |
Input.mouseWorldX, Input.mouseWorldY | Posicion del raton en coordenadas de mundo. |
Input.mouseDeltaX, Input.mouseDeltaY | Movimiento del raton durante el frame. |
Input.mouseWheel | Movimiento 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.
| Funcion | Uso | Ejemplo |
|---|---|---|
Input.gamepadCount | Mandos 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
| Funcion | Uso |
|---|---|
Input.touchCount | Numero 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
- Crea o selecciona un UI Canvas.
- Abre Add GameObject > Mobile Controls.
- Anade Touch Joystick, Touch D-Pad o Touch Button.
- Coloca el joystick o la cruceta en la parte inferior izquierda y los botones en la derecha.
- Configura sus ejes o su accion desde el Inspector.
- Opcionalmente, asigna una imagen de Textures a cada control.
- Pruebalo en Play con el raton o genera un build nuevo para probar multitouch en el dispositivo.
| Control | Funcion | Configuracion habitual |
|---|---|---|
Touch Joystick | Movimiento analogico en cualquier direccion. Devuelve valores entre -1 y 1. | Horizontal y Vertical. |
Touch D-Pad | Cruceta digital. Cada direccion devuelve -1, 0 o 1. | Horizontal y Vertical. |
Touch Button | Boton mantenido, recien pulsado o recien soltado. | Acciones como Jump, Run, Crouch, Attack o Pause. |
Propiedades del Inspector
| Propiedad | Uso |
|---|---|
Horizontal Axis | Nombre del eje horizontal que recibe el joystick o la cruceta. Normalmente Horizontal. |
Vertical Axis | Nombre del eje vertical. Normalmente Vertical; positivo significa arriba. |
Action | Nombre de la accion enviada por un Touch Button. Distingue mayusculas y minusculas. |
Image | Imagen normal del Touch Button, imagen completa del D-Pad o imagen de base del joystick. |
Pressed Image | Imagen que muestra un Touch Button mientras permanece pulsado. Si se deja en None, conserva la imagen normal. |
Inner Image | Imagen del circulo interior movil del Touch Joystick. Se recorta automaticamente con forma circular. |
Inner Opacity | Opacidad independiente del circulo interior del joystick, entre 0 y 1. |
Visual Style | Aspecto 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 Mode | Fixed mantiene el joystick en su posicion. Floating in Area lo oculta hasta tocar la zona y lo centra bajo el dedo. |
Activation Area | Zona que puede iniciar un joystick flotante: Left Half, Right Half, Full Screen o Custom Area. |
Always Visible | Si 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 Zone | Ignora movimientos pequenos cerca del centro del joystick. El valor recomendado inicial es 0.12. |
Sensitivity | Multiplica la respuesta del joystick antes de limitarla al intervalo de -1 a 1. |
Touch devices only | Oculta el control en equipos sin pantalla tactil. Desactivalo mientras quieras probarlo con raton en Play. |
Background, Border, Opacity | Personalizan el aspecto visual. Una opacidad moderada evita tapar el juego. |
Anchor, posicion y tamano | Mantienen 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.
}
}
| Funcion | Resultado |
|---|---|
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.
| Opcion | Que hace |
|---|---|
Collision | Incluye el objeto en el sistema de colisiones durante Play. |
Trigger | Detecta contacto sin resolver fisicamente la colision. |
One Way Platform | Permite atravesar la plataforma saltando desde abajo y caer encima desde arriba. |
Shape | Forma del collider. Los objetos Square usan Box por defecto; los objetos Circle usan Circle y tambien pueden usar Capsule. |
Offset | Desplaza el collider respecto al centro del objeto sin mover el render. |
Size | Ancho y alto del collider para Box y Capsule. |
Radius | Radio del collider cuando la forma es Circle. |
Static | El 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
| Componente | Uso |
|---|---|
Ladder | Convierte 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 Platform | Mueve 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 Belt | Convierte un collider solido en una cinta transportadora que desplaza hacia la izquierda o derecha los personajes y cuerpos fisicos apoyados encima. |
Texture Scroller | Anima 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.
| Propiedad | Uso |
|---|---|
Enabled | Activa o desactiva el movimiento de la cinta. |
Direction | Elige si la cinta arrastra hacia Left o Right. |
Speed | Velocidad horizontal en pixeles por segundo. |
Affect Characters | Arrastra objetos que tengan un componente Character Controller activo. |
Affect Physics Bodies | Arrastra 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
| Funcion | Uso | Ejemplo |
|---|---|---|
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.
| Propiedad | Uso |
|---|---|
Enabled | Activa o desactiva la animacion del offset. |
Speed X | Velocidad horizontal positiva del offset por segundo. |
Speed Y | Velocidad vertical positiva del offset por segundo. |
Scroll Right | Marcado desplaza la textura hacia la derecha; desmarcado la desplaza hacia la izquierda. |
Scroll Down | Marcado desplaza la textura hacia abajo; desmarcado la desplaza hacia arriba. |
API de Texture Scroller
| Funcion | Uso | Ejemplo |
|---|---|---|
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.
| Funcion | Cuando 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
| Propiedad | Contenido |
|---|---|
collision.other | El otro objeto del contacto. |
collision.self | El objeto que recibe el callback. |
collision.normal | Direccion de separacion desde el punto de vista de self. |
collision.overlap | Profundidad de solapamiento. |
collision.point | Punto aproximado del contacto. |
collision.isTrigger | true si el contacto incluye un trigger. |
API Collision
| Funcion | Uso | Ejemplo |
|---|---|---|
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.deltaTime | Delta escalado del frame. |
Time.unscaledDeltaTime | Delta real, incluso con pausa o camara lenta. |
Time.fixedDeltaTime | Paso fijo del motor. |
Time.time, Time.unscaledTime | Tiempo acumulado escalado y real. |
Time.frameCount | Frames procesados. |
Time.timeScale | Escala 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.
| Zona | Finalidad | Durante el juego | Ejemplos |
|---|---|---|---|
assets/data/ | Contenido interno preparado por el desarrollador. | Solo lectura | Traducciones, diálogos, configuración, niveles y tablas de datos. |
user/ | Datos locales creados o modificados durante la ejecución. | Lectura y escritura | Perfiles, 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étodo | Descripció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
| Sistema | Uso recomendado | Persistencia |
|---|---|---|
PlayerPrefs | Volumen, idioma, controles, calidad gráfica y otras preferencias. | Almacenamiento local, separado por proyecto. |
Save | Partidas, 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.version | Version del motor. |
Engine.apiVersion | Version del contrato de scripts. |
Engine.isEditor | True en Editor Play y false en compilados. |
Engine.platform | Plataforma 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.
| Entorno | Resultado |
|---|---|
| Play del editor | Detiene Play y vuelve a la escena sin cerrar el editor. |
| Juego web en GameCrom | Cierra el reproductor web y finaliza la sesion de partida. |
| Juego EXE | Cierra 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
| Metodo | Uso |
|---|---|
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.
| Boton | Salida | Uso recomendado |
|---|---|---|
| Build Web | <RAIZ_BUILDS>/<Proyecto>/web | Versión web minificada y protegida para publicar. |
| Build Windows | <RAIZ_BUILDS>/<Proyecto>/windows | Ejecutable 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
deltaTimepara que el movimiento no dependa de los FPS. - Comprueba siempre si
FindByNameoFindByTagdevuelvennull. - Usa tags para categorias como
Enemy,Player,PickupoTarget. - Si un script se asigna a varios objetos, cada objeto recibira su propia llamada a
startyupdate. - Los cambios hechos durante Play son temporales y se restauran al salir de Play.