Lingara Lingara Documentatie Gidsen API Bibliotheken Apps Bouwen Insluiten Webapp
Taal: Nederlands

NPC-dialoog

Deze pagina is vertaald uit het Engels. Als de twee verschillen, is de Engelse pagina juist. Lees de Engelse pagina

Een personage in je game kan met de speler een gesprek voeren in de taal die de speler leert, afgestemd op diens niveau. Elke regel die de speler zegt, is één beurt: de spelerkit verstuurt hem, en het antwoord van het personage stroomt in stukken terug.

Wat een beurt bevat

Elke beurt verstuurt alles wat het personage nodig heeft, omdat Lingara tussen beurten geen gesprek bewaart:

  • npc: wie er spreekt. De name is 1 tot 32 tekens, en de optionele persona is één regel beschrijving van 1 tot 120 tekens, zoals “een verkoopster van dumplings”.
  • scene: optioneel, waar het gesprek plaatsvindt, 1 tot 160 tekens.
  • source_lang en target_lang: de eigen taal van de speler en de taal die de speler leert. Ze moeten verschillen, en het personage spreekt alleen target_lang.
  • level: het niveau van de speler, van 1 tot 9. De Lingara-gids “Wat een niveau betekent” beschrijft de schaal.
  • line: wat de speler net heeft gezegd, 1 tot 500 tekens.
  • history: het gesprek tot nu toe, oudste eerst, maximaal 12 regels. Elke regel heeft een speaker, player of npc, en de text, 1 tot 500 tekens.

Elke tekst is één regel. Je game houdt het gesprek bij: de spelerkit bewaart het venster voor elke dialoog die je opent, voegt elke voltooide beurt eraan toe, kort elk antwoord in tot de eerste 500 tekens en laat de oudste regels voorbij 12 vallen.

Lingara behandelt de persona en de scène als onbetrouwbare tekst uit je game. Ze bepalen hoe het personage spreekt, nooit wat het mag doen.

Hoe een antwoord aankomt

Het antwoord stroomt binnen als stukken tekst, die je game toevoegt zodra ze aankomen. Daartussen kan een melding komen, bijvoorbeeld dat het antwoord is afgekapt. De beurt eindigt met done als het antwoord compleet is, of met error als het is mislukt. Een beurt kan niet worden hervat: als de verbinding wegvalt, zegt de speler de regel opnieuw.

Zeg tegen elk personage één regel tegelijk. Een regel die wordt gezegd terwijl het personage nog antwoordt, wordt geweigerd in plaats van in de wachtrij gezet, omdat elke beurt wordt gefactureerd.

Wie betaalt

Alleen de spelers van een client met betalen per gebruik mogen een gesprek voeren, en elke beurt wordt aan die client gefactureerd. Het token van een speler heeft embed:play nodig.

Taal van het codevoorbeeld

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());
  }
}

Zie ook