GEMINI LABJP
ROBOTICS — The ER 1.6 preview that shut down on August 31 does have a successor. Gemini Robotics ER 2 is in public preview, in both standard and streaming variantsVIDEO — ER 2 judges success and failure from live video rather than still snapshots, which is what lets it catch spills, slips, and misalignments while a task is still runningDEADLINE — Next up is September 30, when gemini-omni-flash-preview is retired. The target is gemini-omni-1.1-flash, GA since August 27, and there are now under four weeks leftAPIKEY — Every remaining standard API key, restricted ones included, stops working during September. The replacement is an auth key bound to a Google Cloud service accountPRICE — Gemini 3.7 Flash keeps its introductory $0.75/$3.75 per 1M through December 31, then moves to $1.50/$7.50 on January 1, 2027. Any estimate crossing the year needs both figuresAUDIO — Gemini 3.5 Transcribe handles language detection across 85+ languages, speaker diarization, word-level timestamps, and custom vocabulary biasing of up to 1,000 termsROBOTICS — The ER 1.6 preview that shut down on August 31 does have a successor. Gemini Robotics ER 2 is in public preview, in both standard and streaming variantsVIDEO — ER 2 judges success and failure from live video rather than still snapshots, which is what lets it catch spills, slips, and misalignments while a task is still runningDEADLINE — Next up is September 30, when gemini-omni-flash-preview is retired. The target is gemini-omni-1.1-flash, GA since August 27, and there are now under four weeks leftAPIKEY — Every remaining standard API key, restricted ones included, stops working during September. The replacement is an auth key bound to a Google Cloud service accountPRICE — Gemini 3.7 Flash keeps its introductory $0.75/$3.75 per 1M through December 31, then moves to $1.50/$7.50 on January 1, 2027. Any estimate crossing the year needs both figuresAUDIO — Gemini 3.5 Transcribe handles language detection across 85+ languages, speaker diarization, word-level timestamps, and custom vocabulary biasing of up to 1,000 terms
Articles/API / SDK
API / SDK/2026-03-19Intermediate

Unity × Gemini API: Give NPCs Real Intelligence — Game Development Guide

Integrate Gemini API into Unity for intelligent NPC conversations. Dynamic dialogue beyond scripts, contextual responses, consistent character personality. Setup through production deployment.

Unity2Gemini API229NPC2AI9Game DevelopmentC#2

Unity × Gemini API: Intelligent NPC Conversations

Talk to a villager three times, hear the same line come back, and the world flattens into painted scenery. No amount of extra dialogue branches quite repairs that feeling.

An NPC that answers in its own words, reads the state of the world, and holds its personality across a conversation is a different experience altogether — and wiring Gemini API into Unity puts it within reach. Here's the build, end to end.

Why Gemini for Game NPCs

  • Ultra-Fast Responses (1.2 sec latency ideal for gaming)
  • Multimodal Capable (future: face expression recognition)
  • Cost-Effective (low API costs per response)
  • Character Consistency (system prompts maintain personality)

Gemini API Setup

Google Cloud Configuration

  1. Visit Google Cloud Console
  2. Create new project ("UnityGameAI")
  3. Enable Gemini API
  4. Generate API key (Credentials → New Key)

Unity API Key Management

using UnityEngine;
 
[CreateAssetMenu(menuName = "AI/Gemini Config")]
public class GeminiConfig : ScriptableObject
{
    [SerializeField]
    private string apiKey;
 
    public string ApiKey => apiKey;
}

Important: In production, access APIs through backend server, not client directly.

Gemini API Client Implementation

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
using System.Text;
using Newtonsoft.Json;
 
public class GeminiAPIClient : MonoBehaviour
{
    [SerializeField]
    private GeminiConfig config;
 
    private const string API_URL =
        "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent";
 
    public IEnumerator SendMessage(string userMessage, System.Action<string> onResponse)
    {
        var request = new GeminiRequest
        {
            contents = new[] {
                new Content {
                    role = "user",
                    parts = new[] { new Part { text = userMessage } }
                }
            }
        };
 
        string jsonData = JsonConvert.SerializeObject(request);
        byte[] postData = Encoding.UTF8.GetBytes(jsonData);
 
        string url = $"{API_URL}?key={config.ApiKey}";
        using (var www = new UnityWebRequest(url, "POST"))
        {
            www.uploadHandler = new UploadHandlerRaw(postData);
            www.downloadHandler = new DownloadHandlerBuffer();
            www.SetRequestHeader("Content-Type", "application/json");
 
            yield return www.SendWebRequest();
 
            if (www.result == UnityWebRequest.Result.Success)
            {
                var response = JsonConvert.DeserializeObject<GeminiResponse>(www.downloadHandler.text);
                string responseText = response.candidates[0].content.parts[0].text;
                onResponse?.Invoke(responseText);
            }
            else
            {
                Debug.LogError($"Error: {www.error}");
                onResponse?.Invoke("Error occurred");
            }
        }
    }
 
    // Serializable structures for API
    [System.Serializable]
    public class GeminiRequest { public Content[] contents; }
 
    [System.Serializable]
    public class Content
    {
        public string role;
        public Part[] parts;
    }
 
    [System.Serializable]
    public class Part { public string text; }
 
    [System.Serializable]
    public class GeminiResponse { public Candidate[] candidates; }
 
    [System.Serializable]
    public class Candidate { public Content content; }
}

NPC Character System

Base NPC Class

using UnityEngine;
using System.Collections.Generic;
 
public class NPCCharacter : MonoBehaviour
{
    [SerializeField]
    private string npcName;
 
    [SerializeField]
    private string characterPrompt;
 
    [SerializeField]
    private GeminiAPIClient apiClient;
 
    private List<(string role, string message)> conversationHistory;
 
    private void Start()
    {
        conversationHistory = new List<(string, string)>();
    }
 
    public void SendMessage(string userMessage)
    {
        conversationHistory.Add(("user", userMessage));
 
        var sb = new System.Text.StringBuilder();
        sb.AppendLine(characterPrompt);
        sb.AppendLine("\n【Conversation History】");
 
        foreach (var (role, msg) in conversationHistory)
        {
            sb.AppendLine($"{(role == "user" ? "Player" : npcName)}: {msg}");
        }
 
        StartCoroutine(apiClient.SendMessage(sb.ToString(), OnResponseReceived));
    }
 
    private void OnResponseReceived(string response)
    {
        conversationHistory.Add(("npc", response));
        // Display in UI
        DisplayDialogue(response);
    }
 
    private void DisplayDialogue(string text)
    {
        // Show NPC response in dialogue panel
        var panel = GetComponent<DialoguePanel>();
        panel.ShowMessage(npcName, text);
    }
}

Character Personality Definition

Key to realistic NPCs: Detailed system prompts

You are "Frodia," a wise 150-year-old wizard living in the eastern tower.

Personality: Calm, thoughtful, occasionally humorous
Catchphrase: "Hmm, I see..." "Do you understand?"

World Knowledge:
- Magic uses four elements (fire, water, wind, earth)
- Humans and elves coexist but have tensions
- Dark magic is forbidden

Conversation Rules:
1. Always respond in character
2. Use world knowledge
3. Keep responses 1-3 sentences
4. Answer player questions helpfully

Example:
Player: "I want to learn fire magic"
Frodia: "Good intention, young one. Fire magic harnesses flame element.
        First learn the basics. Will you practice?"

This level of detail ensures consistent, contextual responses.

Cost Optimization

Conversation History Management

private const int MAX_HISTORY_PAIRS = 5;
 
private string BuildConversationContext(string userMessage)
{
    // Keep only last 5 exchanges to limit tokens
    int startIndex = Mathf.Max(0, conversationHistory.Count - MAX_HISTORY_PAIRS * 2);
 
    var sb = new System.Text.StringBuilder();
    sb.AppendLine(characterPrompt);
 
    for (int i = startIndex; i < conversationHistory.Count; i++)
    {
        var (role, msg) = conversationHistory[i];
        sb.AppendLine($"{(role == "user" ? "Player" : npcName)}: {msg}");
    }
 
    sb.AppendLine($"Player: {userMessage}");
    return sb.ToString();
}

Response Caching

private Dictionary<string, string> responseCache = new();
 
public IEnumerator SendMessage(string userMessage, System.Action<string> onResponse)
{
    if (responseCache.TryGetValue(userMessage, out string cached))
    {
        onResponse?.Invoke(cached);
        yield break;
    }
 
    // API call... then cache result
    responseCache[userMessage] = response;
}

Fallback Responses

private string GetFallbackResponse(string userMessage)
{
    if (userMessage.Contains("hello"))
        return "Hello there, traveler. What brings you?";
    else if (userMessage.Contains("quest"))
        return "Quests... check the bulletin board.";
    else
        return "Hmm... (contemplating)";
}

Practical Examples

Merchant NPC

public class MerchantNPC : NPCCharacter
{
    [SerializeField]
    private List<ItemData> inventory;
 
    protected override string BuildCharacterPrompt()
    {
        var sb = new System.Text.StringBuilder();
        sb.AppendLine("You are Marco, a merchant. Shrewd, business-minded.");
        sb.AppendLine("\nCurrent Inventory:");
 
        foreach (var item in inventory)
            sb.AppendLine($"- {item.name}: {item.price} gold");
 
        sb.AppendLine("\nRecommend items to the customer.");
        return sb.ToString();
    }
}

Quest NPC

public class QuestGiverNPC : NPCCharacter
{
    [SerializeField]
    private List<QuestData> availableQuests;
 
    // Similar implementation:  Dynamic quest offers based on inventory
}

UI Integration

public class DialoguePanel : MonoBehaviour
{
    [SerializeField] private Text characterNameText;
    [SerializeField] private Text dialogueText;
 
    public void ShowMessage(string characterName, string message)
    {
        characterNameText.text = characterName;
        StartCoroutine(TypeMessage(message));
    }
 
    private IEnumerator TypeMessage(string message)
    {
        dialogueText.text = "";
        foreach (char c in message)
        {
            dialogueText.text += c;
            yield return new WaitForSeconds(0.05f);
        }
    }
}

Best Practices

  1. Character Consistency: Detailed, specific system prompts
  2. Response Length: Limit to 1-3 sentences for game pacing
  3. Token Management: Cache, limit history, use fallbacks
  4. Error Handling: Network failures need graceful degradation
  5. Testing: Thoroughly test NPC personalities before deployment

Security Notes

  • Never embed API keys in client code
  • Use backend proxy for production
  • Rate limit API calls per player
  • Validate all inputs before API calls

Wrapping up

Gemini API-powered NPCs transform game immersion. With proper configuration, your NPCs become genuinely intelligent conversationalists, not dialogue tree puppets.

Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $15 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

API / SDK2026-03-19
Unity × Gemini Multimodal Complete Implementation — Advanced Code Collection
Complete production-ready Unity + Gemini implementation: Streaming responses, image recognition, voice dialogue, context management. 65% latency reduction, 34% UX satisfaction improvement.
API / SDK2026-07-09
Google Sheets API × Gemini API: A Python Data Pipeline — No Apps Script Required
Learn how to build a fully Python-based pipeline that reads data from Google Sheets, processes it with Gemini API, and writes results back — without touching Apps Script. Covers service account auth, structured output, and rate limit handling.
API / SDK2026-09-01
Your New Gemini API Key Never Took Effect, and Load Order Wasn't the Reason
When several sources supply the same environment variable, swapping your key can leave the old value in place. Here is what four load orders actually produced, and a ledger that records which source won.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →