Lección 52 de 170

Diseñar elecciones sin escrituras globales ocultas

Curso de desarrollo de videojuegos con IA

Traza una elección narrativa desde la intención hasta la confirmación de la autoridad correspondiente y sus consecuencias de dominio, a la vez que especificas una entrada, salida y alternativa seguras para el bloqueo del puntero durante el diálogo.

754. Identidad de la lección

Módulo
2.8 — Narrativa interactiva
Lección
Diseñar elecciones sin escrituras globales ocultas
Tipo académico
Estudio de caso
Orden
Lección 2 del módulo
Tiempo estimado
35–45 minutos, incluida la práctica

755. Nota de alcance

El diálogo con bloqueo del puntero es un tema documentado de CONTRABAND. Las ramas del intendente, la transferencia de suministros y la pista sobre una ruta que aparecen a continuación son ejemplos didácticos hipotéticos. No describen una implementación, un incidente ni una regla de juego documentados de CONTRABAND.

756. Objetivo de aprendizaje

Al finalizar esta lección, podrás especificar una rama narrativa como un contrato de elección trazable, separar la intención de la confirmación, asignar cada consecuencia persistente al sistema responsable y documentar una entrada, salida, observación y alternativa seguras para el bloqueo del puntero.

757. Por qué importa

Una elección de diálogo suele afectar a más de un sistema. Puede solicitar una transferencia de recursos, provocar una consecuencia en una relación o hacer avanzar un objetivo. Eso no convierte al controlador de diálogo en la autoridad sobre el inventario, las relaciones o las misiones.

Existe una escritura global oculta cuando un único controlador modifica silenciosamente estados que pertenecen a varios dominios. Es difícil validar una rama así porque la selección, la autorización, la persistencia y la presentación quedan reunidas en una sola operación. También puede producir un estado incoherente: el sistema de economía rechaza una transferencia mientras que los sistemas de relaciones o misiones ya han registrado el éxito.

Una rama trazable separa dos etapas:

  1. Intención: lo que el jugador solicitó.
  2. Resultado confirmado: lo que el sistema responsable validó y registró.

Solo el resultado confirmado debe autorizar las consecuencias posteriores que dependan del éxito.

El diálogo también crea un límite entre modos de interacción. El bloqueo del puntero depende de un ciclo de vida asíncrono del navegador y no queda garantizado por el mero hecho de llamar a requestPointerLock(). La restauración puede requerir una activación transitoria del usuario, y el éxito o el fallo deben observarse en lugar de darse por supuestos.

758. Conocimientos previos

Debes poder:

  • distinguir el estado del diálogo de su presentación;
  • identificar el sistema responsable de un hecho persistente;
  • describir nodos y elecciones de diálogo;
  • aplicar la distinción de la Etapa 2 entre presentación temporal y estado persistente del juego;
  • reconocer el bloqueo del puntero como un modo de interacción y no como un hecho narrativo.

La lección anterior estableció que el panel de diálogo no debe convertirse en la autoridad sobre el estado duradero del mundo.

759. Concepto central: la intención no es una confirmación

Un contrato de elección útil identifica la elección, la solicitud, la autoridad correspondiente y los posibles resultados confirmados.

Elemento del contrato Pregunta Ejemplo hipotético
Identidad de la elección ¿Qué seleccionó el jugador? offer_one_crate
Intención o solicitud ¿Qué operación se solicita? Transferir una caja del jugador
Sistema responsable ¿Qué sistema valida y registra la operación? Economía o inventario
Éxito confirmado ¿Qué evento demuestra que terminó la operación? SuppliesTransferCompleted
Rechazo confirmado ¿Qué evento indica que no se completó? SuppliesTransferRejected
Consumidores posteriores ¿Qué sistemas pueden reaccionar al éxito confirmado? Relaciones y misiones

Un evento de intención no demuestra que la operación solicitada haya ocurrido. Los sistemas de relaciones y misiones no deben interpretar por su cuenta un evento SuppliesTransferRequested sin validar como si fuera un éxito. Si sus consecuencias requieren una transferencia completada, deben consumir SuppliesTransferCompleted.

760. Secuencia segura de eventos

La rama hipotética del intendente puede especificarse así:

1. El diálogo registra la selección:
   choiceId = offer_one_crate

2. El diálogo emite una intención:
   SuppliesTransferRequested
   correlationId = transfer-42
   quantity = 1
   source = player
   recipient = quartermaster

3. El sistema de economía procesa la solicitud:
   - valida que la operación esté permitida
   - valida que haya una caja disponible
   - registra la retirada del inventario si es válida

4a. Si el registro se completa, economía emite:
    SuppliesTransferCompleted
    correlationId = transfer-42
    quantity = 1

4b. Si se rechaza, economía emite:
    SuppliesTransferRejected
    correlationId = transfer-42
    reasonCode = insufficient_supplies u otro motivo definido

5. Los sistemas de relaciones y misiones:
   - no consideran la solicitud una prueba de éxito
   - consumen el evento de finalización cuando corresponde
   - no aplican consecuencias de éxito después de un rechazo

Los nombres son ejemplos, pero la distinción es obligatoria: la selección genera una solicitud; el sistema responsable genera el resultado confirmado.

761. Correlación, orden y ausencia de escrituras parciales

La especificación de una rama debe incluir algo más que nombres de eventos.

Correlación

Cada solicitud y su resultado necesitan un identificador de correlación compartido. Así, los consumidores pueden distinguir dos selecciones parecidas y asociar una finalización o un rechazo con la rama correcta.

Orden

Una consecuencia que dependa del éxito no debe procesarse antes del evento de finalización emitido por el sistema responsable. El orden lógico requerido es:

elección seleccionada
→ transferencia solicitada
→ economía valida y registra
→ resultado completado o rechazado
→ los consumidores dependientes del éxito reaccionan al resultado completado

En una implementación asíncrona, el orden de entrega puede variar. Por eso, los consumidores deben imponer la dependencia y no confiar solo en el momento de llegada.

Ausencia de escrituras parciales tras un rechazo

Si el sistema de economía rechaza la transferencia:

  • el inventario no cambia;
  • no se registra una mejora de relación asociada a una transferencia completada;
  • no avanza ningún objetivo que requiera una transferencia completada;
  • el jugador recibe una presentación de rechazo, no una presentación de éxito.

Entregas duplicadas y reintentos

Cada consumidor debe procesar el evento confirmado de forma idempotente mediante su identificador de evento o correlación. Recibir la misma confirmación más de una vez no debe aplicar repetidamente la misma consecuencia de relación o misión.

Fallo en otro dominio después de la confirmación

La transferencia confirmada demuestra que la operación económica se completó; no demuestra que todos los consumidores posteriores ya hayan persistido sus consecuencias. Cada consumidor registra su propio estado de procesamiento y puede reintentarlo de forma segura. Si el diseño exige que todos los dominios tengan éxito o fallen juntos, la especificación necesita un coordinador y una política de compensación explícitos, no la suposición de una transacción global invisible.

762. Mapa de responsabilidades

Hecho Sistema responsable Desencadenante permitido
Caja retirada del inventario Economía o inventario Solicitud de transferencia validada
Transferencia completada o rechazada Economía o inventario Resultado del intento de validación y registro
Consecuencia de relación registrada Sistema de relaciones Finalización confirmada de la transferencia
Progreso del objetivo registrado Sistema de misiones Finalización confirmada, si el objetivo la requiere
Respuesta mostrada en el diálogo Presentación del diálogo Resultado confirmado de finalización o rechazo
Estado del bloqueo observado Controlador del modo de interacción Eventos del ciclo de vida del bloqueo

La capa de diálogo puede mostrar un estado pendiente mientras se realiza la validación. No debe anunciar un éxito completo solo porque el jugador seleccionó la opción.

763. El bloqueo del puntero es un contrato de interacción asíncrono

La entrada y la salida del diálogo deben especificarse por separado de la persistencia narrativa.

Entrada

Cuando el juego con el puntero bloqueado entra en diálogo:

  1. Registra el modo de interacción anterior.
  2. Libera el bloqueo del puntero.
  3. Observa el cambio correspondiente en el ciclo de vida del bloqueo.
  4. Entrega el foco y la interpretación de la entrada a la interfaz de diálogo.
  5. No uses el estado del bloqueo como prueba del éxito o fracaso narrativo.

Salida

Cuando se cierra el diálogo:

  1. Registra la causa de salida, como un clic del jugador, una cancelación o un resultado narrativo asíncrono.
  2. Cierra la presentación y restaura la entrada de juego solo si el juego realmente va a continuar.
  3. Determina si el modo anterior requería el bloqueo del puntero.
  4. Comprueba que el lienzo siga siendo apto para recibirlo.
  5. Solicita el bloqueo solo desde una ruta compatible con los requisitos de activación del usuario del navegador.
  6. Observa pointerlockchange para confirmar el estado resultante.
  7. Trata pointerlockerror, o un estado que siga desbloqueado, como una solicitud fallida y no como un éxito.

requestPointerLock() es una solicitud, no una asignación de estado síncrona. El navegador puede exigir una activación transitoria del usuario. Si el diálogo solo se cierra después de un procesamiento asíncrono, es posible que la activación generada por el clic original ya no esté disponible.

Alternativa segura

Si la restauración automática no está disponible o se rechaza:

  • mantén desactivado el control de cámara mediante movimiento mientras el puntero siga libre;
  • presenta un control explícito como Haz clic para continuar o Haz clic para volver a capturar el puntero;
  • llama a requestPointerLock() desde esa nueva acción del jugador;
  • continúa observando los eventos del ciclo de vida;
  • permite navegar sin bloqueo o cancelar cuando el diseño lo contemple.

No solicites el bloqueo repetidamente mediante un bucle oculto, no des por supuesto el éxito y no dejes activo el control de cámara mientras el puntero esté libre.

764. Caso hipotético combinado

Entrada al diálogo:
  priorMode = pointer_locked_gameplay
  liberar el bloqueo
  esperar pointerlockchange
  activar la entrada del diálogo

Selección de la opción:
  emitir SuppliesTransferRequested(correlationId)
  mostrar una respuesta pendiente

Resultado de economía:
  si se registró:
    emitir SuppliesTransferCompleted(correlationId)
  de lo contrario:
    emitir SuppliesTransferRejected(correlationId, reasonCode)

Respuesta posterior:
  relaciones y misiones consumen solo el resultado completado
  cada consumidor evita duplicados mediante el ID del evento o de correlación
  el rechazo no produce escrituras persistentes que dependan del éxito

Salida del diálogo tras un resultado asíncrono:
  restaurar el modo de entrada de juego
  no suponer que el clic anterior aún aporta activación del usuario
  solicitar el bloqueo solo si la acción de salida actual cumple los requisitos
  confirmar mediante pointerlockchange
  si ocurre pointerlockerror, mostrar un control explícito para continuar

Este diseño separa el resultado narrativo del resultado de interacción. El rechazo de una solicitud de bloqueo no revierte una transferencia de suministros confirmada, y una transferencia rechazada no determina si el navegador puede capturar el puntero.

765. Flujo de trabajo con IA

Usa la IA para inspeccionar un contrato, no para inventar sus autoridades ni sus reglas.

  1. Escribe la solicitud de la elección, el sistema responsable, los resultados confirmados y los consumidores.
  2. Añade un identificador de correlación y el orden requerido.
  3. Declara las reglas de rechazo y entrega duplicada.
  4. Especifica la entrada, la salida, los eventos del ciclo de vida, la activación del usuario y la alternativa del bloqueo del puntero.
  5. Pide a la IA que produzca un recorrido de eventos y señale consumidores que reaccionen a una intención como si fuera una confirmación.
  6. Pídele que identifique escrituras entre dominios, responsabilidades ausentes, rutas de rechazo incompletas y solicitudes de bloqueo cuyo éxito se dé por supuesto.
  7. Revisa tú el resultado antes de pedir una implementación.

Un prompt útil es:

«Revisa este contrato de elección narrativa y de interacción con bloqueo del puntero. Separa la intención del resultado confirmado, traza la correlación y el orden, identifica cada escritura persistente y su sistema responsable, comprueba el rechazo y las entregas duplicadas, y señala las transiciones de bloqueo que supongan activación del usuario o éxito síncrono. No inventes reglas del juego ni modifiques archivos».

766. Errores comunes

Distribuir una intención sin validar

onChoiceSelected():
  emit SuppliesTransferRequested

relationship.onRequested(): rewardRelationship()
quest.onRequested(): advanceObjective()
economy.onRequested(): maybeRemoveCrate()

Esto permite que relaciones y misiones registren un éxito aunque economía rechace la transferencia.

Mutación global oculta

onChoiceSelected():
  inventory.crates -= 1
  relationship.quartermaster += 10
  quest.suppliesObjective.complete = true
  saveGame()

Este enfoque oculta la validación, la autoridad, el orden y el comportamiento de fallo dentro del código de diálogo.

Dar por restaurado el bloqueo

closeDialogue():
  await finishDialogueWork()
  canvas.requestPointerLock()
  enableCameraLook()

Después del trabajo asíncrono, la activación transitoria del usuario puede haber caducado. La solicitud puede fallar y el control de cámara no debe activarse suponiendo que la captura tuvo éxito.

767. Práctica guiada

Diseña una rama hipotética en la que el jugador pueda compartir una pista sobre una ruta con un contacto o mantener la pista en privado. No atribuyas esta situación a CONTRABAND y no la implementes.

Completa la especificación:

Campo Tu especificación
IDs y texto mostrado de las elecciones
Intención emitida por cada elección
Identificador de correlación
Sistema responsable de validar cada intención
Eventos confirmados de éxito y rechazo
Orden requerido de los eventos
Consumidores del éxito confirmado
Hecho persistente que corresponde a cada consumidor
Regla para evitar escrituras parciales tras un rechazo
Regla para entregas duplicadas
Respuesta al jugador mientras está pendiente
Respuesta tras la confirmación o el rechazo
Modo anterior del bloqueo del puntero
Causa de salida del diálogo
Disponibilidad de activación del usuario al salir
Eventos del ciclo de vida que deben observarse
Alternativa tras el rechazo de la solicitud de bloqueo

Después, comprueba:

  1. ¿Puede cada consumidor dependiente del éxito señalar un evento confirmado y no solo una intención?
  2. ¿La ruta de rechazo deja sin cambios todos los dominios que dependen del éxito?
  3. ¿Puede recibirse dos veces la finalización sin duplicar consecuencias?
  4. ¿Puede un revisor seguir cada hecho persistente hasta un único sistema responsable?
  5. ¿La restauración del bloqueo depende del estado observado y no solo de una llamada a una función?
  6. Si caducó la activación del usuario, ¿existe una alternativa basada en una nueva acción explícita?
  7. ¿Se tratan la finalización narrativa y la restauración del bloqueo como resultados independientes?

Revisa el contrato si alguna respuesta es negativa.

768. Evidencia de validación

La especificación completada debe incluir:

  • al menos dos elecciones;
  • una intención para cada elección;
  • un sistema responsable de validar cada operación que pueda fallar;
  • resultados confirmados de éxito y rechazo;
  • datos de correlación compartidos;
  • reglas explícitas de orden y ausencia de escrituras parciales;
  • una regla de idempotencia o entrega duplicada;
  • un sistema responsable de cada hecho persistente;
  • condiciones de entrada y salida del bloqueo;
  • las observaciones pertinentes del ciclo de vida;
  • un análisis de la activación del usuario;
  • una alternativa explícita tras el fallo de restauración.

La rama es trazable cuando un revisor puede determinar qué se solicitó, qué se confirmó, qué sistema persistió cada consecuencia y cómo el rechazo evita un éxito falso. La transición de interacción es segura cuando el juego no da por supuesta la captura del puntero y el jugador dispone de una acción clara para recuperarla.

769. Ideas clave

  • Una elección seleccionada expresa una intención; no demuestra necesariamente que la operación se haya completado.
  • El sistema responsable emite el resultado confirmado de éxito o rechazo.
  • Los sistemas que dependen del éxito consumen la confirmación, no una intención sin validar.
  • Las reglas de correlación, orden, rechazo e idempotencia evitan consecuencias incoherentes.
  • requestPointerLock() es asíncrono y puede requerir una activación transitoria del usuario.
  • El éxito del bloqueo debe observarse mediante su ciclo de vida y debe existir una alternativa explícita cuando falle la restauración.
  • La persistencia narrativa y la restauración del modo de interacción son resultados independientes.

770. Próxima lección

Continúa con 2.9 — Sistemas de facciones. La consecuencia de relación confirmada que has identificado aquí se convertirá en una entrada para un contrato de relaciones bajo la autoridad del sistema de facciones. El diálogo seguirá siendo la fuente de la elección o del resultado confirmado, mientras que el sistema de relaciones de facción definirá y mantendrá la regla persistente.

771. Comprobación

Responde estas preguntas por tu cuenta antes de leer las respuestas.

El jugador selecciona «Ofrecer una caja». ¿Qué debe comunicar primero el sistema de diálogo si el sistema de economía tiene que validar la transferencia?

  • A. Un objetivo de misión completado
  • B. Un guardado global que dé por hecho el éxito de todas las consecuencias
  • C. Una mejora de relación confirmada
  • D. Una solicitud o intención de transferencia con datos de correlación
Mostrar respuesta y explicación

Respuesta: Una solicitud o intención de transferencia con datos de correlación

Por qué: La selección expresa una intención. El sistema de economía debe validar y registrar la transferencia antes de emitir una finalización o un rechazo confirmados.

¿Qué secuencia impide que los sistemas de relaciones y misiones registren un éxito después de una transferencia inválida?

  • A. El diálogo emite una solicitud; todos los sistemas la interpretan por separado; economía puede rechazarla después
  • B. El diálogo modifica todos los dominios y luego pregunta a economía si el cambio era válido
  • C. El diálogo emite una solicitud correlacionada; economía valida y registra; los demás sistemas consumen solo la finalización confirmada
  • D. Primero se actualiza la relación, después la misión y el inventario se comprueba al cerrar el diálogo
Mostrar respuesta y explicación

Respuesta: El diálogo emite una solicitud correlacionada; economía valida y registra; los demás sistemas consumen solo la finalización confirmada

Por qué: Los consumidores que dependen del éxito necesitan el evento de finalización emitido por el sistema responsable. Una solicitud por sí sola no demuestra que la transferencia fuera válida ni que se registrara.

El sistema de economía rechaza una transferencia porque el objeto necesario no está disponible. ¿Qué reglas deben formar parte del contrato de la rama?

  • A. El inventario permanece sin cambios
  • B. No se producen escrituras de relación ni de misión que dependan del éxito
  • C. El diálogo presenta un rechazo asociado con el identificador de correlación original
  • D. El progreso de la misión se aplica temporalmente para que la rama parezca más inmediata
Mostrar respuesta y explicación

Respuesta: El inventario permanece sin cambios; No se producen escrituras de relación ni de misión que dependan del éxito; El diálogo presenta un rechazo asociado con el identificador de correlación original

Por qué: Un rechazo no debe dejar un estado parcial que dependa del éxito. La correlación permite asociar la respuesta de rechazo con la elección original.

¿Qué demuestra que una solicitud para restaurar el bloqueo del puntero tuvo éxito?

  • A. La llamada a requestPointerLock() terminó
  • B. El panel de diálogo quedó oculto
  • C. El estado observado del ciclo de vida confirma que el elemento previsto tiene el bloqueo
  • D. La consecuencia narrativa se persistió
Mostrar respuesta y explicación

Respuesta: El estado observado del ciclo de vida confirma que el elemento previsto tiene el bloqueo

Por qué: requestPointerLock() es asíncrono. El código debe observar el ciclo de vida del bloqueo y gestionar los errores o un estado que siga desbloqueado.

El juego tenía el puntero bloqueado antes del diálogo. El jugador hace clic en una opción, pero el diálogo solo se cierra después de recibir un resultado asíncrono. La activación original del usuario ha caducado, requestPointerLock() se rechaza y el puntero sigue libre. ¿Qué transición de salida es la más segura?

  • A. Activar de inmediato el control de cámara y volver a solicitar el bloqueo continuamente hasta que funcione
  • B. Mantener el diálogo abierto indefinidamente porque la finalización narrativa depende del bloqueo
  • C. Volver a un modo seguro sin bloqueo, mantener desactivado el control de cámara, mostrar un control explícito para continuar y solicitar el bloqueo desde esa nueva acción mientras se observan los eventos del ciclo de vida
  • D. Revertir la consecuencia narrativa confirmada porque falló la restauración del bloqueo
Mostrar respuesta y explicación

Respuesta: Volver a un modo seguro sin bloqueo, mantener desactivado el control de cámara, mostrar un control explícito para continuar y solicitar el bloqueo desde esa nueva acción mientras se observan los eventos del ciclo de vida

Por qué: La transición segura no da por supuesta la captura, no deja activo el control de cámara mientras el puntero está libre y obtiene una nueva acción del usuario para repetir la solicitud. El fallo del bloqueo permanece separado del resultado narrativo confirmado.

Apoyar