Lingara Lingara المستندات أدلة التعلّم API المكتبات التطبيقات البناء التضمين تطبيق الويب
اللغة: العربية

حوار NPC

هذه الصفحة مترجمة من الإنجليزية. إذا اختلفت النسختان، فالصفحة الإنجليزية هي الصحيحة. اقرأ الصفحة الإنجليزية

يمكن لشخصية في لعبتك أن تجري محادثة مع اللاعب باللغة التي يتعلّمها، بما يناسب مستواه. كل سطر يقوله اللاعب هو دور واحد: ترسله حزمة اللاعب، ويتدفّق رد الشخصية عائدًا على أجزاء.

ما يحمله الدور

يرسل كل دور كل ما تحتاجه الشخصية، لأن Lingara لا تحتفظ بأي محادثة بين الأدوار:

  • npc: من يتحدث. طول name من 1 إلى 32 حرفًا، وpersona الاختياري سطر وصف واحد، من 1 إلى 120 حرفًا، مثل «بائع زلابية».
  • scene: اختياري، المكان الذي تجري فيه المحادثة، من 1 إلى 160 حرفًا.
  • source_lang وtarget_lang: لغة اللاعب نفسه واللغة التي يتعلّمها. يجب أن تختلفا، ولا تتحدث الشخصية إلا بـ target_lang.
  • level: مستوى اللاعب، من 1 إلى 9. يصف دليل Lingara «ما معنى المستوى» هذا المقياس.
  • line: ما قاله اللاعب للتو، من 1 إلى 500 حرف.
  • history: المحادثة حتى الآن، الأقدم أولًا، بحد أقصى 12 سطرًا. لكل سطر speaker، إما player أو npc، وtext الخاص به، من 1 إلى 500 حرف.

كل نص سطر واحد. تحتفظ لعبتك بالمحادثة: تحتفظ حزمة اللاعب بالنافذة لكل حوار تفتحه، وتضيف إليها كل دور مكتمل، وتقصّ كل رد إلى أول 500 حرف منه، وتُسقط الأسطر الأقدم بعد 12 سطرًا.

تعامل Lingara وصف الشخصية والمشهد على أنهما نص غير موثوق من لعبتك. فهما يشكّلان طريقة كلام الشخصية، ولا يحدّدان أبدًا ما يُسمح لها بفعله.

كيف يصل الرد

يتدفّق الرد على شكل أجزاء من النص، تُلحقها لعبتك بعضها ببعض فور وصولها. قد يأتي إشعار بينها، مثل إشعار يقول إن الرد قُطع قبل اكتماله. ينتهي الدور بـ done عندما يكتمل الرد، أو بـ error عندما يفشل. الدور غير قابل للاستئناف: إذا انقطع الاتصال، يقول اللاعب السطر مرة أخرى.

قل سطرًا واحدًا في كل مرة لكل شخصية. السطر الذي يُقال بينما لا تزال الشخصية ترد يُرفض بدلًا من وضعه في الطابور، لأن كل دور يُفوتَر.

من يدفع

لا يمكن إجراء محادثة إلا للاعبي عميل مشترك في خطة الاستخدام المقاس، ويُفوتَر كل دور على ذلك العميل. يحتاج رمز اللاعب إلى embed:play.

لغة مثال الشيفرة

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

انظر أيضًا