Inventario y equipo
Construye una cuadrícula de inventario — muestra todos los artículos que el jugador ha recolectado, con iconos y cantidades. Los consumibles pueden usarse (desaparecen cuando se agotan), el equipo puede ponerse. Esta receta te muestra cómo combinar una variable JSON, lógica del Root Component y comportamientos para construir un sistema de inventario completo.
Lo que vas a construir
Un panel de inventario integrado en la interfaz del chat. El jugador ve todos sus artículos, cada uno mostrando un icono, nombre y cantidad. Debajo de cada artículo hay un botón de acción:
- Consumibles (por ejemplo, pociones) — haz clic en "Use" → HP se restaura en 20 → el conteo de pociones disminuye en 1 → se elimina del inventario cuando el conteo llega a 0 → emergente dice "Used a potion! HP +20"
- Equipo (por ejemplo, espada de hierro) — haz clic en "Equip" → la ranura de arma muestra "Iron Sword" → la IA sabe que el jugador está blandiendo una espada de hierro → emergente dice "Equipped Iron Sword!"
El jugador hace clic en el botón "Use" en una poción
→ el renderizador comprueba: ¿el inventario contiene una poción?
→ sí: actualiza el array de inventario, hp +20, toast de éxito
→ no: toast de advertencia "No potions left!"
El jugador hace clic en el botón "Equip" en Iron Sword
→ el renderizador comprueba: ¿ya equipado?
→ no: dispara el comportamiento "equip-sword"
→ el comportamiento establece equipped_weapon, le dice a la IA, muestra notificación
→ sí: toast informativo "Already equipped!"Cómo funciona
El inventario se almacena como una variable JSON — una única variable que contiene un array completo de objetos de artículo. El Root Component lee este array para mostrar la cuadrícula, y lo manipula directamente usando api.setVariable() cuando el jugador usa o adquiere artículos.
¿Por qué manejar la lógica en el Root Component? Los operadores de condición del sistema de comportamientos (eq, neq, gt, lt, contains, etc.) funcionan sobre valores simples — números, cadenas, booleanos. No pueden buscar dentro de arrays JSON (por ejemplo, "¿contiene el array un objeto con name = Potion?"). Para estructuras de datos complejas como inventarios, el Root Component es el lugar adecuado para manejar la lógica usando JavaScript.
Los comportamientos aún se usan para cosas en las que son buenos: establecer variables simples (equipped_weapon), inyectar instrucciones a la IA ("Tell AI") y mostrar notificaciones.
La división:
| Qué | Dónde | Por qué |
|---|---|---|
| Mostrar la cuadrícula de inventario | Root Component | Lee el array JSON y renderiza UI |
| Usar un consumible | Root Component | Necesita encontrar, actualizar y eliminar elementos del array |
| Equipar un arma | Comportamiento | Establece una variable de tipo string + le dice a la IA |
| Decir a la IA sobre los cambios | Comportamiento | Solo los comportamientos pueden inyectar instrucciones a la IA |
Paso a paso
Paso 1: Crea las variables
Necesitamos 3 variables — inventario (array JSON), puntos de vida (número) y arma actualmente equipada (cadena).
Editor → barra lateral izquierda → pestaña Variables → haz clic en "Add Variable" para cada una
Variable 1: Inventario
| Campo | Valor | Por qué |
|---|---|---|
| Nombre visible | Inventario | Etiqueta legible para ti |
| ID | inventory | El ID usado en código y comportamientos para leer/escribir esta variable |
| Tipo | JSON | El inventario es un array — necesita el tipo JSON para almacenarlo |
| Valor por defecto | [{"name":"Potion","icon":"🧪","count":2},{"name":"Iron Sword","icon":"⚔️","count":1}] | Las nuevas sesiones empiezan con 2 pociones y 1 espada de hierro |
| Categoría | Inventory | Lo agrupa bajo la categoría Inventory |
| Reglas de comportamiento | Los botones del inventario gestionan automáticamente las acciones de usar y equipar. También puedes añadir artículos durante la historia (el jugador encuentra botín, recibe una recompensa) o quitar artículos (rotos, perdidos, robados). | Le dice a la IA que el inventario también puede cambiar durante la narración |
El valor predeterminado de una variable JSON debe ser JSON válido. Usa comillas dobles alrededor de los nombres de los campos y los valores de cadena. Cada objeto de artículo tiene tres campos:
name(para coincidencia y visualización),icon(para la UI),count(para seguir la cantidad de los consumibles).
Variable 2: Puntos de vida
| Campo | Valor | Por qué |
|---|---|---|
| Nombre visible | Puntos de vida | Etiqueta legible |
| ID | hp | Se usa cuando las pociones restauran HP |
| Tipo | Number | HP es numérico — necesita sumar/restar |
| Valor por defecto | 80 | Empezar por debajo del máximo le da al jugador una razón para usar una poción |
| Valor mínimo | 0 | Evita que HP sea negativo |
| Valor máximo | 100 | Tope de HP en 100, evita acumulación infinita |
| Categoría | Stats | Variable de estadística del personaje |
| Reglas de comportamiento | El valor actual representa los puntos de vida restantes del jugador (0-100). Disminuye en combate o situaciones peligrosas, aumenta al usar pociones o descansar. | Le dice a la IA cuándo cambiar HP |
Variable 3: Arma equipada
| Campo | Valor | Por qué |
|---|---|---|
| Nombre visible | Arma equipada | Etiqueta legible |
| ID | equipped_weapon | Registra el nombre del arma equipada del jugador |
| Tipo | String | Almacena el nombre del arma como texto |
| Valor por defecto | (déjalo vacío) | Cadena vacía = nada equipado |
| Categoría | Custom | Variable de estado del equipo |
| Reglas de comportamiento | El valor actual es el nombre del arma que el jugador tiene equipada. Una cadena vacía significa que no hay nada equipado. El botón de equipar lo establece automáticamente, pero también puedes cambiarlo durante la historia — por ejemplo, el arma se rompe, se la roban o el jugador encuentra una nueva. | Le dice a la IA que el estado del equipo también puede cambiar narrativamente |
¿Por qué usar una cadena para equipped_weapon en lugar de JSON? Porque el jugador solo puede blandir un arma a la vez. Una cadena simple es suficiente — vacía significa desequipado,
"Iron Sword"significa equipado. Si quieres un sistema de equipo de múltiples ranuras (arma + armadura + accesorio), podrías usar un objeto JSON en su lugar.
Paso 2: Crea los comportamientos
Necesitamos 2 comportamientos — equipar espada de hierro (éxito y ya equipado). El uso de pociones se maneja completamente en el Root Component.
Editor → pestaña Behaviors → haz clic en "Add Behavior"
Comportamiento 1: Equipar Espada de Hierro (éxito)
WHEN (disparador):
| Campo | Valor | Por qué |
|---|---|---|
| Trigger Type | Action button pressed | Se dispara cuando el Root Component llama a executeAction("equip-sword") |
| Action ID | equip-sword | Coincide con la llamada executeAction("equip-sword") en el Root Component |
ONLY IF (condiciones):
| Variable | Operador | Valor | Por qué |
|---|---|---|---|
equipped_weapon | neq | Iron Sword | No ya equipado — evita superposición con el Comportamiento 2 |
DO (efectos):
Añade estos efectos en orden:
| Tipo de efecto | Configuración | Qué hace |
|---|---|---|
| Modificar variable | Variable equipped_weapon, operación set, valor Iron Sword | Establece el arma actual a Iron Sword |
| Tell AI | Contenido: El jugador equipó una Espada de Hierro. A partir de ahora, el jugador empuña un mandoble de hierro. Refleja la presencia del arma en las descripciones de combate y en las interacciones. | Inyecta una instrucción para que la IA sepa del arma |
| Mostrar notificación | Mensaje Equipped Iron Sword!, estilo achievement | Emergente de éxito dorado |
¿Qué hace "Tell AI"? Inyecta una instrucción temporal en el contexto de la IA. De esta forma, cuando la IA escriba su próxima respuesta, sabe que el jugador acaba de equipar una espada y puede reflejarlo en la narrativa (por ejemplo, "You tighten your grip on the iron sword. Its cold edge glints in the firelight.").
Comportamiento 2: Equipar Espada de Hierro (ya equipada)
WHEN:
| Campo | Valor |
|---|---|
| Trigger Type | Action button pressed |
| Action ID | equip-sword |
ONLY IF:
| Variable | Operador | Valor | Por qué |
|---|---|---|---|
equipped_weapon | eq | Iron Sword | Ya equipada — no es necesario equipar de nuevo |
DO:
| Tipo de efecto | Configuración | Qué hace |
|---|---|---|
| Mostrar notificación | Mensaje Iron Sword is already equipped!, estilo info | Emergente informativo azul |
¿Por qué dividir esto en dos comportamientos? Mismo patrón que la receta de la tienda — un único comportamiento solo puede tener un conjunto de condiciones. Si las condiciones pasan, se ejecuta; si no, no pasa nada. Así que usamos dos comportamientos para cubrir ambos casos. Escuchan el mismo action ID, pero sus condiciones son mutuamente exclusivas — solo uno se dispara.
¿Por qué no hay comportamiento "use-potion"? Porque comprobar si un array JSON contiene un artículo específico requiere JavaScript — el operador
containsdel sistema de comportamientos solo funciona en cadenas, no en arrays. Así que la lógica de las pociones vive en el Root Component donde tenemos acceso completo a JavaScript. El Root Component actualiza las variablesinventoryyhpdirectamente medianteapi.setVariable().
Paso 3: Añade el panel de inventario en el Root Component
Este es el paso que hace que la UI del inventario aparezca en el chat. Mostraremos tres secciones debajo del último mensaje: una barra de HP, una ranura de equipo y una cuadrícula de inventario (cada artículo con un botón de acción).
Editor → sección Custom UI → abre index.tsx → pega lo siguiente (reemplazando el predeterminado return <Chat />):
export default function MyWorld() {
var api = useYumina();
var msgs = api.messages || [];
// Lee las variables
var hp = Number(api.variables.hp ?? 80);
var equippedWeapon = String(api.variables.equipped_weapon || "");
var inventory = Array.isArray(api.variables.inventory)
? api.variables.inventory
: [];
// ── Lógica del inventario (se ejecuta en el Root Component) ──
function useItem(itemName) {
var inv = Array.isArray(api.variables.inventory)
? api.variables.inventory
: [];
var idx = -1;
for (var i = 0; i < inv.length; i++) {
if (inv[i] && inv[i].name === itemName) { idx = i; break; }
}
if (idx === -1) {
api.showToast("No " + itemName + " left!", "error");
return;
}
var item = inv[idx];
var newInv = inv.slice(); // copia el array
if (Number(item.count) <= 1) {
newInv.splice(idx, 1); // elimínalo por completo
} else {
newInv[idx] = { name: item.name, icon: item.icon, count: Number(item.count) - 1 };
}
api.setVariable("inventory", newInv);
// Específico para pociones: restaurar HP
if (itemName === "Potion") {
var currentHp = Number(api.variables.hp ?? 0);
api.setVariable("hp", Math.min(currentHp + 20, 100));
api.showToast("Used a potion! HP +20", "success");
}
}
function equipItem(itemName, actionId) {
if (equippedWeapon === itemName) {
api.showToast(itemName + " is already equipped!", "info");
return;
}
api.executeAction(actionId); // dispara el comportamiento para set + Tell AI
}
// Mapa de tipos de artículo: decide qué acción recibe cada artículo
var itemActions = {
"Potion": { type: "consumable", handler: function() { useItem("Potion"); }, label: "Use" },
"Iron Sword": { type: "equipment", handler: function() { equipItem("Iron Sword", "equip-sword"); }, label: "Equip" },
};
return (
<Chat renderBubble={(msg) => {
var isLastMsg = msg.messageIndex === msgs.length - 1;
return (
<div>
{/* Renderiza el texto del mensaje normalmente (la plataforma ya renderizó el HTML, usa contentHtml directamente) */}
<div
style={{ color: "#e2e8f0", lineHeight: 1.7 }}
dangerouslySetInnerHTML={{ __html: msg.contentHtml }}
/>
{/* Muestra el panel de inventario solo debajo del último mensaje */}
{isLastMsg && (
<div style={{
marginTop: "16px",
padding: "16px",
background: "rgba(15, 23, 42, 0.6)",
borderRadius: "12px",
border: "1px solid #334155",
}}>
{/* ====== Barra de HP ====== */}
<div style={{
display: "flex",
alignItems: "center",
gap: "10px",
marginBottom: "14px",
}}>
<span style={{ fontSize: "16px" }}>❤️</span>
<div style={{ flex: 1 }}>
<div style={{
display: "flex",
justifyContent: "space-between",
marginBottom: "4px",
}}>
<span style={{ color: "#94a3b8", fontSize: "12px" }}>HP</span>
<span style={{ color: "#e2e8f0", fontSize: "12px", fontWeight: "bold" }}>
{hp} / 100
</span>
</div>
<div style={{
height: "8px",
background: "#1e293b",
borderRadius: "4px",
overflow: "hidden",
}}>
<div style={{
height: "100%",
width: Math.min(hp, 100) + "%",
background: hp > 50
? "linear-gradient(90deg, #22c55e, #4ade80)"
: hp > 20
? "linear-gradient(90deg, #eab308, #facc15)"
: "linear-gradient(90deg, #ef4444, #f87171)",
borderRadius: "4px",
transition: "width 0.3s ease",
}} />
</div>
</div>
</div>
{/* ====== Ranura de equipo ====== */}
<div style={{
display: "flex",
alignItems: "center",
gap: "8px",
marginBottom: "14px",
padding: "10px 14px",
background: "rgba(30, 41, 59, 0.8)",
borderRadius: "8px",
border: "1px solid #475569",
}}>
<span style={{ fontSize: "16px" }}>⚔️</span>
<span style={{ color: "#94a3b8", fontSize: "13px" }}>Weapon:</span>
<span style={{
color: equippedWeapon ? "#e2e8f0" : "#475569",
fontSize: "13px",
fontWeight: equippedWeapon ? "600" : "normal",
fontStyle: equippedWeapon ? "normal" : "italic",
}}>
{equippedWeapon || "None"}
</span>
</div>
{/* ====== Encabezado del inventario ====== */}
<div style={{
fontSize: "14px",
fontWeight: "bold",
color: "#94a3b8",
marginBottom: "10px",
textTransform: "uppercase",
letterSpacing: "1px",
}}>
Inventory
</div>
{/* ====== Cuadrícula de inventario ====== */}
{inventory.length === 0 ? (
<div style={{
padding: "24px",
textAlign: "center",
color: "#475569",
fontSize: "13px",
background: "rgba(30, 41, 59, 0.4)",
borderRadius: "8px",
border: "1px dashed #334155",
}}>
Inventory is empty
</div>
) : (
<div style={{
display: "grid",
gridTemplateColumns: "repeat(auto-fill, minmax(140px, 1fr))",
gap: "8px",
}}>
{inventory.map(function(item, idx) {
var name = String(item?.name || item);
var icon = String(item?.icon || "📦");
var count = Number(item?.count ?? 1);
var action = itemActions[name];
return (
<div
key={idx}
style={{
display: "flex",
flexDirection: "column",
alignItems: "center",
padding: "12px 8px 8px",
background: "rgba(30, 41, 59, 0.8)",
borderRadius: "8px",
border: equippedWeapon === name
? "1px solid #22d3ee"
: "1px solid #475569",
gap: "6px",
}}
>
<span style={{ fontSize: "28px" }}>{icon}</span>
<span style={{
color: "#e2e8f0",
fontSize: "12px",
fontWeight: "600",
textAlign: "center",
}}>
{name}
</span>
<span style={{
color: "#64748b",
fontSize: "11px",
}}>
x{count}
</span>
{/* Botón de acción */}
{action && (
<button
onClick={action.handler}
style={{
marginTop: "4px",
padding: "4px 14px",
background: action.type === "consumable"
? "linear-gradient(135deg, #065f46, #047857)"
: equippedWeapon === name
? "linear-gradient(135deg, #374151, #4b5563)"
: "linear-gradient(135deg, #1e3a5f, #1e40af)",
border: action.type === "consumable"
? "1px solid #10b981"
: equippedWeapon === name
? "1px solid #6b7280"
: "1px solid #3b82f6",
borderRadius: "6px",
color: action.type === "consumable"
? "#a7f3d0"
: equippedWeapon === name
? "#9ca3af"
: "#bfdbfe",
fontSize: "12px",
fontWeight: "600",
cursor: "pointer",
width: "100%",
}}
>
{equippedWeapon === name ? "Equipped" : action.label}
</button>
)}
</div>
);
})}
</div>
)}
</div>
)}
</div>
);
}} />
);
}Recorrido por el código
No te intimides por la longitud — lo que hace es muy directo. Vamos sección por sección:
Configuración básica
var api = useYumina();
var msgs = api.messages || [];
// ...
<Chat renderBubble={(msg) => {
var isLastMsg = msg.messageIndex === msgs.length - 1;
// ...
}} />- El Root Component
MyWorld()es la entrada para la UI del mundo.<Chat renderBubble={...} />deja a la plataforma manejar la lista de mensajes, el cuadro de entrada y el desplazamiento — solo tomas el control del aspecto de cada burbuja useYumina()— toma la API de Yumina para que puedas leer variables y disparar accionesmsg.messageIndex— el índice de la burbuja actual en la lista de mensajes. El panel de inventario solo se renderiza debajo del último mensaje, así que no se repite en cada unomsg.contentHtml— el HTML que la plataforma ya renderizó desde Markdown, se puede pasar directamente adangerouslySetInnerHTML
Leyendo variables
var hp = Number(api.variables.hp ?? 80);
var equippedWeapon = String(api.variables.equipped_weapon || "");
var inventory = Array.isArray(api.variables.inventory)
? api.variables.inventory
: [];api.variables.hp— lee los puntos de vida.?? 80es un fallback en caso de que la variable no se haya cargado aúnapi.variables.equipped_weapon— lee el arma actual. Cadena vacía significa nada equipadoapi.variables.inventory— lee el inventario.Array.isArray()protege contra tipos inesperados
Funciones de lógica de inventario
function useItem(itemName) {
var inv = Array.isArray(api.variables.inventory)
? api.variables.inventory : [];
var idx = -1;
for (var i = 0; i < inv.length; i++) {
if (inv[i] && inv[i].name === itemName) { idx = i; break; }
}
if (idx === -1) {
api.showToast("No " + itemName + " left!", "error");
return;
}
// ... update array and call api.setVariable()
}Este es el patrón clave. Dado que los operadores de condición del sistema de comportamientos no pueden buscar dentro de arrays JSON, manejamos la lógica directamente aquí en el Root Component:
- Encuentra el artículo — recorre el array y coincide por
name - Comprueba si existe — si no se encuentra, muestra un toast de error
- Actualiza el array — disminuye el conteo o elimina por completo
- Escríbelo de vuelta — llama a
api.setVariable("inventory", newInv)para persistir el cambio
Para el equipo, equipItem() delega a api.executeAction() porque el comportamiento maneja el establecimiento de la variable y la inyección de una instrucción a la IA:
function equipItem(itemName, actionId) {
if (equippedWeapon === itemName) {
api.showToast(itemName + " is already equipped!", "info");
return;
}
api.executeAction(actionId);
}Mapa de tipos de artículo
var itemActions = {
"Potion": { type: "consumable", handler: function() { useItem("Potion"); }, label: "Use" },
"Iron Sword": { type: "equipment", handler: function() { equipItem("Iron Sword", "equip-sword"); }, label: "Equip" },
};Una tabla de búsqueda. Dado el nombre de un artículo, te dice la etiqueta del botón y la función handler a llamar. El campo type controla el color del botón — los consumibles obtienen verde, el equipo obtiene azul. ¿Quieres añadir un nuevo artículo? Añade una línea aquí. Para consumibles, añade lógica a useItem. Para equipo, crea un comportamiento correspondiente en el editor.
Botón de acción
<button onClick={action.handler}>
{equippedWeapon === name ? "Equipped" : action.label}
</button>Hacer clic en el botón llama directamente a la función handler. Para consumibles, el handler gestiona el array en JavaScript. Para equipo, el handler llama a api.executeAction() que dispara el comportamiento correspondiente.
¿No quieres escribir código tú mismo? Usa Studio AI
Barra superior del editor → haz clic en "Enter Studio" → panel AI Assistant → describe lo que quieres en lenguaje natural, por ejemplo "Construye una cuadrícula de inventario con una barra de HP, ranura de equipo y artículos que se puedan usar o equipar" — la IA generará el código por ti.
Paso 4: Guarda y prueba
- Haz clic en Save en la parte superior del editor
- Haz clic en Start Game o vuelve a la página de inicio e inicia una nueva sesión
- Verás el panel de inventario debajo de la respuesta de la IA: HP 80/100, ranura de arma vacía, 2 pociones y 1 espada de hierro
- Haz clic en "Use" en una poción — HP va de 80 a 100, la poción desaparece, el toast dice "Used a potion! HP +20"
- Haz clic en "Equip" en Iron Sword — la ranura de arma muestra "Iron Sword", el botón se vuelve gris y dice "Equipped", el emergente dice "Equipped Iron Sword!"
- Haz clic en el botón "Equipped" en Iron Sword de nuevo — el toast dice "Iron Sword is already equipped!"
- Sigue chateando con la IA — si añadiste el efecto "Tell AI", la respuesta de la IA reflejará que el jugador blande una espada de hierro
Si algo no funciona:
| Síntoma | Causa probable | Solución |
|---|---|---|
| El panel de inventario no aparece | El código del Root Component no se guardó o tiene un error de sintaxis | Comprueba el estado de compilación en la parte inferior de la sección Custom UI — debería mostrar un "OK" verde |
| El inventario no muestra artículos | El valor predeterminado de la variable JSON tiene mal formato | Asegúrate de que el predeterminado sea un array JSON válido con nombres de campos entre comillas dobles |
| El botón no hace nada al hacer clic | El action ID del comportamiento no coincide con el código | Confirma que el action ID del comportamiento sea exactamente equip-sword, coincidiendo con el argumento executeAction() en el código |
| Se usó una poción pero no desapareció | La función useItem no puede encontrar el nombre del artículo | Asegúrate de que el campo name del artículo en el JSON coincida exactamente con lo que useItem() busca — sensible a mayúsculas |
| HP no cambió | La llamada api.setVariable no está alcanzando la variable correcta | Comprueba que el ID de la variable sea exactamente hp — debe coincidir con la definición de la variable |
| Equipado pero la IA no lo sabe | Falta el efecto "Tell AI" | Añade un efecto "Tell AI" dentro de la sección DO del comportamiento de equipar |
Cómo puede la IA modificar el inventario
La IA también puede añadir o eliminar artículos durante la historia usando directivas. Como el inventario es una variable JSON, la IA puede usar la directiva push para añadir artículos:
Derrotaste al goblin y encontraste una poción de salud entre sus pertenencias.
[inventory: push {"name":"Potion","icon":"🧪","count":1}]Limitaciones de las directivas de IA en arrays
La directiva push funciona bien para añadir artículos. Sin embargo, delete en arrays solo funciona con un índice numérico (por ejemplo, [inventory: delete 0] elimina el primer elemento), y merge solo funciona en objetos planos, no en arrays. Para operaciones complejas de inventario (eliminar un artículo específico por nombre, actualizar conteos de artículos), usa la lógica JavaScript del Root Component o diseña tu sistema para que la IA comunique su intención a través de otras variables sobre las que los comportamientos puedan actuar.
Referencia rápida
| Qué quieres | Cómo hacerlo |
|---|---|
| Almacenar una lista de artículos | Crea una variable JSON con un valor predeterminado de [{...}, ...] |
| Mostrar una cuadrícula de inventario | En el Root Component, usa CSS Grid + inventory.map() |
| Usar un consumible | Root Component: encontrar artículo → actualizar array → api.setVariable() → mostrar toast |
| Equipar un artículo | Root Component: llama a api.executeAction() → Comportamiento: establecer variable + Tell AI |
| Comprobar si el jugador posee un artículo | Root Component: inventory.find(i => i.name === "ItemName") |
| Añadir un artículo (IA) | Directiva de IA: [inventory: push {"name":"Item","icon":"📦","count":1}] |
| Seguir el equipo actual | Crea una variable de tipo string — cadena vacía = nada equipado |
| Botón dispara usar/equipar | En el Root Component, llama a funciones handler o api.executeAction("actionId") |
| Hacer saber a la IA sobre los cambios | Añade un efecto "Tell AI" en el comportamiento |
Pruébalo tú mismo — mundo demo importable
Descarga este JSON e impórtalo como un nuevo mundo para ver todo en acción:
Cómo importar:
- Ve a Yumina → My Worlds → Create New World
- En el editor, haz clic en More Actions → Import Package
- Selecciona el archivo
.jsondescargado - El mundo se crea con todas las variables, comportamientos y Root Component preconfigurados
- Inicia una nueva sesión y pruébalo
Qué incluye:
- 3 variables (
inventory+hppuntos de vida +equipped_weaponarma actual) - 2 comportamientos (equipar espada de hierro éxito + ya equipada)
- Un Root Component (barra de HP + ranura de equipo + cuadrícula de inventario + botones de acción + lógica de usar/equipar)
Esta es la Receta #7
Las recetas anteriores cubrieron el salto de escenas, los sistemas de combate, las interfaces de tienda y la creación de personaje. Esta receta te enseña a gestionar un inventario de array JSON usando lógica JavaScript del Root Component combinada con comportamientos para cambios de estado simples. El mismo patrón funciona para registros de misiones, árboles de habilidades, recetas de crafteo — cualquier cosa que necesite "gestionar una lista, realizar operaciones en sus elementos".
