GEMINI LABJP
NANOLITE — Nano Banana 2 Lite is here: Google's fastest and most cost-efficient Gemini Image model, made for running lightweight image generation cheaplyOMNIFLASH — Gemini Omni Flash is in public preview, a natively multimodal model that lets enterprises and developers build custom, dynamic video workflowsAGENTS — Managed Agents expand with background: true for async server-side runs and polling, remote MCP server integration, and refreshing credentials across interactionsMEMORY — The Memory Bank IngestEvents API is generally available, decoupling event ingestion from memory generation so you can stream content continuouslyTHROUGHPUT — Provisioned Throughput now lets you submit up to seven pending orders for the same model and regionDEPRECATE — Image generation models shut down on August 17, and the Grok 4.1 family on the Gemini Enterprise Agent Platform on August 20NANOLITE — Nano Banana 2 Lite is here: Google's fastest and most cost-efficient Gemini Image model, made for running lightweight image generation cheaplyOMNIFLASH — Gemini Omni Flash is in public preview, a natively multimodal model that lets enterprises and developers build custom, dynamic video workflowsAGENTS — Managed Agents expand with background: true for async server-side runs and polling, remote MCP server integration, and refreshing credentials across interactionsMEMORY — The Memory Bank IngestEvents API is generally available, decoupling event ingestion from memory generation so you can stream content continuouslyTHROUGHPUT — Provisioned Throughput now lets you submit up to seven pending orders for the same model and regionDEPRECATE — Image generation models shut down on August 17, and the Grok 4.1 family on the Gemini Enterprise Agent Platform on August 20
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 API192NPC2AI9Game 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 $10 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-07-19
Still image or short clip? Deciding feature placement from the cost gap between Nano Banana 2 Lite and Omni Flash
When I froze over whether a wallpaper app's hero asset should be a still image or a short moving loop, the deciding factor was not taste but the order of magnitude of the cost. Here is how to normalize Nano Banana 2 Lite and Omni Flash onto the same footing, down to a working decision function.
📚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 →