Sistema de logros
Cuando el jugador alcanza un hito (más de 100 de oro, más de 5 combates ganados, encontrar una zona oculta), aparece una tarjeta con el nombre del logro y una frase. Cada logro se desbloquea una sola vez, se guarda en una lista, y una página de la interfaz del jugador muestra cuáles ha encontrado y cuáles siguen bloqueados. Todo se puede montar sin código.
Lo que vas a construir
- Una tarjeta que aparece en cuanto se alcanza un hito: con un título, una frase y, si quieres, una imagen
- Detección automática: los comportamientos vigilan los números y la conversación, así que el jugador no tiene que hacer nada
- Cada logro se desbloquea una vez: un momento que ya está en su lista no vuelve a salir
- Una página de logros: aparecen todos; los desbloqueados muestran su texto y los bloqueados, una pista
- Opcional: logros que siguen desbloqueados aunque se empiece una partida nueva
Cómo funciona
El oro del jugador pasa de 95 a 101
→ El comportamiento "Big Spender" vigila Oro (Una variable cruza un umbral, Sube por encima de 100)
→ Su efecto "Desbloquear un momento" muestra la tarjeta "Big Spender"
→ El título "Big Spender" se añade a la variable de lista Achievements
→ La página de logros muestra Big Spender como desbloqueadoLa IA mueve los números según avanza la historia, pero quien decide si un logro se desbloquea es el motor, así que un logro no puede olvidarse ni darse dos veces.
Paso a paso
Paso 1: Crea las variables
En la fila Puedes añadir, abajo en la carta, pulsa + Variable para cada una de estas.
Oro
| Campo | Valor |
|---|---|
| Nombre | Oro |
| Tipo | Número |
| Valor inicial | 0 |
| Rango | de 0 a (déjalo vacío) |
| Reglas de comportamiento | El oro del jugador. Sube cuando le pagan, saquea algo o vende algo; baja cuando gasta. |
Combates ganados
| Campo | Valor |
|---|---|
| Nombre | Combates ganados |
| Tipo | Número |
| Valor inicial | 0 |
| Reglas de comportamiento | Cuántos combates ha ganado el jugador. Suma 1 cada vez que el jugador gane claramente una pelea. |
Achievements
| Campo | Valor |
|---|---|
| Nombre | Achievements |
| Tipo | Lista / tabla |
| Valor inicial | [] |
Abre Qué hace la IA con ella y pon Acceso de la IA en Solo motor (oculta para la IA). En esta lista solo escriben los comportamientos, y a la IA no le sirve de nada leerla.
Logros que sobreviven a una partida nueva
En esa misma sección, marca Se conserva entre partidas (para cada jugador). Así, cuando un jugador vuelve a empezar, la lista arranca con lo que ya había desbloqueado y esos logros no vuelven a salir. Así funcionan las galerías de ilustraciones y las colecciones de finales.
Paso 2: Crea un comportamiento por logro
En la fila Puedes añadir, pulsa + Comportamiento.
Comportamiento 1: Big Spender
| Parte | Ajuste |
|---|---|
| Cuándo se dispara | Una variable cruza un umbral: Oro, Sube por encima de, 100 |
| Efectos | Desbloquear un momento |
Rellena el momento:
| Campo | Valor |
|---|---|
| Título | Big Spender |
| Mensaje | Has ahorrado más de 100 de oro. |
| Imagen (enlace) | opcional: un enlace https:// o un recurso de Paneles → Recursos |
| Se guarda en (una lista) | Achievements |
«Una variable cruza un umbral» se dispara solo en el momento en que el número pasa de 100 o menos a más de 100. Si el oro sigue subiendo de 101 a 150, no se dispara nada. Si el oro baja de 100 y vuelve a subir, se dispararía otra vez, pero el momento ya está en Achievements y no sale nada.
Comportamiento 2: Seasoned Fighter
| Parte | Ajuste |
|---|---|
| Cuándo se dispara | Una variable cruza un umbral: Combates ganados, Sube por encima de, 5 |
| Efectos | Desbloquear un momento: Título Seasoned Fighter, Mensaje Has ganado más de 5 combates., Se guarda en Achievements |
Comportamiento 3: Trailblazer (palabra clave)
Este vigila la conversación en lugar de un número. Un comportamiento tiene un solo disparador, así que para pillar tanto lo que dice el jugador como lo que dice la IA, haz dos comportamientos.
3a
| Parte | Ajuste |
|---|---|
| Cuándo se dispara | El jugador dice una palabra clave: explorar, registrar la cueva |
| Efectos | Desbloquear un momento: Título Trailblazer, Mensaje Fuiste a buscar lo que estaba escondido., Se guarda en Achievements |
3b
| Parte | Ajuste |
|---|---|
| Cuándo se dispara | La IA dice una palabra clave: pasadizo oculto, sala secreta |
| Efectos | el mismo Desbloquear un momento que en 3a, con el mismo título |
Las palabras clave se separan con comas, y basta con una cualquiera. Los dos comportamientos guardan en la misma lista con el mismo título, así que el que se dispare primero desbloquea el logro, y el otro se lo encuentra ya ahí y no hace nada. No te hacen falta condiciones de más para esto.
¿Momentos o una notificación?
Mostrar notificación (con el estilo Éxito) también sirve para un aviso de una línea tipo «Logro desbloqueado», pero no recuerda nada: necesitarías un Interruptor por logro, una condición para que no se dispare dos veces y Máx. activaciones en 1. Desbloquear un momento ya se encarga de recordar.
Paso 3: Monta la página de logros
Pulsa Interfaz en el centro de la barra superior. Añade una página con Nueva página (una Página en blanco sirve), ponle un título y añade una parte Lista desde Añadir una parte:
- En Las filas vienen de, elige Filas que escribo y añade una fila por logro:
Big Spender,Seasoned Fighter,Trailblazer, cada una con una frase - Activa Dibujar cada fila como tarjeta
- En Bloqueada hasta, activa Mostrar las filas bloqueadas. Pon Vigilar esta variable en Achievements y deja Comparar con este campo de la fila en
title. Una fila se desbloquea cuando la lista contiene su título, que es justo lo que mete ahí Desbloquear un momento - En Texto mientras está bloqueada, escribe la pista que ve el jugador antes de desbloquearla, como «Ahorra un poco»
- Añade un Botón con Ir a la página de vuelta a la conversación, para que la página no sea un callejón sin salida (si no, la columna de páginas avisa con Sin salida)
- En la página de la conversación, añade un Botón con el texto «Logros» cuyo paso sea Ir a la página → tu página nueva
Si los coleccionables los reparte la IA en la historia y no los comportamientos, parte mejor de la plantilla Colección: «Lo que hay que encontrar empieza en gris y se ilumina cuando la historia te lo da.» Trae su propia variable de lista, una ventana emergente y unas Reglas de comportamiento que le dicen a la IA cuándo añadir cosas.
Desactiva Editar arriba para recorrer la página como lo haría un jugador.
Cuéntalos
Añade una variable de Número llamada «Logros desbloqueados» y dale la Fórmula (se calcula sola) len(Achievements). Pon {Logros desbloqueados} / 3 en una parte de Texto de la página y la cuenta se mantiene al día sola.
Paso 4: Pruébalo
Pulsa Jugar en la barra superior.
- Pulsa Logros: los tres están bloqueados y muestran su pista
- Juega hasta que tu oro pase de 100. Sale la tarjeta «Big Spender» y la página lo muestra desbloqueado
- Gana seis combates. «Seasoned Fighter» sale cuando Combates ganados pasa de 5 a 6
- Envía «Quiero explorar esta cueva». Sale «Trailblazer». Más tarde la IA menciona un pasadizo oculto y no vuelve a salir nada
Este turno, a la derecha de la prueba, te dice qué comportamientos se dispararon y por qué alguno no lo hizo.
Si algo falla:
| Síntoma | Causa probable | Solución |
|---|---|---|
| El oro pasa de 100 pero no ha salido nada | El oro nunca cruzó la línea: empezó por encima de 100 | El umbral solo se dispara al cruzarlo. Comprueba que el Valor inicial esté en el umbral o por debajo |
| Salió el momento pero la página no cambió | Se guarda en (una lista) está vacío, o la página vigila otra variable | Elige Achievements en los dos sitios |
| La página lo muestra bloqueado aunque salió | El título de la fila no coincide exactamente con el del momento | Déjalos idénticos, mayúsculas incluidas |
| Un logro salió dos veces | Los dos comportamientos usan títulos distintos o listas distintas | Mismo título, misma lista |
Ruta con código propio: un panel de logros debajo del chat
Si prefieres dibujar el panel tú, por ejemplo debajo del último mensaje en lugar de en una página aparte, escríbelo en el código de la interfaz. Los comportamientos de arriba se quedan tal cual; el código solo lee la lista Achievements.
Paneles → Código de frontend → abre index.tsx y sustituye el return <Chat /> que viene por defecto:
export default function MyWorld() {
const api = useYumina();
const msgs = api.messages || [];
// Titles must match the moment titles in your behaviors
const achievements = [
{ title: "Big Spender", desc: "Save more than 100 gold", icon: "💰" },
{ title: "Seasoned Fighter", desc: "Win more than 5 battles", icon: "⚔️" },
{ title: "Trailblazer", desc: "Find a hidden area or secret", icon: "🗺️" },
];
// The list the moments are collected into, read by its name
const unlockedList = Array.isArray(api.variables["Achievements"])
? api.variables["Achievements"].map(String)
: [];
const isUnlocked = (a) => unlockedList.includes(a.title);
const unlockedCount = achievements.filter(isUnlocked).length;
return (
<Chat renderBubble={(msg) => {
const isLastMsg = msg.messageIndex === msgs.length - 1;
return (
<div>
<div
style={{ color: "#e2e8f0", lineHeight: 1.7 }}
dangerouslySetInnerHTML={{ __html: msg.contentHtml }}
/>
{isLastMsg && (
<div style={{
marginTop: "16px",
padding: "12px 16px",
background: "linear-gradient(135deg, #1c1917, #292524)",
border: "1px solid #44403c",
borderRadius: "10px",
}}>
<div style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginBottom: "10px",
}}>
<span style={{ fontSize: "13px", fontWeight: "bold", color: "#fbbf24" }}>
🏆 Achievements
</span>
<span style={{ fontSize: "12px", color: "#a8a29e" }}>
{unlockedCount} / {achievements.length}
</span>
</div>
<div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
{achievements.map((a) => {
const unlocked = isUnlocked(a);
return (
<div
key={a.title}
style={{
display: "flex",
alignItems: "center",
gap: "10px",
padding: "6px 8px",
borderRadius: "6px",
background: unlocked
? "rgba(251, 191, 36, 0.08)"
: "rgba(120, 113, 108, 0.08)",
}}
>
<span style={{ fontSize: "18px", opacity: unlocked ? 1 : 0.3 }}>
{unlocked ? a.icon : "🔒"}
</span>
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{
fontSize: "13px",
fontWeight: "600",
color: unlocked ? "#fbbf24" : "#78716c",
}}>
{a.title}
</div>
<div style={{
fontSize: "11px",
color: unlocked ? "#a8a29e" : "#57534e",
marginTop: "1px",
}}>
{a.desc}
</div>
</div>
{unlocked && (
<span style={{ fontSize: "11px", color: "#fbbf24" }}>✓ Unlocked</span>
)}
</div>
);
})}
</div>
</div>
)}
</div>
);
}} />
);
}Qué hace el código:
<Chat renderBubble={...} />conserva la lista de mensajes, el cuadro de texto y el desplazamiento de la plataforma; tú solo dibujas cada burbujamsg.messageIndex === msgs.length - 1pone el panel solo debajo del último mensajemsg.contentHtmles el mensaje ya convertido en HTMLapi.variables["Achievements"]lee la lista por el nombre de la variable. Los nombres con espacios o mayúsculas funcionan con los corchetes- Un logro cuenta como desbloqueado cuando su título está en la lista, la misma regla que usa el momento
El estado que aparece junto al archivo en Paneles → Código de frontend debería ser un OK verde. Si pone Error, el mensaje de debajo te dice en qué línea.
¿No quieres escribir el código tú?
Pulsa Asistente IA arriba a la derecha del lienzo y describe el panel que quieres. Te escribe el código de la interfaz.
«Una variable cruza un umbral» o «Una variable cambia»
Los dos disparadores vigilan variables, pero se disparan en momentos distintos.
Una variable cruza un umbral se dispara en el momento en que un número cruza una línea:
gold: 80 → 95 → 101 ← fires on 95→101 (crossed above 100)
gold: 101 → 150 → 200 ← doesn't fire (already above)
gold: 200 → 50 → 120 ← fires on 50→120 (crossed above 100 again)Úsalo para hitos, avisos («la salud ha bajado de 20») y comprobaciones de muerte.
Una variable cambia se dispara cada vez que cambia la variable que elijas, tenga el valor que tenga:
gold: 80 → 95 ← fires
gold: 95 → 101 ← fires
gold: 101 → 150 ← firesPara que sirva de algo necesita una condición en SOLO SI («solo si Oro ≥ 100»), y vuelve a comprobarla con cada cambio. En un logro, lo que te importa es el cruce, así que lo natural es Una variable cruza un umbral.
Más logros
Cada logro nuevo es un comportamiento más una fila en la página de logros:
| Logro | Cuándo se dispara |
|---|---|
| Parlanchín | Cada N turnos: 50, con Máx. activaciones en 1 |
| Acaparador | Una variable cruza un umbral: Oro sube por encima de 500 |
| Alma social | La IA dice una palabra clave: confía en ti, os hacéis amigos |
| De vuelta del abismo | Una variable cruza un umbral: con Salud bajando por debajo de 10 se pone en verdadero un Interruptor «Casi muerto»; un segundo comportamiento, con Salud subiendo por encima de 50 y SOLO SI Casi muerto es verdadero, desbloquea el momento |
Referencia rápida
| Lo que quieres | Cómo hacerlo |
|---|---|
| Desbloquear cuando un número llega a una meta | Cuándo se dispara: Una variable cruza un umbral, Sube por encima de |
| Desbloquear cuando se dice algo | El jugador dice una palabra clave o La IA dice una palabra clave |
| Mostrar una tarjeta y recordarla | Efecto: Desbloquear un momento, con Se guarda en (una lista) |
| Que solo se desbloquee una vez | Mismo título, misma lista. El momento no sale si su título ya está en la lista |
| Conservar los logros en partidas nuevas | Marca Se conserva entre partidas (para cada jugador) en la variable de lista |
| Mostrar logros encontrados y bloqueados | Interfaz → plantilla Colección, o una parte Lista con Bloqueada hasta |
| Contarlos | Una variable de Número con la fórmula len(Achievements) |
| Un panel a medida | Código de interfaz que lea la lista (la ruta con código propio de arriba) |
