Jump to content
Unity Insider Forum

Scriptable Objects fuer Dialog System


Strooja0108

Recommended Posts

Hi Leute,

 

ich bin mal wieder hier mit einer weiteren Frage. Ich wuerde gern ein einfaches Dialogsystem bauen,welches unterschiedliche Dialoge beinhaltet.

 

Dafuer habe ich mir ueberlegt. Ich habe ein Script ueber dem ich das Dialogscript starte.In diesem Startscript steht einfach etwas wie  DialogStart(scriptableobject1);    oder  DialogStart(scriptableobject2);     Je nach Situation halt ein andere Dialog.  In dem ScriptableObject moechte ich zum einen den Text der gesprochen wird festhalten und zum anderen weitere Informationen wie zum Beispiel wer den Text gerade spricht und ein passendes Bild zur Person.

In dem aufgerufenden Script mit der methode DialogStart() moechte ich dann die Daten weiterverarbeiten. Bis jetzt habe ich immer nur gesehen das ScriptableObjects im Inspector zugeordnet wurden. Ist es auch moeglich ein ScriptableObject als Ubergabeparameter zu verwenden ? Und wenn ja wie geht das und wie greife ich dann auf die einzelnen Parameter des scriptableObjects  in einer methode drauf zu?

 

 

Es waere klasse wenn da jemand einen Ratschlag hat

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hi

Ich kenne mich mit ScriptableObjects nicht aus, aber ich habe ein einfaches Dialog System entwickelt. Dazu habe ich einfach ein LUA File (XML würde auch gehen) verwendet.

Darin habe ich verschiedene "Stages" definiert. Jede stage enthält entweder Informationen, was der Npc sagt oder Auswahlmöglichkeiten, die der Spieler Antworten kann. Die Variable "nextStage" gibt an, welche Stage als nächstes kommt (wieder NPC sagt was oder Spieler antwortet was). Dazu habe ich noch eine "requirements" Variable bei den Antwortmöglichkeiten gemacht. Die Antwort erscheint also nur, wenn der Spieler die "requirements" erfüllt... zum Beispiel ein bestimmter Gegenstand im Inventar hat.

Ist leider ziemlich kompliziert die Datei zu schreiben. Wenn du ein System entwickeln willst, um die Dialoge auf komfortable Art zu designen, wäre ich sehr interessiert 🙂

So sieht so eine Datei aus:

defineDialog {
	id = "sailorfrank",
	name = "Frank",
	startStageId = "s0",
	autoStartRadius = 0,
	stages = {
		s0 = {
			say = {
				speaker = "npc",
				text = "Warum nur immer ich?",
				audio = "",
				actions = nil,
				nextStage = "s1"
			},
			options = nil
		},
		s1 = {
			say = nil,
			options = {
				option1 = {
					text = "Was ist los?",
					requirements = nil,
					actions = nil,
					nextStage = "s2"
				},
				option2 = {
					text = "Ich muss weiter.",
					requirements = nil,
					actions = nil,
					nextStage = ""
				}
			}
		},
		s2 = {
			say = {
				speaker = "npc",
				text = "Jemand hat meine Schuhe geklaut! Gestern hatte ich sie noch.",
				audio = "",
				actions = nil,
				nextStage = "s3"
			},
			options = nil
		},
		s3 = {
			say = {
				speaker = "npc",
				text = "Es sind ganz normale Schiffsstiefel.",
				audio = "",
				actions = nil,
				nextStage = "s4"
				
			},
			options = nil
		},
		s4 = {
			say = nil,
			options = {
				option1 = {
					text = "Wenn ich sie sehe, werde ich bescheid geben.",
					requirements = nil,
					actions = {
						SetStage = "s6"
					},
					nextStage = "s5"
				},
				option2 = {
					text = "Viel Glück!",
					requirements = nil,
					actions = nil,
					nextStage = ""
				}
			}
		},
		s5 = {
			say = {
				speaker = "npc",
				text = "Das wäre super!",
				audio = "",
				actions = nil,
				nextStage = ""
				
			},
			options = nil
		},
		s6 = {
			say = nil,
			options = {
				option1 = {
					text = "Wegen deinen Stiefeln...",
					requirements = nil,
					actions = nil,
					nextStage = "s7"
				},
				option2 = {
					text = "Ich gehe jetzt.",
					requirements = nil,
					actions = nil,
					nextStage = ""
				}
			}
		},
		s7 = {
			say = {
				speaker = "npc",
				text = "Ja?",
				audio = "",
				actions = nil,
				nextStage = "s8"
				
			},
			options = nil
		},
		s8 = {
			say = nil,
			options = {
				option1 = {
					text = "Ich habe sie gefunden. Hier sind sie.",
					requirements = {
						InventoryContainsItem = "BOOTS=1"
					},
					actions = nil,
					nextStage = "s10"
				},
				option2 = {
					text = "Noch nichts neues.",
					requirements = {
						InventoryNotContainsItem = "BOOTS=1"
					},
					actions = nil,
					nextStage = "s9"
				}
			}
		},
		s9 = {
			say = {
				speaker = "npc",
				text = "Dann such weiter, ok?",
				audio = "",
				actions = nil,
				nextStage = "s6"
				
			},
			options = nil
		},
		s10 = {
			say = {
				speaker = "npc",
				text = "Das war echt nett von dir! Vielen Dank!",
				audio = "",
				actions = {
						SetStage = "s11"
					},
				nextStage = ""
				
			},
			options = nil
		},
		s11 = {
			say = {
				speaker = "npc",
				text = "Hey! Danke nochmals, dass du meine Stiefel gefunden hast!",
				audio = "",
				actions = nil,
				nextStage = ""
				
			},
			options = nil
		}
	}
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hey vielen Dank für deine Antwort.Das ist ist eine interessante Lösung aber ich würde es gerne in einer art array oder halt scriptable objekt lösen damit ich alles schön im Überblick habe. Ich könnte natürlich anstatt scriptable objects auch einfach gameobjects nehmen .Allerdings brauche ich ja nur verschiedene Objekte um Daten zu speichern deshalb halte ich GameObject für überflüssig.Würde halt gerne jede Conversation in ein Object speichern.

 

Hat vielleicht sonst noch jemand einen Voschlag?

Link zu diesem Kommentar
Auf anderen Seiten teilen

ScriptableObjects können dafür schon ganz gut sein. Ich würde empfehlen, bei der Idee erstmal zu bleiben.

vor 21 Stunden schrieb Strooja0108:

Ist es auch moeglich ein ScriptableObject als Ubergabeparameter zu verwenden ?

Klar, so wie alles andere auch:

public class Dialogue : ScriptableObject
{
  // string nur als Beispiel, ist natürlich keine gute Idee
  public string[] lines;
public void StartDialogue(Dialogue dialogue)

 

vor 21 Stunden schrieb Strooja0108:

Und wenn ja wie geht das und wie greife ich dann auf die einzelnen Parameter des scriptableObjects  in einer methode drauf zu?

Auch hier ist die Antwort "wir bei allem anderen auch":

foreach (var line in dialogue.lines)
{
  textComponent.text = line;
  // Nur ein Platzhalter
  WaitForClick();
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hey danke für die Hilfe.Habe es soweit hinbekommen. Jetzt würde ich allerdings gerne je nach Event ein bestimmten Dialog übergeben.Zurzeit mache ich das so zum Beispiel.

 

DataDialogShow.StartConversation(DialogList[0]);

 

Wobei ich so natürlich im Inspektor jedes SciptableObject in das array schieben muss und es über Nummern aufrufe.

Ich würde aber gerne das ScriptableObjekt beim Namen aufrufen und ohne das ich es in irgendein Array speichern muss.Ist das irgendwie möglich?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Warum sind überhaupt alle Dialoge in einer global umfassenden Liste? Der Witz an ScriptableObjects ist, dass du eben nicht über irgendeinen zusätzlichen Schlüssel (wie int oder string) darauf zugreifst, sondern direkt über eine Referenz, die Unity dir bereitstellt.

Statt also

DataDialogShow.StartConversation(DialogList[0]); 

machst du

public Dialogue dialogue;

und

DataDialogShow.StartConversation(dialogue); 

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

mh ok und wie weiss, in deinem Beispiel, unity dann das ich Dialog5 haben will und nicht Dialog1? Ohne irgendwas im Inspector zu machen.Ich hab halt nicht nur einen Dialog sondern 30 Stueck die ich ueber ein Script je nach Situation aufrufen moechte.In der DialogList habe ich zurzeit alle 30 Dialoge die es gibt, damit ich darauf Zugriff habe. Ich wuerde liebend gern auf diese globale Liste verzichten,deswegen fragte ich wie der command dafuer ist ein sciptableobject(das ja keinem GameObject zugewiesen ist) aus den Asset heraus aufzurufen und zu uebergeben.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Gerade eben schrieb Strooja0108:

Ohne irgendwas im Inspector zu machen

Das ist halt so die Annahme, mit der das schwierig wird. Dass man das im Inspektor macht, ist genau der Witz.

vor 1 Minute schrieb Strooja0108:

Ich hab halt nicht nur einen Dialog sondern 30 Stueck die ich ueber ein Script je nach Situation aufrufen moechte

Dann musst du dir die Frage stellen: Worin unterscheiden sich die Situationen, und wie ist das implementiert? An irgendeiner Stelle bei deinem aktuellen Entwurf schreibst du ja Code, bei dem dann entschieden wird, ob du eher Dialog 8 oder Dialog 9 starten willst. Das ist der Punkt, wo du ansetzen musst. Du musst das richtige ScriptableObject von Inspektor bis hinzu diesem Punkt leiten.

Damit du dir da etwas drunter vorstellen kannst: Eine Möglichkeit, die dir zur Verfügung steht, ist das Verlinken von Dialogen in andere Dialoge.

public class Dialogue : ScriptableObject
{
  public string[] lines;
  
  public Dialogue nextDialogueYes;
  public Dialogue nextDialogueNo;
}

Hier kannst du die Folgedialoge für die Fälle, dass der Spieler mit "Ja" oder "Nein" antwortet reinziehen. Deine Komponente kann dann die entsprechenden Knöpfe anbieten und den nächsten Dialog starten.

DataDialogShow.StartConversation(currentDialogue.nextDialogueIfYes);

Das kann man natürlich beliebig verschönern, und zum Beispiel stattdessen eine Liste an Antworten definieren:

public class Dialogue : ScriptableObject
{
  [System.Serializable]
  public struct Response
  {
    public string responseText;
    public Dialogie nextDialogue;
  }
  
  public string[] lines;
  public Response[] responses;
}

Das struct "Response" kann dann auch wieder beliebig erweitert werden, zum Beispiel mit Bedingungen zur Verfügbarkeit der Antwort (Spieler muss mind. X Punkt in Speech haben oder etwas wissen oder so) oder dass etwas passiert, wenn man die Option wählt.

Link zu diesem Kommentar
Auf anderen Seiten teilen

ah ok ich denke wir reden von zwei  unterschiedlichen Sachen. Ich mache das exakt so wie du gesagt hast.

mit der Zeile :

DialogShow.StartConversation(DialogList[0]);

 

Rufe ich das script auf welches mein sciptable Object dann ausgeben soll. Mein scriptable Object sieht ziemlich aehnlich aus wie dein Beispiel nur mit ein paar anderen variablen noch.Aber ich speicher auch den Text einfach in nem string array.So jetzt habe ich in meinem scriptable Object meine ganze conversation stehen. Aber wie uebergebe ich nun diese Conversation zu dem script "DialogShow" welches dafuer zustaendig ist das scirptable Object auszulesen und zu verarbeiten.

Du schreibst ja selbst " Du musst das richtige ScriptableObject von Inspektor bis hinzu diesem Punkt leiten. " GENAU das ist es .Ich moechte das aber nicht vom Inspector dahin leiten sondern aus meinen Assets heraus.

So das ,vereinfacht dargestellt, mein Eventscript nachher  so schoen uebersichtlich aussieht.

if(time==12)

DialogShow.StartConversation(DialogMittagessen);   (das in Klammern muss halt ein Verweis auf das scriptable Object in meinen assets sein)

if(Geld==0)

DialogShow.StartConversation(DialogkeinGeldmehr);

 

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 7 Stunden schrieb Strooja0108:

okay also geht es nicht das ich kein Feld erstelle sondern einfach auf das Asset zugreife ohne irgendwas zu erstellen oder im Inspector zuzuweisen,richtig?

Das geht schon, aber es geht auch, ne Suppe mit der Gabel zu essen. Wenn du ScriptableObjects nutzt, dann solltest du sie auch richtig nutzen. Sie irgendwie über einen string zu identifizieren und rauszusuchen ist halt völlig am Sinn der Dinger vorbei.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hab kurz das Video überflogen

gZocpgK.png

Das hier gefällt mir persönlich gar nicht. Für mich ist das ein Redundant. Es geht wohl um zwei Charaktere die mit einander reden, aber warum muss ich jedes mal nochmal Charakter dahin ziehen. Vllt zieht man sogar mal falschen Charakter dahin ^^. Wäre leichter eigentlich vllt ein bool rein zu machen oder ein Dropdown Auswahl, ob der rechte oder linke redet und dann je nach dem Speaker variable verwenden.

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 2 Stunden schrieb Strooja0108:

@Thariel  Ich bin auf youtube fündig geworden . Das Tutorial erklärt meiner Meinung nach eine schön saubere Variante um Dialoge zu ereugen und zu verwalten.

Nunja, im Endeffekt macht sein script nichts anderes als einfach linear Text auszugeben. Da kann ich auch einfach ein Textfile erstellen und abwechselnd in einem Fenster anzeigen.

Mein System kann verschiedene Positionen im Gespräch zwischenspeichern, Optionen nach Bedingungen anzeigen und ein völlig freier Gesprächsverlauf ausgeben. Ist nur mühsam das File zu schreiben. Wenn du mal dem Gesprächsverlauf folgst, dann siehst du, dass es ein ganzer Dialog mit einer Quest ist, die man abschliessen kann. Genau so könnte es auch in einem RPG wie Gothic ablaufen.

In den nächsten Tagen wird das Tema für mich sehr aktuell, sobald ich die NPC AI fertig habe. Dann werde ich schauen, wie ich es diesmal angehen werde. Die Herausforderung ist vor allem: Die Gespräche laufen nicht linear ab, sondern in Schlaufen mit verschiedenen "Levels". Das geht fast nur mit einem Node-Basiertem System. Aber ich brauche die Dialoge eigentlich nur für die Intro Sequenz, deshalb werde ich da was einfaches bauen.

Es gibt auch Dialog Editore. Vielleicht findest du ja einen guten und man könnte das exportierte XML File einfach in Unity interpretieren :D

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wie du schon schreibst ist das mit den XML Files etwas muehsamer und meiner Meinung nach auch unuebersichtlicher aber ich glaub jeder sollte es so machen wie es ihm passt und wie er es braucht. Wollte das nur mit dir teilen weil du scheinbar auch gerade im Thema bist. Ich finde es sehr uebersichtlich mit den scriptableObjects und habe es auch erweitert das ich angeben kann wie schnell der Text dargestellt wird, ob in einer Sprechblase oder einem Window und so weiter.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Vorteile bei xml oder ähnlichen (z.b. json) können sein wie z.B., dass du einen geeigneten Programm dafür schreiben kannst und viel übersichtlicher alles gestalten kannst.

Ich musste mal ein Auftrag erledigen und jemanden bei einem DialogSystem helfen. Er hatte da sich was im AssetStore geholt. Die z.B. unterstützten viele solche Formate. Ich glaube es gab sogar eine Seite wo man solche Dialoge erstellen kann und dann in Unity reinladen usw.

Oder man kann z.B., wenn du wegen ein Rechtschreibfehler nicht das ganze Spiel nochmal builden willst direkt an der Datei bearbeiten. Mehrere Sprachen könnten leichter übersetzbar sein.. usw.

Allerdings sind auch ScriptableObjects Assets glaube auch mit einem Texteditor lesbar und editierbar. Nur muss man da sehr aufpassen. Sie könnte man daher auch außerhalb lagern, wenn man es möchte.

Link zu diesem Kommentar
Auf anderen Seiten teilen

ah okay. Ich bin nicht so tief in der Materie drin.Ich dachte da ich vielleicht 30 Dialoge in meinem Spiel habe reicht es wenn ich das in Scriptable Objects hinterlege. Vielleicht gucke ich mir das mit den xml Dateien mal an. Das ist bestimmt ne absolut dumme Frage aber wenn ich das in xml Dateien schreibe, kann der Spieler die Datei auf seinem Smartphone oder Computer nicht einfach veraendern?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wasn das für ne Aussage?

Deine Assets werden von Unity standardmäßig verpackt. Solange du das nicht explizit willst, liegen da gar keine Dateien einzeln herum.

Das heißt nicht, dass die Daten unmodifizierbar sind. Jemand, der genügend Arbeit investiert, kann jeden Aspekt deines Spiels ändern. Sind halt alles Daten, die auf dem Rechner des Spielers liegen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...