Lingara Lingara Dokumentation Ratgeber API Bibliotheken Apps Erstellen Einbetten Web-App
Sprache: Deutsch

NPC-Dialoge

Diese Seite ist aus dem Englischen übersetzt. Wenn die beiden voneinander abweichen, ist die englische Seite maßgeblich. Englische Seite lesen

Eine Figur in Ihrem Spiel kann mit dem Spieler ein Gespräch in der Sprache führen, die er lernt, abgestimmt auf seine Stufe. Jede Zeile, die der Spieler sagt, ist ein Zug: Das Spieler-Kit sendet sie, und die Antwort der Figur strömt in Teilen zurück.

Was ein Zug enthält

Jeder Zug sendet alles, was die Figur braucht, denn Lingara speichert zwischen den Zügen kein Gespräch:

  • npc: wer spricht. Sein name hat 1 bis 32 Zeichen, und seine optionale persona ist eine Zeile Beschreibung mit 1 bis 120 Zeichen, etwa „eine Teigtaschenverkäuferin“.
  • scene: optional, wo das Gespräch stattfindet, 1 bis 160 Zeichen.
  • source_lang und target_lang: die eigene Sprache des Spielers und die, die er lernt. Sie müssen sich unterscheiden, und die Figur spricht nur target_lang.
  • level: die Stufe des Spielers, von 1 bis 9. Der Lingara-Leitfaden „Was ein Niveau bedeutet“ beschreibt die Skala.
  • line: was der Spieler gerade gesagt hat, 1 bis 500 Zeichen.
  • history: das bisherige Gespräch, älteste Zeile zuerst, höchstens 12 Zeilen. Jede Zeile hat einen speaker, entweder player oder npc, und ihren text, 1 bis 500 Zeichen.

Jeder Text ist eine einzelne Zeile. Ihr Spiel führt das Gespräch: Das Spieler-Kit hält das Fenster für jeden Dialog, den Sie öffnen, fügt ihm jeden abgeschlossenen Zug hinzu, kürzt jede Antwort auf ihre ersten 500 Zeichen und verwirft die ältesten Zeilen über 12 hinaus.

Lingara behandelt die Persona und die Szene als nicht vertrauenswürdigen Text aus Ihrem Spiel. Sie prägen, wie die Figur spricht, nie, was sie tun darf.

Wie eine Antwort ankommt

Die Antwort strömt als Textstücke herein, die Ihr Spiel anhängt, sobald sie ankommen. Dazwischen kann ein Hinweis kommen, etwa einer, der besagt, dass die Antwort gekürzt wurde. Der Zug endet mit done, wenn die Antwort vollständig ist, oder mit error, wenn sie fehlgeschlagen ist. Ein Zug lässt sich nicht fortsetzen: Bricht die Verbindung ab, sagt der Spieler die Zeile erneut.

Sagen Sie jeder Figur eine Zeile nach der anderen. Eine Zeile, die gesagt wird, während die Figur noch antwortet, wird abgelehnt statt eingereiht, weil jeder Zug abgerechnet wird.

Wer bezahlt

Nur die Spieler eines nutzungsbasiert abgerechneten Clients dürfen ein Gespräch führen, und jeder Zug wird diesem Client in Rechnung gestellt. Das Token eines Spielers braucht embed:play.

Sprache des Codebeispiels

Bevy

fn spawn_seller(mut commands: Commands) {
    let mei = NpcDialogue::new("Mei", "zh", 2)
        .and_then(|npc| npc.with_persona("a dumpling seller"))
        .and_then(|npc| npc.with_scene("the night market"))
        .expect("within Lingara's bounds");
    commands.spawn(mei);
    commands.spawn(Player);
}

/// One turn at a time: a line said while the NPC is replying is a `Busy` error.
fn talk(keys: Res<ButtonInput<KeyCode>>, npcs: Query<Entity, With<NpcDialogue>>, mut say: MessageWriter<NpcSay>) {
    if keys.just_pressed(KeyCode::Digit1) {
        for entity in &npcs {
            say.write(NpcSay { entity, line: "饺子多少钱?".into() });
        }
    }
}

/// `streaming` grows as the reply arrives; `turns` holds the finished ones.
fn show_reply(transcripts: Query<&NpcTranscript, Changed<NpcTranscript>>) {
    for transcript in &transcripts {
        if let Some(partial) = &transcript.streaming {
            info!("…{partial}");
        }
    }
}

Unity

public DialogueId OpenDialogue(string npc, string sourceLang, string targetLang, byte level) =>
    Client.DialogueOpen(new DialogueConfig { Npc = new Npc { Name = npc }, SourceLang = sourceLang, TargetLang = targetLang, Level = level });

// The reply streams back as NpcTurn events: append each Fragment's text to your label.
public RequestId Say(DialogueId dialogue, string line) => Client.DialogueSay(dialogue, line);

Godot C#

public long OpenDialogue(string npc, string sourceLang, string targetLang, byte level) =>
    Client.DialogueOpen(new DialogueConfig { Npc = new Npc { Name = npc }, SourceLang = sourceLang, TargetLang = targetLang, Level = level }).Value;

// The reply streams back as NpcTurnFragment signals, then one NpcTurnFinished.
public long Say(long dialogue, string line) => Client.DialogueSay(new DialogueId(dialogue), line).Value;

GDScript

# A LingaraNpc child per character: npc_name, target_lang and level in the
# inspector. say() returns false while a turn is in flight (turns are never
# queued, because each one is billed).
func talk_to_mei(line: String) -> void:
	if mei.say(line):
		bubble.text = "…"


func _on_mei_replied(text: String) -> void:
	bubble.text = text

Unreal C++

void ALingaraEmbedSnippetActor::Say(const FString& Line)
{
	ELingaraCallResult Result;
	FLingaraEmbedError Error;
	if (Dialogue == 0)
	{
		FLingaraDialogueConfig Config;
		Config.Npc.Name = TEXT("Mei");
		Config.Npc.Persona = TEXT("a tea seller at the night market");
		Config.SourceLang = TEXT("en");
		Config.TargetLang = TEXT("zh");
		Config.Level = 2;
		Dialogue = Lingara()->DialogueOpen(Config, Result, Error);
	}
	Reply.Reset();
	Lingara()->DialogueSay(Dialogue, Line, Result, Error);
}

// The reply streams back as npc_turn events: append each fragment.
void ALingaraEmbedSnippetActor::HandleNpcTurn(const FLingaraNpcTurn& Turn)
{
	if (Turn.Dialogue == Dialogue && Turn.Update.Type == ELingaraNpcTurnUpdateType::Fragment)
	{
		Reply += Turn.Update.Text;
	}
}

Kotlin

fun talkToMei(line: String) {
    val dialogue = npc ?: lingara.dialogueOpen(DialogueConfig(Npc("Mei", "a tea seller"), "the tea house", "en", "zh", 2, emptyList()))
    npc = dialogue
    lingara.dialogueSay(dialogue, line)
}

private fun onNpcTurn(update: NpcTurnUpdate) {
    when (update) {
        is NpcTurnUpdate.Opened -> bubble = ""
        is NpcTurnUpdate.Fragment -> bubble += update.text
        is NpcTurnUpdate.Finished -> bubble = update.text
        else -> Unit
    }
}

Java

void talkToMei(String line) {
  if (npc < 0) {
    Npc mei = new Npc("Mei", "a tea seller");
    npc =
        lingara.dialogueOpen(new DialogueConfig(mei, "the tea house", "en", "zh", 2, List.of()));
  }
  lingara.dialogueSay(npc, line);
}

void onNpcTurn(EmbedEvent.NpcTurn turn) {
  if (turn.getUpdate() instanceof NpcTurnUpdate.Fragment fragment) {
    bubble.append(fragment.getText());
  } else if (turn.getUpdate() instanceof NpcTurnUpdate.Finished finished) {
    bubble.setLength(0);
    bubble.append(finished.getText());
  }
}

Siehe auch