NPC Conversations
Quickly implement intelligent game NPCs using PlayKit_NPC
NPC Conversations
PlayKit_NPC is a MonoBehaviour component designed specifically for game NPCs. It automatically manages conversation history, letting you focus on character design rather than low-level implementation.
Unlike PlayKit_AIChatClient which requires manual history management, PlayKit_NPC automatically records conversations, making it ideal for game character dialogue scenarios.
Before You Begin
- Make sure you've completed SDK initialization
- Understand message roles in Core Concepts
- Read Text Generation for basic conversation features
Add NPC Client
PlayKit_NPC is a MonoBehaviour component that can be added directly to an NPC's GameObject.
Method 1: Add in Inspector
- Select the NPC's GameObject
- Click Add Component
- Search for and add PlayKit_NPC
Method 2: Add via Code
using PlayKit_SDK;
using PlayKit_SDK.Public;
using UnityEngine;
public class NPCController : MonoBehaviour
{
private PlayKit_NPC npcClient;
void Start()
{
npcClient = gameObject.AddComponent<PlayKit_NPC>();
}
}Method 3: Use Factory Method
var npc = GetComponent<PlayKit_NPC>();
PlayKitSDK.Populate.CreateNpc(npc, "gpt-4");Basic Conversation
Set Character
Use SetCharacterDesign() to define the NPC's personality and behavior:
using Cysharp.Threading.Tasks;
using PlayKit_SDK;
using PlayKit_SDK.Public;
using UnityEngine;
public class SimpleNPC : MonoBehaviour
{
private PlayKit_NPC npc;
void Start()
{
npc = GetComponent<PlayKit_NPC>();
npc.SetCharacterDesign(@"
You are a magic shop owner named Ellie.
You run the best magic shop in the village.
You are friendly and love chatting with adventurers.
You are an expert in various magic items and always happy to give advice.
");
}
public async UniTask TalkToNPC(string playerMessage)
{
string response = await npc.Talk(
playerMessage,
this.GetCancellationTokenOnDestroy()
);
if (response != null)
{
Debug.Log($"Ellie: {response}");
DisplayDialog(response);
}
}
void DisplayDialog(string text)
{
}
}Simple Conversation Example
var npc = GetComponent<PlayKit_NPC>();
npc.SetCharacterDesign("You are a friendly villager");
// First turn
string reply1 = await npc.Talk("Hello!");
// NPC might respond: "Hello! Nice to meet you. How can I help?"
// Second turn - NPC remembers previous conversation
string reply2 = await npc.Talk("What's interesting to see in this village?");
// NPC will respond based on conversation contextStreaming Conversation
Use TalkStream() for typewriter effect, displaying NPC response character by character:
using System;
using UnityEngine.UI;
public class StreamingNPC : MonoBehaviour
{
[SerializeField] private Text dialogText;
private PlayKit_NPC npc;
private string currentDialog = "";
void Start()
{
npc = GetComponent<PlayKit_NPC>();
npc.SetCharacterDesign("You are a mysterious traveling merchant");
}
public async UniTask TalkToNPCStreaming(string playerMessage)
{
currentDialog = "";
dialogText.text = "";
await npc.TalkStream(
message: playerMessage,
onChunk: (chunk) =>
{
currentDialog += chunk;
dialogText.text = currentDialog;
},
onComplete: (fullResponse) =>
{
Debug.Log($"Full response: {fullResponse}");
},
cancellationToken: this.GetCancellationTokenOnDestroy()
);
}
}History Management
View Conversation History
var npc = GetComponent<PlayKit_NPC>();
// Get history
PlayKit_ChatMessage[] history = npc.GetHistory();
// Print history
foreach (var msg in history)
{
Debug.Log($"[{msg.Role}] {msg.Content}");
}
// Or use built-in formatted print
npc.PrintPrettyChatMessages("NPC Conversation History");Clear History
// Clear all history (including system message)
npc.ClearHistory();
// Need to reset character after clearing
npc.SetCharacterDesign("You are a friendly NPC");Undo Last Message
// Undo last message
bool success = npc.RevertHistory();
if (success)
{
Debug.Log("Last message undone");
}Undo Multiple Messages
// Undo last 3 messages
int removed = npc.RevertChatMessages(3);
Debug.Log($"Removed {removed} messages");Manually Add Messages
// Manually add messages to history
npc.AppendChatMessage("user", "Player said this");
npc.AppendChatMessage("assistant", "NPC responded this");Save and Load Conversations
Save NPC conversation history for persistent NPC state.
Save Conversation
using System.IO;
public class NPCSaveSystem : MonoBehaviour
{
private PlayKit_NPC npc;
public void SaveNPCState()
{
// Get serialized history data
string saveData = npc.SaveHistory();
// Save to file
string path = Path.Combine(
Application.persistentDataPath,
"npc_merchant_history.json"
);
File.WriteAllText(path, saveData);
Debug.Log($"NPC state saved to: {path}");
}
}Load Conversation
public class NPCLoadSystem : MonoBehaviour
{
private PlayKit_NPC npc;
void Start()
{
npc = GetComponent<PlayKit_NPC>();
// Try to load previous conversation
LoadNPCState();
}
public void LoadNPCState()
{
string path = Path.Combine(
Application.persistentDataPath,
"npc_merchant_history.json"
);
if (File.Exists(path))
{
string saveData = File.ReadAllText(path);
// Load history
bool success = npc.LoadHistory(saveData);
if (success)
{
Debug.Log("NPC state restored");
Debug.Log($"History length: {npc.GetHistoryLength()}");
}
else
{
Debug.LogError("Failed to load NPC state");
}
}
}
}Check NPC Status
Check If Talking
var npc = GetComponent<PlayKit_NPC>();
if (npc.IsTalking)
{
Debug.Log("NPC is thinking of a response...");
// Disable interaction button
}
else
{
// NPC is idle, can talk
}Check If Ready
if (npc.IsReady)
{
// NPC is initialized and ready to talk
await npc.Talk("Hello");
}
else
{
Debug.LogWarning("NPC not ready yet");
}Get History Length
int messageCount = npc.GetHistoryLength();
Debug.Log($"Current conversation has {messageCount} messages");
// Limit history length to control costs
if (messageCount > 20)
{
// Clean up old messages or summarize history
}Practical Examples
Shop NPC
using Cysharp.Threading.Tasks;
using PlayKit_SDK;
using PlayKit_SDK.Public;
using UnityEngine;
using UnityEngine.UI;
public class ShopkeeperNPC : MonoBehaviour
{
[SerializeField] private Text dialogText;
[SerializeField] private Button talkButton;
[SerializeField] private InputField playerInput;
private PlayKit_NPC npc;
void Start()
{
npc = GetComponent<PlayKit_NPC>();
// Set shopkeeper character
npc.SetCharacterDesign(@"
You are a blacksmith named Tom.
You sell weapons and armor.
You are straightforward and speak concisely.
When customers ask about items, you recommend suitable equipment.
");
talkButton.onClick.AddListener(() => OnTalkButtonClicked().Forget());
// Show initial greeting
ShowGreeting().Forget();
}
async UniTaskVoid ShowGreeting()
{
string greeting = await npc.Talk(
"New customer arrived",
this.GetCancellationTokenOnDestroy()
);
dialogText.text = $"Tom: {greeting}";
}
async UniTaskVoid OnTalkButtonClicked()
{
string playerMessage = playerInput.text;
if (string.IsNullOrEmpty(playerMessage)) return;
talkButton.interactable = false;
playerInput.text = "";
dialogText.text = $"You: {playerMessage}\n\nTom is thinking...";
string response = await npc.Talk(
playerMessage,
this.GetCancellationTokenOnDestroy()
);
if (response != null)
{
dialogText.text = $"You: {playerMessage}\n\nTom: {response}";
}
talkButton.interactable = true;
}
}Multi-NPC Conversation System
public class MultiNPCManager : MonoBehaviour
{
private Dictionary<string, PlayKit_NPC> npcs = new Dictionary<string, PlayKit_NPC>();
private PlayKit_NPC currentNPC;
void Start()
{
CreateNPC("merchant", "You are a merchant who sells various goods");
CreateNPC("guard", "You are a city gate guard responsible for protecting the city");
CreateNPC("wizard", "You are a wise mage who masters various magical knowledge");
}
void CreateNPC(string npcId, string role)
{
GameObject npcObj = new GameObject($"NPC_{npcId}");
npcObj.transform.SetParent(transform);
PlayKit_NPC npc = npcObj.AddComponent<PlayKit_NPC>();
npc.SetCharacterDesign(role);
npcs[npcId] = npc;
}
public async UniTask TalkTo(string npcId, string message)
{
if (!npcs.ContainsKey(npcId))
{
Debug.LogError($"NPC '{npcId}' doesn't exist");
return;
}
currentNPC = npcs[npcId];
string response = await currentNPC.Talk(
message,
this.GetCancellationTokenOnDestroy()
);
Debug.Log($"{npcId}: {response}");
}
public void SaveAllNPCs()
{
foreach (var kvp in npcs)
{
string saveData = kvp.Value.SaveHistory();
PlayerPrefs.SetString($"npc_{kvp.Key}", saveData);
}
PlayerPrefs.Save();
Debug.Log("All NPC states saved");
}
public void LoadAllNPCs()
{
foreach (var kvp in npcs)
{
string key = $"npc_{kvp.Key}";
if (PlayerPrefs.HasKey(key))
{
string saveData = PlayerPrefs.GetString(key);
kvp.Value.LoadHistory(saveData);
}
}
Debug.Log("All NPC states loaded");
}
}Reply Predictions
Generate suggested player responses after NPC replies. Useful for creating dialogue option UIs.
Enable Auto Predictions
var npc = GetComponent<PlayKit_NPC>();
// Enable automatic prediction generation
npc.GenerateReplyPrediction = true;
npc.PredictionCount = 4; // 2-6 predictionsSubscribe to Prediction Event
void Start()
{
var npc = GetComponent<PlayKit_NPC>();
npc.OnReplyPredictionGenerated += HandlePredictions;
}
void HandlePredictions(string[] predictions)
{
foreach (var option in predictions)
{
CreateDialogueButton(option);
}
}Manual Generation
// Generate predictions manually
string[] predictions = await npc.GenerateReplyPredictionsAsync(
count: 3,
cancellationToken: this.GetCancellationTokenOnDestroy()
);
foreach (var prediction in predictions)
{
Debug.Log($"Suggested: {prediction}");
}Performance Optimization
Limit History Length
Long conversation history increases API costs and response time:
public class NPCWithLimitedHistory : MonoBehaviour
{
private PlayKit_NPC npc;
private const int MAX_HISTORY = 15;
void Start()
{
npc = GetComponent<PlayKit_NPC>();
npc.SetCharacterDesign("You are a friendly NPC");
}
public async UniTask TalkWithLimit(string message)
{
// Check history length
if (npc.GetHistoryLength() > MAX_HISTORY)
{
// Remove oldest conversations (keep system message)
int toRemove = npc.GetHistoryLength() - MAX_HISTORY;
npc.RevertChatMessages(toRemove);
}
// Normal conversation
string response = await npc.Talk(
message,
this.GetCancellationTokenOnDestroy()
);
Debug.Log(response);
}
}Reset Long Conversations
For long-running NPCs, periodically reset conversations:
public void ResetNPCConversation()
{
// Save current system prompt
string systemPrompt = npc.CharacterDesign;
// Clear history
npc.ClearHistory();
// Reset character
npc.SetCharacterDesign(systemPrompt);
Debug.Log("NPC conversation reset");
}Best Practices
- Use NPC Client: For game characters, prefer
PlayKit_NPCover manual history management - Detailed character design: Clearly define NPC personality, background, and behavior in system prompts
- Check status: Use
IsTalkingto avoid sending new messages during ongoing conversations - Save state: Save conversation history for important NPCs to provide continuous game experience
- Limit history length: Periodically clean up or summarize conversation history to control costs
- Error handling: Always check if return value is null
- Use streaming responses: Use
TalkStreamin dialogue UIs for better user experience
Next Steps
- Learn about Authentication to configure authentication
- Read the API Reference for all available methods