Back to Blog
·Summer Team

Godot 4で記憶と個性を持つAI NPCを作る方法

Godot 4でAIを活用し、プレイヤーを記憶し、キャラクターを保ち、動的に反応するNPCの作り方を学びます。

ほとんどのゲームのNPCはステートマシンです。決められたルートを巡回し、プレイヤーを検知し、攻撃モードに切り替わり、またループに戻ります。敵キャラクターには十分ですが、生き生きとした存在に感じさせたいキャラクターには通用しません。

プレイヤーがゲーム内で何をしようと、同じ3つのセリフしか口にしない店主。先週あなたが村を救ったことを認識しないクエストギバー。会話が終わった瞬間にすべてを忘れてしまう仲間。

AIはここで何ができるかを変えます。ゲームデザインをチャットボットに置き換えるのではなく、従来のNPCシステムの上に記憶、個性、動的な反応のレイヤーを追加するのです。

AI NPCとは実際に何か

AI NPCとは、ゲーム世界に貼り付けられたチャットボットではありません。それが最もよくある誤解で、その結果として、ゲームから切り離されて感じられるNPCになってしまいます。

うまく構築されたAI NPCは、言語モデルとゲームシステムを組み合わせます。次のような要素を備えています。

  • 個性プロンプト: 話し方、何を大切にしているか、さまざまな状況にどう反応するかを定義します。無骨な鍛冶屋と臆病な見習いでは話し方が違います。
  • 記憶システム: プレイヤーとのやり取りを追跡します。何が語られたか、何が取引されたか、どのクエストが渡され完了したか。
  • 目標と動機: 行動に影響します。商人はお金を稼ぎたい。衛兵は町を守りたい。盗賊は捕まらないようにしたい。
  • ゲーム世界の認識: 実際のイベント、アイテム、場所、他のキャラクターを参照できるようにします。「東街道の盗賊を片付けてくれたそうだな」というセリフは、NPCがゲームの状態を照会できる場合にのみ機能します。

その結果として生まれるのは、一貫性を保ち、文脈を記憶し、ゲーム世界に根ざした自然な形でプレイヤーに応答するキャラクターです。

AI NPCの3つのレイヤー

すべてのAI NPCは3つの明確なレイヤーに分解できます。3つすべてを実装してもいいですし、1つか2つから始めてもかまいません。

レイヤー1: 振る舞い

これは従来のゲームAIです。巡回ルート、反応トリガー、戦闘ロジック、日々のスケジュール。ビヘイビアツリーまたはステートマシンが、NPCの世界における物理的な行動を処理します。

このレイヤーはインターネット接続なしでローカルに動作します。決定的で予測可能です。鍛冶屋は日中は鍛冶場に立ち、夜には家に帰ります。衛兵は城壁を巡回します。商人は夜明けに店を開けます。

Godot 4では通常、ステート遷移にAnimationTree、検知ゾーンにArea3Dノード、ステートマシンやビヘイビアツリーを管理するスクリプトを使って実装します。

enum State { IDLE, WORKING, SLEEPING, TALKING }
var current_state: State = State.IDLE
var schedule: Dictionary = {
    6: State.WORKING,
    20: State.IDLE,
    22: State.SLEEPING
}

このレイヤーは土台です。AI会話と記憶を追加するとしても、振る舞いのレイヤーがNPCをゲーム世界に根付かせ、一貫性のある信頼できる行動を保ちます。

レイヤー2: 会話

ここでLLMが登場します。あらかじめ書かれたセリフから選ぶのではなく、NPCは個性、現在の文脈、会話履歴に基づいて応答を生成します。

個性プロンプトは最も重要な要素です。キャラクターの声、知識、境界線を定義します。

You are Tormund, a blacksmith in the village of Ashford.
You are gruff but fair. You take pride in your craft.
You charge reasonable prices and give discounts to repeat customers.
You have a side quest: you need rare ore from the northern mines
to forge a legendary blade. You will ask trusted customers for help.
You know about: village gossip, weapon quality, mining locations.
You do not know about: magic, politics, events outside Ashford.

会話レイヤーにはAIモデルが必要です。クラウドAPI(OpenAI、Anthropic、Google)でも、Ollama経由で動作するローカルモデルでもかまいません。ローカルモデルは遅延は大きくなりますが、ランニングコストはゼロで、プライバシーも完全に守られます。

重要な設計判断として、NPCの応答には制約が必要です。制約のないチャットボットは、存在しない場所を幻覚的に作り上げたり、ゲームにないアイテムを参照したり、キャラクターを完全に壊したりします。個性プロンプトと、現在のゲーム状態を注入するシステムを組み合わせることで、応答を地に足のついたものに保てます。

レイヤー3: 記憶

説得力のあるAI NPCを単なる物珍しさから分けるのは記憶です。記憶がなければ、すべての会話は毎回ゼロから始まります。NPCはプレイヤーが誰なのか、以前に何があったのかをまったく知りません。

記憶システムは次のものを追跡します。

  • やり取りの履歴: プレイヤーが何を言ったか、NPCがどう応答したか、いつ起こったか。
  • 関係性の状態: NPCはプレイヤーを信頼しているか。友好的か、中立か、敵対的か。
  • 重要なイベント: プレイヤーがこのNPCのクエストを完了した。プレイヤーがその店から盗みを働いた。プレイヤーがその子どもを危険から救った。
  • 共有された知識: プレイヤーが明かした情報。「失われた神殿を探している」は、後でNPCが参照できる情報になります。

記憶の保存はシンプルで構いません。JSONファイルやSQLiteデータベースでほとんどのゲームには十分です。重要なのは、記憶をどう取り出し、会話のコンテキストに注入するかです。

var memories: Array[Dictionary] = []

func add_memory(event: String, importance: float) -> void:
    memories.append({
        "event": event,
        "importance": importance,
        "timestamp": Time.get_unix_time_from_system(),
    })

func get_relevant_memories(context: String, limit: int = 5) -> Array:
    # Sort by importance and recency, return top memories
    var sorted = memories.duplicate()
    sorted.sort_custom(func(a, b):
        return a.importance * _recency_weight(a.timestamp) > \
               b.importance * _recency_weight(b.timestamp)
    )
    return sorted.slice(0, limit)

プレイヤーがNPCと話すと、関連する記憶が取り出され、プロンプトに含められます。「プレイヤーは3日前、希少な鉱石を探すのを手伝ってくれた。あなたは感謝しており、割引を提供した。」LLMはこの文脈を使って、共有された歴史を踏まえた応答を生成します。

記憶はセッションをまたいで残ります。プレイヤーがセーブをロードしたとき、NPCはすべてを覚えています。これこそがAI NPCをスクリプトされたNPCとは本質的に違うものにするポイントです。

Summer EngineでAI NPCを作る

Summer Engineはこのプロセスを会話形式にします。各レイヤーを手作業で配線する代わりに、欲しいNPCを言葉で説明します。

「Tormundという名前の鍛冶屋NPCを追加してください。彼は無骨だが公正で、合理的な価格で販売し、北の鉱山で希少な鉱石を探すサブクエストを持っています。過去の取引を記憶し、リピーターには割引を提供します。」

エンジンは次のものを作成します。

  • CharacterBody3D、コリジョン形状、メッシュを備えたNPCノード
  • 日々のスケジュールを持つビヘイビアツリー(日中は鍛冶場で働き、夜は家に帰る)
  • あなたの説明に基づく個性プロンプトを備えた会話システム
  • プレイヤーとのやり取りと取引履歴を追跡する記憶ストア
  • 関係性の状態を価格に反映するショップインターフェース

これらのコンポーネントはどれも会話で調整できます。「Tormundを見知らぬ人に対してもっと疑い深くして」と言えば、個性プロンプトと初期の関係性状態が調整されます。「攻撃されたら反撃する戦闘反応を追加して」と言えば、ビヘイビアツリーが拡張されます。

Summer EngineはGodot 4 互換なので、生成されるシステムは標準のGodotノードとGDScriptを使用します。エンジンが作成したものはすべて確認して修正できます。AI NPCはブラックボックスではありません。あなたが所有するノード、スクリプト、リソースの集まりです。

AI NPCとスクリプトされたNPCの比較

どちらのアプローチにも正当な用途があります。適切な選択はゲーム次第です。

スクリプトされたNPC:

  • 完全に予測可能。彼らが話すすべての言葉をあなたが制御します。
  • オフラインで動作し、ランタイムコストはゼロ。
  • 振る舞いが決定的なのでテストとQAが容易。
  • スケールしやすい。100体のスクリプトされたNPCのコストは1体と同じ。
  • あなたが書いたコンテンツに制限される。プレイヤーはすぐに会話を使い果たします。

AI NPC:

  • 動的で反応的。すべての会話がユニーク。
  • やり取りをまたいで文脈を記憶する。
  • 想定外のプレイヤー入力にも優雅に対応できる。
  • ランタイムコストが高い(API呼び出しまたはローカルモデルの推論)。
  • 応答がばらつくのでテストが難しい。
  • 適切なガードレールがないと、キャラクターを壊したり不適切なコンテンツを生成したりするリスクがある。

ハイブリッドアプローチがほとんどのゲームに最適です。 巡回ルート、戦闘ロジック、日々のスケジュール、重要なストーリーの瞬間などの基盤レイヤーにはスクリプトされた振る舞いを使用します。動的な応答が最も価値を生む会話と記憶のレイヤーにはAIを使用します。

クエストに関わる重要なNPCは、物語の重要な場面にはスクリプト化されたセリフを持ち、それ以外にはAIによる応答を持つかもしれません。プレイヤーは進行に必要な情報を常に得られる一方で、質問をしてキャラクターとの関係を築く自由も手にできます。

はじめる

Summer EngineのRPGテンプレートには、カスタマイズ可能なAI NPCシステムが最初から用意されています。欲しいキャラクターを説明すれば、エンジンが個性、記憶、ゲーム世界の認識を備えてそれらを構築します。

AI NPC生成をもっと探りたい方は、AI NPCジェネレーターをチェックするか、Summer Engineをダウンロードして、最初のAI駆動キャラクターを作ってみてください。