Unityで「自律的に生活するAI」を作るための、C#コードのサンプル
このシステムは、拡張性を考えて以下の2つのスクリプトに分かれています。
SmartObject.cs: 家具につけるスクリプト(「これはベッドで、体力が回復する」という情報を定義)。HumanLifeAI.cs: 人間につけるスクリプト(欲求を管理し、適切な家具を探して行動する)。
そのままコピペして動作確認ができるように設計しています。
1. 家具用スクリプト (SmartObject.cs)
まず、家具が「何の欲求を満たすか」を定義するスクリプトを作成します。
C#
using UnityEngine;
// 欲求の種類を定義
public enum NeedType
{
None,
Hunger, // 空腹
Energy, // 体力
Fun // 娯楽
}
public class SmartObject : MonoBehaviour
{
[Header("家具の設定")]
public string objectName = "Furniture"; // 家具の名前
public NeedType needType; // 回復する欲求の種類
public float recoveryAmount = 50f; // 回復量
public float interactionTime = 3f; // 行動にかかる時間(秒)
// AIが家具を使うための立ち位置(設定なければ家具の位置)
public Vector3 GetInteractionPosition()
{
return transform.position;
}
}
2. AI用スクリプト (HumanLifeAI.cs)
次に、AIの頭脳となるスクリプトです。NavMeshAgentを使って移動し、欲求に応じて行動を決定します。
C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using System.Linq; // リスト操作用
public class HumanLifeAI : MonoBehaviour
{
[Header("欲求パラメータ (0-100)")]
public float hunger = 100f;
public float energy = 100f;
public float fun = 100f;
[Header("減衰スピード")]
public float hungerDecay = 5f; // 1秒ごとに減る量
public float energyDecay = 2f;
public float funDecay = 3f;
// 内部状態
private NavMeshAgent agent;
private bool isBusy = false; // 行動中かどうか
void Start()
{
agent = GetComponent<NavMeshAgent>();
}
void Update()
{
// 1. 時間経過で欲求を減らす
DecreaseNeeds();
// 2. 行動中でなければ、次の行動を決める
if (!isBusy)
{
ThinkAndAct();
}
}
// --- 思考ルーチン ---
void ThinkAndAct()
{
// 優先順位: お腹 -> 眠気 -> 暇つぶし -> うろうろ
if (hunger < 30)
{
FindAndInteract(NeedType.Hunger);
}
else if (energy < 20)
{
FindAndInteract(NeedType.Energy);
}
else if (fun < 40)
{
FindAndInteract(NeedType.Fun);
}
else
{
// 特に不満がなければランダムに歩き回る
Wander();
}
}
// --- 行動ロジック ---
void FindAndInteract(NeedType type)
{
// シーン内の全てのSmartObjectを探す
SmartObject[] allObjects = FindObjectsOfType<SmartObject>();
// 求めている欲求タイプに一致する家具だけを抽出
var targetObjects = allObjects.Where(obj => obj.needType == type).ToList();
if (targetObjects.Count > 0)
{
// 一番近い家具を探す(簡易版)
SmartObject nearest = targetObjects[0];
float minDist = Vector3.Distance(transform.position, nearest.transform.position);
foreach (var obj in targetObjects)
{
float dist = Vector3.Distance(transform.position, obj.transform.position);
if (dist < minDist)
{
minDist = dist;
nearest = obj;
}
}
// 行動コルーチンを開始
StartCoroutine(ExecuteAction(nearest));
}
else
{
Debug.LogWarning($"タイプ {type} の家具が見つかりません!");
Wander(); // 家具がないならとりあえず歩く
}
}
// 家具を使う一連の流れ(移動 -> 待機 -> 回復)
IEnumerator ExecuteAction(SmartObject target)
{
isBusy = true; // 他の思考を停止
Debug.Log($"{target.objectName} に向かいます...");
// 移動開始
agent.SetDestination(target.GetInteractionPosition());
// 到着を待つ
while (agent.pathPending || agent.remainingDistance > agent.stoppingDistance)
{
yield return null;
}
Debug.Log($"{target.objectName} を使用中...");
// ここでアニメーション再生を入れると良い (例: anim.SetTrigger("Eat"))
// 行動時間分待つ
yield return new WaitForSeconds(target.interactionTime);
// 欲求を回復
RestoreNeed(target.needType, target.recoveryAmount);
Debug.Log($"{target.objectName} の使用完了!");
isBusy = false; // 思考再開
}
void RestoreNeed(NeedType type, float amount)
{
switch (type)
{
case NeedType.Hunger: hunger = Mathf.Clamp(hunger + amount, 0, 100); break;
case NeedType.Energy: energy = Mathf.Clamp(energy + amount, 0, 100); break;
case NeedType.Fun: fun = Mathf.Clamp(fun + amount, 0, 100); break;
}
}
void Wander()
{
// まだ移動中なら何もしない
if (agent.remainingDistance > agent.stoppingDistance) return;
// ランダムな地点へ移動
Vector3 randomDirection = Random.insideUnitSphere * 5f; // 半径5m以内
randomDirection += transform.position;
NavMeshHit hit;
if (NavMesh.SamplePosition(randomDirection, out hit, 5f, 1))
{
agent.SetDestination(hit.position);
}
}
void DecreaseNeeds()
{
hunger -= hungerDecay * Time.deltaTime;
energy -= energyDecay * Time.deltaTime;
fun -= funDecay * Time.deltaTime;
}
}
3. Unityエディタでのセットアップ手順
このコードを実際に動かすための手順です。
- NavMeshの準備:
- 床(Plane)と壁(Cube)を配置し、Inspector右上の
Staticにチェックを入れる。 - Window > AI > Navigation を開き、
Bakeタブで Bake ボタンを押す(青いメッシュが表示されればOK)。
- 床(Plane)と壁(Cube)を配置し、Inspector右上の
追加:Unityのバージョンが新しい場合(2022.2以降など)、これまでの「NavigationウィンドウでBakeする」という機能は非推奨(古いやり方)になり、画面構成が変わっている可能性が高いです。
現在のUnityの標準である「NavMeshSurface」コンポーネントを使った、新しいBakeの方法を解説します。こちらのほうが便利でトラブルも少ないです。
新しいBakeの手順 (AI Navigation パッケージ)
「ウィンドウ」ではなく、シーン上の「部品(コンポーネント)」としてNavMeshを管理します。
1. 必要なパッケージを入れる
まず、新しい機能が有効になっているか確認します。
- メニューバーの
Window>Package Managerを開く。 - 左上のドロップダウンを
Packages: Unity Registryにする。 - リストから
AI Navigationを探して選択。 - 右下の Install ボタンを押す(すでにInstalledならそのままでOK)。
2. NavMeshSurface を作る
これからは「Bakeボタン」をInspector上に作ります。
- Hierarchyで何もないところを右クリック >
Create Emptyで空のオブジェクトを作成。 - 名前を
NavMeshManagerなどに変更。 - Inspectorで
Add Componentを押し、NavMeshSurfaceと検索して追加します。
3. 設定して Bake する
追加された NavMeshSurface コンポーネントを見てください。
- Agent Type:
Humanoidになっているか確認。 - Collect Objects:
All Game Objects(シーン全体)になっているか確認。- ※これで、Staticにチェックを入れていない家具や床も含めて、すべてのColliderを自動で認識してくれます(Static設定が不要になり、非常に楽です)。
- 下にある
Bakeボタンを押します。
これでシーンビューを見ると、青いメッシュ(NavMesh)が生成されているはずです。
- 家具の配置:
- Cubeをいくつか作り、「冷蔵庫」「ベッド」「テレビ」に見立てる。
- それぞれのCubeに
SmartObject.csをアタッチする。 - 設定例:
- 冷蔵庫: Need Type =
Hunger, Recovery = 50 - ベッド: Need Type =
Energy, Recovery = 100, Time = 5 - テレビ: Need Type =
Fun, Recovery = 30
- 冷蔵庫: Need Type =
- 人間の配置:
- Capsuleなどのオブジェクトを作成。
NavMeshAgentコンポーネントを追加。HumanLifeAI.csコンポーネントを追加。
- 実行:
- Playボタンを押します。
- Sceneビューで見ていると、人間(Capsule)がお腹が減ったら冷蔵庫へ、体力が減ったらベッドへ自動で移動し、生活を始めます。
- Inspectorで
HumanLifeAIのパラメータ(Hungerなど)をスライダーでいじってみてください。AIが即座に反応します。

