como hago un sistema de dialogos/mensajes para mi ...
बनाया गया: 25 जून 2025
बनाया गया: 25 जून 2025
como hago un sistema de dialogos/mensajes para mi juego de pseudo-chat en unity? lo quiero hacer con excel (nada de jsons y esas madres). La idea es que los personajes se comuniquen a traves de "mensajes" de texto y el jugador tenga opciones para responder y ramificar la historia.
Aquí tienes una manera práctica (y sin JSON 😉) de montar un sistema de “pseudo-chat” ramificado en Unity usando un archivo Excel como única fuente de datos.
Crea un libro con una sola hoja llamada, por ejemplo, Dialogos (o varias si te gusta tener todo ordenado). Usa una fila por mensaje:
ID | Remitente | Texto | Opción 1 Texto | Opción 1 SiguienteID | Opción 2 Texto | Opción 2 SiguienteID | Condición | Efecto |
---|---|---|---|---|---|---|---|---|
0 | Ana | “¡Hola! ¿Cómo estás?” | “Bien” | 1 | “Mal” | 2 | ||
1 | Jugador | “Genial.” | “¿Qué planes?” | 3 | score+1 | |||
2 | Jugador | “Pues regular…” | “Ánimo” | 3 | score-1 | |||
3 | Ana | “Vamos al cine.” | “Sí” | 4 | “Otro día” | 5 | score>=0 |
Guarda el libro como .xlsx en la carpeta StreamingAssets/ (Unity la copia tal cual dentro del build, así que no hace falta rehacer la hoja en cada iteración).
Packages/manifest.json
:jsonc"com.system.exceldatareader": "https://github.com/ExcelDataReader/ExcelDataReader.Unity.git"
System.Text.Encoding.CodePages
en Player Settings → Other Settings → Api Compatibility Level >= .NET 4.x y añade:
csharpSystem.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
csharpusing ExcelDataReader; using System.Data; using UnityEngine; using System.IO; using System.Linq; public class DialogueLoader { public static Dictionary<int, DialogueNode> LoadSheet(string fileName) { string path = Path.Combine(Application.streamingAssetsPath, fileName); using var stream = File.Open(path, FileMode.Open, FileAccess.Read); using var reader = ExcelReaderFactory.CreateReader(stream); var result = reader.AsDataSet().Tables[0]; // primera hoja return Enumerable.Range(1, result.Rows.Count - 1) // salta cabecera .Select(r => ParseRow(result.Rows[r])) .ToDictionary(n => n.ID, n => n); } static DialogueNode ParseRow(DataRow row) { int GetInt(string col) => int.TryParse(row[col]?.ToString(), out var v) ? v : -1; string GetStr(string col) => row[col]?.ToString() ?? ""; return new DialogueNode { ID = GetInt("ID"), speaker = GetStr("Remitente"), text = GetStr("Texto"), options = new[] { new DialogueOption{ text = GetStr("Opción 1 Texto"), nextID = GetInt("Opción 1 SiguienteID")}, new DialogueOption{ text = GetStr("Opción 2 Texto"), nextID = GetInt("Opción 2 SiguienteID")} }.Where(o => !string.IsNullOrWhiteSpace(o.text)).ToList(), condition = GetStr("Condición"), effect = GetStr("Efecto") }; } } public class DialogueNode { public int ID; public string speaker; public string text; public List<DialogueOption> options; public string condition; public string effect; } public class DialogueOption { public string text; public int nextID; }
csharppublic class DialogueManager : MonoBehaviour { public ChatUI ui; // tu script de interfaz (TextMeshPro, botones, etc.) Dictionary<int, DialogueNode> nodes; int currentID; Dictionary<string,int> vars = new(); // score, karma, etc. void Start() { nodes = DialogueLoader.LoadSheet("Dialogos.xlsx"); StartConversation(0); } void StartConversation(int id) => ShowNode(id); void ShowNode(int id) { if (!nodes.TryGetValue(id, out var node)) return; if (!IsAllowed(node.condition)) { ShowNode(id+1); return; } // fallback ui.AddBubble(node.speaker, node.text); ui.ClearChoices(); foreach (var opt in node.options) ui.AddChoice(opt.text, () => OnChoose(opt)); ApplyEffect(node.effect); currentID = id; } void OnChoose(DialogueOption opt) => ShowNode(opt.nextID); bool IsAllowed(string cond) { if (string.IsNullOrEmpty(cond)) return true; // mini parser super simple: “score>=0” var parts = System.Text.RegularExpressions.Regex.Match(cond, @"(\w+)\s*([><=]+)\s*(-?\d+)"); if (!parts.Success) return true; int value = vars.GetValueOrDefault(parts.Groups[1].Value, 0); int rhs = int.Parse(parts.Groups[3].Value); return parts.Groups[2].Value switch { ">" => value > rhs, ">=" => value >= rhs, "<" => value < rhs, "<=" => value <= rhs, "=" => value == rhs, _ => true }; } void ApplyEffect(string eff) { if (string.IsNullOrEmpty(eff)) return; // ejemplo “score+1” var m = System.Text.RegularExpressions.Regex.Match(eff, @"(\w+)([+\-]\d+)"); if (!m.Success) return; string key = m.Groups[1].Value; int delta = int.Parse(m.Groups[2].Value); vars[key] = vars.GetValueOrDefault(key,0) + delta; } }
El UI Chat puede ser tan simple como:
VerticalLayoutGroup
para las “burbujas” (TextMeshProUGUI
).speaker
).Truco | Ventaja |
---|---|
Nombra las columnas con espacios y acentos si quieres; el loader las busca por cabecera | Más legible para guionistas; no necesitan saber de código |
Comentarios: añade una columna “Notas” que ignores al leer | Feedback de QA sin romper nada |
Variables globales: suma columnas de booleanos (flag_habla_ana ) si prefieres checks directos | Menos regex |
Pruebas rápidas: guarda el .xlsx como CSV en un macro y recarga en hot-reload | Nada de volver a compilar |
Google Sheets → Excel: deja que el guionista trabaje online; bajas el .xlsx cuando quieras | Flujo colaborativo |
StreamingAssets/
para que lleguen intactos a Android/iOS.¡Y listo! Con esto tienes un “motorcito” de chat ramificado 100 % Excel-friendly, fácil de ampliar y sin tocar JSON ni editores externos. Cuando quieras meter más profundidad (timers, mensajes asincrónicos, multimedia) solo extiende la hoja con nuevas columnas y amplía el DialogueManager
. ¡Éxitos con tu juego!