NPC'leri oyun motoruyla orkestre et
Moonborn karakter katmanını oyun motorunun sahne durum makinesine (state machine) bağla — kim hangi tarafa ait, kayıt / yükleme Moonborn oturum kimliğini nasıl taşır.
Moonborn karakter katmanını sahiplenir: persona üretimi, voice fingerprint, drift detection, ensemble ilişkileri, hafıza (memory). Oyun motorun sahne katmanını sahiplenir: hangi NPC sahnede, tur sırası, dallı anlatı (branching narrative), kayıt / yükleme (save / load), oyuncu arayüzü (player UI). Bu rehber sınırı net çizer ve iki tarafı bağlayan minimum deseni gösterir.
Bu rehberi bitirdiğinde
- Moonborn'un ve motorun sahiplendiği şeyleri ayırt edebileceksin.
- Bir sahnedeki NPC'leri Moonborn oturumuna bağlayabileceksin (tek + çok karakterli / ensemble).
- Motorun kim konuşacak kararını verdiği bir orkestrasyon deseni kurabileceksin.
- Kayıt / yükleme akışında Moonborn oturum kimliğinin nasıl saklandığını (serialize) bileceksin.
- Drift sinyalini motor arayüzünde (örn. karakter mimiklerini — emote — tetikleme) kullanabileceksin.
Ön koşul: API anahtarı + en az iki NPC persona + bir oyun motoru veya prototip CLI'ı. Çok karakterli akış yeni bir konuysa önce Çok karakterli bir sahne kur.
Sınır — kim neyi sahipleniyor
- Persona üretimi + kalıcılığı (persistence)
- Yanıt başına voice fingerprint + drift detection
- Ensemble ilişkileri (tipli kenarlar / edges)
- Sohbet oturumu içinde uzun vadeli hafıza
- Denetim (audit) + tahrik (provocation) test hattıBağlama deseni
Motor sahne durum makinesini yönetir, Moonborn'a sadece "kim konuşuyor ve ne söyledi" çağrısı yapar.
// Motor tarafı — sahne tanımı
class Scene {
constructor(
public participants: NPC[],
public turnOrder: 'round-robin' | 'narrative' | 'initiative',
) {}
// Sahne durumuna göre kim konuşacak seç
pickResponder(playerText: string): NPC {
if (this.turnOrder === 'narrative') {
return this.narrativePolicy(playerText);
}
if (this.turnOrder === 'initiative') {
return this.highestInitiative();
}
return this.nextInRoundRobin();
}
async onPlayerSay(text: string) {
const speaker = this.pickResponder(text);
const reply = await client.chat.messages.create({
sessionId: speaker.moonbornSessionId,
speaker: speaker.personaId,
content: text,
});
// Motor yanıtı işler — animasyon, ses, arayüz
this.deliver(speaker, reply.content);
// Drift sinyali arayüze — örn. karakterin "şaşkın" animasyonunu tetikle
if (reply.driftAlert) {
this.flagCharacter(speaker, 'drift', reply.driftScore);
}
}
}Çoklu persona oturumları (ensemble)
Birden fazla NPC aynı sahnede konuşacaksa, tek bir paylaşılan oturum aç. ensemble dizisi ek konuşmacıları taşır; her messages.create çağrısında speaker alanı aktif NPC'yi seçer.
const session = await client.chat.sessions.create({
personaId: merchant.id,
ensemble: [traveler.id, tavernKeeper.id],
metadata: { sceneId: 'tavern_arrival' },
});
// Tur 1 — merchant konuşuyor
await client.chat.messages.create({
sessionId: session.id,
speaker: merchant.id,
content: 'Tavernci! Bana bir kase çorba ve bir ekmek...',
});
// Tur 2 — tavern keeper cevap veriyor
await client.chat.messages.create({
sessionId: session.id,
speaker: tavernKeeper.id,
content: '(merchant\'a soğuk bir bakış) Para önce.',
});Kayıt / yükleme
Sohbet oturum kimliği kalıcılık anahtarıdır. Oyun kayıt dosyasında sahne durumunun yanına sakla (serialize).
{
"sceneId": "tavern_arrival",
"turn": 14,
"participants": ["merchant", "traveler", "tavern_keeper"],
"moonbornSessionId": "ses_01H...",
"questFlags": { "letter_revealed": true, "merchant_suspicious": false }
}Yükleme akışı:
- Kayıt dosyasından
moonbornSessionId'yi çek. - Aynı
sessionIdilechat.messages.createçağrıları yapmaya devam et. - Kısa vadeli hafıza bozulmamış (son N tur istemde), uzun vadeli hafıza + voice fingerprint hâlâ sabitli (pinned).
Drift sinyalini motor arayüzüne bağla
Drift skorunu sahne arayüzüne bağlamak anlatı ipucu olarak kullanılabilir:
if (reply.driftAlert) {
// Bir karakter "kendisinden çıkmış" gibi görünüyor — arayüzde bir
// mimik (emote), müzik değişikliği veya altyazı stilinde fark
scene.tweakEmote(speaker, 'uncertain');
}Bu yazılı drama için işlevsel olabilir — karakter isteminde (prompt) zorlanıyorsa bunu arayüzde görünür kıl. RPG ürünleri için drift sinyali "büyü baskısı altında karakter kontrolünü kaybediyor" gibi mecazlara dönüşebilir.
Tipik bir motor entegrasyonu
| Motor | Tipik bağlama biçimi |
|---|---|
| Unity | C# sarmalayıcı (wrapper), Moonborn REST API'yi MonoBehaviour'da çağırır. Oturum kimliği sahne ScriptableObject'inde tutulur. |
| Godot | GDScript HTTP istemcisi; Moonborn yanıtı DialogueResource dosyasına itilir. |
| Twine / Ink | Özel fonksiyon koşum takımı (harness); ink seçeneğinden Moonborn yanıtı tetiklenir. |
| Özel (TS / Node) | Doğrudan @moonborn/sdk; CLI prototipleme ve web tabanlı oyunlar için ideal. |
Plan gereksinimi
Pro ve üstü (ensemble + uzun hafıza aktif).
İlgili
Ensemble oturum + konuşmacı seçimi adım adım eğitimi.
Motor entegrasyonu öncesi CLI prototip akışı.
Tipli kenarların istem (prompt) birleştirmesine nasıl indiği.
Oyun ekiplerinin Moonborn'u motorla nasıl kullandığına dair kullanım senaryosu.