tutoriales.com

Unreal Engine: Creación de un Sistema de Diálogos Ramificados con Data Tables y Blueprint

Este tutorial te guiará en la creación de un robusto sistema de diálogos ramificados para tus juegos en Unreal Engine 5. Utilizaremos Data Tables para gestionar el contenido de los diálogos y Blueprints para la lógica de visualización e interacción. Prepárate para dar vida a tus personajes y enriquecer la narrativa de tu juego.

Intermedio15 min de lectura15 views
Reportar error

🚀 Introducción al Sistema de Diálogos Ramificados en Unreal Engine

Los sistemas de diálogo son el corazón narrativo de muchos videojuegos, permitiendo a los jugadores interactuar con personajes, tomar decisiones que afectan la historia y sumergirse en el mundo del juego. Un sistema de diálogos ramificados va un paso más allá, ofreciendo múltiples caminos y consecuencias basadas en las elecciones del jugador, lo que aumenta la rejugabilidad y la profundidad narrativa.

En este tutorial, construiremos un sistema de diálogo flexible y escalable en Unreal Engine 5 utilizando dos herramientas poderosas: Data Tables para la organización de los datos de diálogo y Blueprints para la lógica visual y la interfaz de usuario. Al final, tendrás un sistema funcional que podrás adaptar y expandir a tus propios proyectos.

🔥 **Importante:** Este tutorial asume un conocimiento básico de Unreal Engine 5 y Blueprints. Si eres completamente nuevo, te recomendamos familiarizarte con la interfaz y los conceptos básicos de Blueprint antes de continuar.

¿Por qué Data Tables y Blueprints?

  • Data Tables: Son ideales para almacenar grandes cantidades de datos estructurados de manera eficiente. Nos permiten separar el contenido del diálogo (texto, personaje, opciones, etc.) de la lógica del juego, facilitando la edición por parte de escritores o diseñadores sin necesidad de tocar código.
  • Blueprints: Proporcionan un entorno visual para crear la lógica del juego, lo que es perfecto para manejar la secuencia de diálogos, mostrar opciones al jugador, y procesar sus elecciones. Es una solución rápida y potente para la mayoría de las necesidades de juego.

🛠️ Configuración Inicial del Proyecto

Antes de sumergirnos en la creación del sistema, necesitamos configurar nuestro proyecto.

1. Creación de una Estructura de Datos para el Diálogo (Struct)

Primero, necesitamos definir cómo se verá una línea de diálogo en nuestro juego. Para esto, crearemos una Structure en Blueprint.

  1. En el Content Browser, haz clic derecho y selecciona Blueprints > Structure.
  2. Nómbrala ST_DialogueNode.
  3. Abre ST_DialogueNode y añade las siguientes variables:
    • NodeID (Type: Name): Un identificador único para cada nodo de diálogo. Será nuestra clave principal.
    • CharacterName (Type: Text): El nombre del personaje que está hablando.
    • DialogueText (Type: Text): El texto principal de la línea de diálogo.
    • Choices (Type: Array of ST_DialogueChoice): Un array que contendrá las opciones que el jugador puede seleccionar. (Necesitaremos crear ST_DialogueChoice primero).
    • DefaultNextNodeID (Type: Name): El NodeID del siguiente diálogo si no hay opciones o si no se elige ninguna.
    • IsEndNode (Type: Boolean): Indica si este nodo finaliza la secuencia de diálogo.

Ahora, creemos la estructura para las opciones de diálogo.

  1. En el Content Browser, haz clic derecho y selecciona Blueprints > Structure.
  2. Nómbrala ST_DialogueChoice.
  3. Abre ST_DialogueChoice y añade las siguientes variables:
    • ChoiceText (Type: Text): El texto que se mostrará al jugador para esta opción.
    • NextNodeID (Type: Name): El NodeID del diálogo al que se pasa si el jugador elige esta opción.
💡 Consejo: Usar `Name` para IDs es eficiente para búsquedas rápidas en Data Tables.
ST_DialogueNode NodeID: int CharacterName: string DialogueText: string Choices: array[] DefaultNextNodeID: int IsEndNode: bool ST_DialogueChoice ChoiceText: string NextNodeID: int Contiene

2. Creación de la Tabla de Datos (Data Table)

Con nuestras estructuras definidas, podemos crear la Data Table que almacenará todos nuestros diálogos.

  1. En el Content Browser, haz clic derecho y selecciona Miscellaneous > Data Table.
  2. Se te pedirá que elijas una Row Structure. Selecciona ST_DialogueNode.
  3. Nómbrala DT_Dialogue.
  4. Abre DT_Dialogue. Aquí es donde introduciremos nuestras líneas de diálogo. Por ahora, deja un par de filas de ejemplo para empezar.
    • Haz clic en Add para añadir una nueva fila.

    • Row Name: Intro1

    • CharacterName: Narrador

    • DialogueText: Te encuentras en una encrucijada. ¿Qué camino tomas?

    • Choices: (Añade dos elementos aquí)

      • Choice 1: ChoiceText: Ir a la izquierda, NextNodeID: PathLeft1
      • Choice 2: ChoiceText: Ir a la derecha, NextNodeID: PathRight1
    • DefaultNextNodeID: (Déjalo vacío por ahora)

    • IsEndNode: False

    • Añade otra fila:

      • Row Name: PathLeft1
      • CharacterName: Guardia
      • DialogueText: ¡Alto! ¿Quién eres?
      • Choices: (Añade un elemento)
        • Choice 1: ChoiceText: Soy un aventurero., NextNodeID: GuardTalk1
      • DefaultNextNodeID: (Déjalo vacío)
      • IsEndNode: False
    • Añade una tercera fila:

      • Row Name: PathRight1
      • CharacterName: Mercader
      • DialogueText: ¡Bienvenido, viajero! ¿Buscas algo en particular?
      • Choices: (Añade un elemento)
        • Choice 1: ChoiceText: Solo miro, gracias., NextNodeID: EndDialogue
      • DefaultNextNodeID: (Déjalo vacío)
      • IsEndNode: False
    • Añade una cuarta fila:

      • Row Name: GuardTalk1
      • CharacterName: Guardia
      • DialogueText: Pasa, pero ten cuidado.
      • Choices: (vacío)
      • DefaultNextNodeID: EndDialogue
      • IsEndNode: False
    • Añade la fila final:

      • Row Name: EndDialogue
      • CharacterName: (Silencio)
      • DialogueText: Fin del diálogo.
      • Choices: (vacío)
      • DefaultNextNodeID: (vacío)
      • IsEndNode: True

Guardar DT_Dialogue.


🎨 Creación de la Interfaz de Usuario (UMG)

Necesitamos una interfaz para mostrar el diálogo y las opciones al jugador.

1. Widget de Línea de Diálogo Individual (para opciones)

Este widget representará cada opción de diálogo que el jugador puede seleccionar.

  1. En el Content Browser, haz clic derecho y selecciona User Interface > Widget Blueprint > UserWidget.
  2. Nómbrala WB_DialogueChoiceButton.
  3. Ábrela y arrastra un Button desde la paleta al Canvas Panel.
  4. Dentro del Button, arrastra un Text Block.
  5. Renombra el Text Block a ChoiceText_TextBlock y marca Is Variable en los detalles.
  6. Selecciona el Button y en Details > Events, haz clic en + junto a OnClicked.

En el Graph de WB_DialogueChoiceButton:

  • Crea una variable NextNodeID (Type: Name) y marca Expose on Spawn.
  • Crea un Event Dispatcher llamado OnChoiceSelected con una entrada NextNodeID (Type: Name).

En el evento OnClicked del botón:

  • Call el Event Dispatcher OnChoiceSelected, pasando la variable NextNodeID.
💡 Consejo: Asegúrate de que los anclajes del botón y el texto estén configurados correctamente para que se adapten a diferentes resoluciones.

2. Widget Principal del Sistema de Diálogo

Este será el widget principal que contendrá el texto del diálogo, el nombre del personaje y los botones de opción.

  1. En el Content Browser, haz clic derecho y selecciona User Interface > Widget Blueprint > UserWidget.
  2. Nómbrala WB_DialogueSystem.
  3. Ábrela y en el Designer, añade los siguientes elementos (puedes usar un Vertical Box o Border como contenedores):
    • Text Block para el nombre del personaje. Renómbralo a CharacterName_TextBlock y marca Is Variable.
    • Text Block para el texto del diálogo. Renómbralo a DialogueText_TextBlock y marca Is Variable.
    • Vertical Box para contener los botones de opción. Renómbralo a ChoicesVerticalBox y marca Is Variable.
    • Un Button (opcional) para avanzar el diálogo si no hay opciones. Renómbralo a ContinueButton y marca Is Variable.
WB_DialogueSystem CharacterName_TextBlock DialogueText_TextBlock "Este es el contenido del diálogo principal..." ChoicesVerticalBox WB_DialogueChoiceButton 1 WB_DialogueChoiceButton 2 WB_DialogueChoiceButton 3 ContinueButton

En el Graph de WB_DialogueSystem:

  • Crea una función ShowDialogueNode que tome un ST_DialogueNode como entrada.

    • Esta función actualizará CharacterName_TextBlock y DialogueText_TextBlock.
    • Borrará todos los hijos de ChoicesVerticalBox.
    • Para cada Choice en el array Choices de ST_DialogueNode:
      • Create Widget de WB_DialogueChoiceButton.
      • Set el NextNodeID del botón recién creado.
      • Set Text del ChoiceText_TextBlock del botón.
      • Add Child al ChoicesVerticalBox.
      • Bind Event to OnChoiceSelected del botón para llamar a un evento personalizado, por ejemplo, OnChoiceMade.
    • Si no hay opciones (Choices está vacío) o si IsEndNode es False:
      • Mostrar ContinueButton.
      • Set Visibility del ChoicesVerticalBox a Hidden.
    • Si hay opciones:
      • Ocultar ContinueButton.
      • Set Visibility del ChoicesVerticalBox a Visible.
  • Crea un Event Dispatcher llamado OnDialogueNodeRequested con una entrada NextNodeID (Type: Name).

  • Crea un Custom Event OnChoiceMade que reciba un NextNodeID (Type: Name).

    • Call el Event Dispatcher OnDialogueNodeRequested con el NextNodeID recibido.
  • En el evento OnClicked de ContinueButton:

    • Call el Event Dispatcher OnDialogueNodeRequested con el DefaultNextNodeID del nodo actual (que deberemos pasar como variable al widget o almacenar).
📌 Nota: Para el `ContinueButton`, necesitaremos una forma de acceder al `DefaultNextNodeID` del nodo actual. Puedes almacenar el `ST_DialogueNode` actual como una variable en `WB_DialogueSystem` al llamar a `ShowDialogueNode`.

🧠 Lógica Principal del Diálogo (Blueprint del Juego)

Necesitamos un lugar centralizado para gestionar el flujo del diálogo. Un Player Controller, Game Mode o un Actor Component son buenas opciones. Para este tutorial, usaremos el Player Controller por simplicidad.

1. Blueprint del Player Controller (o Actor Component)

  1. Abre tu Player Controller (o crea un nuevo Blueprint Actor Component llamado BP_DialogueManager).
  2. Añade una variable CurrentDialogueNodeID (Type: Name). Inicialízala a un valor None o el NodeID inicial de tu diálogo (Intro1).
  3. Añade una variable DialogueWidget (Type: WB_DialogueSystem Object Reference).

2. Funciones de Carga y Visualización del Diálogo

En tu Player Controller (o BP_DialogueManager):

  • Crea una función StartDialogue que tome un StartingNodeID (Type: Name) como entrada.

    • Set CurrentDialogueNodeID al StartingNodeID.
    • Create Widget de WB_DialogueSystem y Add to Viewport.
    • Set la variable DialogueWidget.
    • Bind Event to OnDialogueNodeRequested de DialogueWidget para llamar a un evento personalizado HandleDialogueNodeRequest.
    • Llama a la función DisplayCurrentDialogueNode.
  • Crea una función DisplayCurrentDialogueNode.

    • Get Data Table Row de DT_Dialogue usando CurrentDialogueNodeID como Row Name.
    • Si la fila es válida (Has Valid output):
      • Llama a la función ShowDialogueNode en DialogueWidget, pasando la estructura de la fila.
      • Si IsEndNode de la fila es True:
        • Delay por unos segundos.
        • Remove from Parent de DialogueWidget.
        • Set DialogueWidget a None.
        • Set CurrentDialogueNodeID a None.
        • (Opcional) Unbind el evento OnDialogueNodeRequested.
    • Si la fila no es válida:
      • Print String con un mensaje de error.
      • Terminar diálogo (similar a IsEndNode).
  • Crea un Custom Event HandleDialogueNodeRequest que reciba un NextNodeID (Type: Name).

    • Set CurrentDialogueNodeID al NextNodeID recibido.
    • Llama a la función DisplayCurrentDialogueNode.
Evento 'StartDialogue' Create WB_DialogueSystem Add to Viewport Bind OnDialogueNodeRequested DisplayCurrentDialogueNode DT_Dialogue (Fuente de Datos) WB_DialogueSystem.Show ¿Es nodo final? Remove from Parent OnDialogueNodeRequested (Desde Widget) HandleDialogueNodeRequest Actualiza ID Nodo DIAGRAMA DE LÓGICA DE DIÁLOGO

3. Activación del Diálogo

Para probar nuestro sistema, podemos activarlo desde un Actor en el nivel.

  1. Crea un nuevo Blueprint Actor llamado BP_DialogueTrigger.
  2. Añade un Box Collision a BP_DialogueTrigger.
  3. En el Event Graph de BP_DialogueTrigger:
    • En el evento OnComponentBeginOverlap del Box Collision:
      • Cast To tu Player Character.
      • Si el Cast es exitoso:
        • Get Player Controller.
        • Cast To tu Player Controller (el que contiene la lógica de diálogo).
        • Si el Cast es exitoso:
          • Llama a la función StartDialogue en el Player Controller, pasando Intro1 como StartingNodeID.
          • (Opcional) Destroy Actor para que el diálogo no se active múltiples veces.

Coloca una instancia de BP_DialogueTrigger en tu nivel y prueba a que tu personaje colisione con él.

⚠️ Advertencia: Asegúrate de que las `Collision Presets` del `Box Collision` estén configuradas para detectar el `Overlap` con tu personaje.

✨ Mejoras Adicionales y Personalización

Este es un sistema básico pero robusto. Aquí hay ideas para expandirlo:

1. Efectos de Sonido y Animaciones

  • Sonido: Añade una variable SoundCue a ST_DialogueNode y reprodúcelo cuando se muestre el nodo.
  • Animaciones: Podrías incluir un Animation o Montage a reproducir para el personaje hablante, o animar el widget de diálogo para que aparezca/desaparezca suavemente.

2. Lógica Condicional en las Opciones

  • Añade variables a ST_DialogueChoice para almacenar condiciones (ej. RequiredItem, RequiredStatValue).
  • En WB_DialogueSystem, antes de añadir un botón de opción, verifica si el jugador cumple las condiciones. Si no, deshabilita el botón o lo oculta.

3. Eventos al Finalizar un Diálogo

  • Añade un Event Dispatcher en el Player Controller (o BP_DialogueManager) llamado OnDialogueFinished.
  • Call este Dispatcher cuando el diálogo llegue a un IsEndNode.
  • Otros sistemas (misiones, IA) pueden Bind a este evento para reaccionar cuando un diálogo termina.

4. Nombres y Avatares de Personajes Dinámicos

  • Puedes tener una DataTable separada para los datos de los personajes (nombre completo, textura del avatar, color de texto, etc.) y usar el CharacterName de ST_DialogueNode como Row Name para obtener esos datos.

5. Diálogos Secuenciales sin Elecciones

  • Si un nodo no tiene opciones, automáticamente debería avanzar al DefaultNextNodeID (que ya hemos implementado con el ContinueButton). Si DefaultNextNodeID también está vacío, el diálogo termina o espera una interacción manual (como en el IsEndNode).

📝 Resumen del Flujo de Trabajo

Paso 1: Estructuras de Datos Define `ST_DialogueNode` y `ST_DialogueChoice` para estructurar tus datos de diálogo.
Paso 2: Data Table Crea `DT_Dialogue` usando `ST_DialogueNode` como plantilla de fila y rellénala con tus diálogos.
Paso 3: Widgets de UI Diseña `WB_DialogueChoiceButton` (para opciones) y `WB_DialogueSystem` (la interfaz principal del diálogo).
Paso 4: Lógica del Juego Implementa la gestión del flujo del diálogo en tu `Player Controller` o un `Actor Component`, incluyendo funciones para cargar y mostrar nodos.
Paso 5: Activación Crea un `Actor` de activación para iniciar el diálogo en tu nivel.
💡 Consejo: Mantén tus estructuras y Data Tables bien organizadas. Una buena planificación inicial te ahorrará mucho tiempo a largo plazo.

Conclusión 🎉

Has aprendido a construir un sistema de diálogos ramificados funcional y extensible en Unreal Engine 5 utilizando Data Tables y Blueprints. Este enfoque separa el contenido de la lógica, haciendo que el sistema sea fácil de mantener, escalar y personalizar.

La versatilidad de las Data Tables, combinada con la potencia visual de Blueprints, te permite crear narrativas ricas y envolventes para tus juegos. Experimenta con las mejoras sugeridas y adapta este sistema a las necesidades específicas de tu proyecto.

¡Ahora tienes las herramientas para dar voz a tus personajes y permitir que los jugadores tomen decisiones significativas en tu mundo de juego!

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!