現場レベルのゲーム制作が、すべてここで学べます。
この講座ではUnityを使って「箱庭経営シミュレーション×農園ゲーム」を作成していきます。
今回はその第9回目です。
前回はハエを追加して対処しないと畑が腐ってしまうようなハプニング要素を追加しました。
前回の記事:

第9回では、ゲームの効率化につながる「従業員システム」を実装していきます。
今回は以下の3種類の従業員を追加していきます。
- ハエを駆除する従業員
- 種植えを行う従業員
- 収穫して商品を陳列する従業員
一人で農園を経営するのは大変。そこで店員や従業員を雇うことであくせく働かなくても農園が発展していく。そんな仕組みをゲームに導入できるようにしていきます。
この章で作成したゲームに自律行動パターンAIを組み込むUnityスキルを手に入れましょう!
ハエを駆除する従業員を追加しよう
まずは、どんな処理を作るのかを整理しておきましょう。
この従業員は、以下のように行動します。
- ハエが発生しているのを検知
- スプレーを探しに行く
- スプレーを手に取る
- ハエの場所まで移動する
- スプレーで駆除する
このように「状況に応じて行動を変えるキャラクター」を作っていくのが今回のポイントです。
従業員オブジェクトを用意しよう
まずは、従業員として使うキャラクターをシーンに配置していきます。
今回は以前作成したCustomer(お客さん)のプレハブを改造して、従業員を作成していきます。
これにより、アニメーションなどを一から設定し直す手間を省くことができます。
プレハブとシーン上のオブジェクトの関係について
プレハブをシーンに配置すると、そのオブジェクトはプレハブとリンクした状態になります。
この状態で変更を加えると、その変更は「差分」として扱われ、元のプレハブとは別の設定を持つようになります。

つまり、シーン上で大きく改造した場合、そのオブジェクトは見た目や設定的にはほぼ別物になります。ただし完全に独立しているわけではなく、あくまで「プレハブをベースにした別バージョン」として扱われます。
Projectウィンドウから「Prefabs」フォルダを開き、「Customer」を見つけてください。
見つけたら、そのままHierarchyにドラッグ&ドロップします。

配置した「Customer」を選択し、Inspector上部から名前を「BugSprayEmployee」に変更しましょう。その後、Transformを以下のように設定します。

作成したいのはお客さんではなく従業員なので、「CustomerAgent」スクリプトは削除しておきましょう。Hierarchyで配置したオブジェクトを選択し、Inspectorに表示されている「CustomerAgent」コンポーネントを確認します。そのタブの上で右クリックをして「Remove Component」を選択し、削除してください。

このように「Removed」と表示が残っていても、削除できていないわけではありません。
これは元のプレハブと比べて、「このコンポーネントはシーン上で削除された」という差分が記録されているため、このような表示になっています。

最後に「Audio Source」を設定し、音が3D空間で聞こえるようにしておきましょう。

音の出方を空間的にし、キャラから離れると音量が減衰するように設定しました。
従業員を自律的に動かすスクリプトを作成しよう
次は従業員を自動で動かすための仕組みを作っていきます。
この従業員は、「今やるべきことは何か?」を毎フレーム判断しながら動くようにします。
従業員の思考は、次のような順番で作成していきます。
- ハエがいるか確認
→ いなければ待機 - ハエがいる
→ スプレーを持っているか確認 - 持っていない
→ スプレーを取りに行く - 持っている
→ ハエの場所へ移動 - 近づいたら
→ 駆除してスプレー消費
まずは、以前作成した「ItemBase」を継承した「BugSprayItem」に、従業員がスプレーを扱うための処理を追加していきます。
プレイヤーが使うだけであれば、スプレーは「使うと消費される道具」という役割だけでも十分でした。しかし今回は、従業員が自動でスプレーを見つけて持ち運び、使用する必要があります。
そのため、ただのアイテムのままでは足りず、
「持てる状態かどうか」
「今誰かが使おうとしているか」
「使用後に消費されたか」
といった、従業員側の行動と連動できる情報や処理を持たせる必要があります。
Projectウィンドウから Scripts フォルダを開き、BugSprayItem.cs を見つけたらダブルクリックして開きましょう。

開けたら、以下のマーカー部分を書き込んでください。
BugSprayItem.cs
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
using UnityEngine; public class BugSprayItem : ItemBase { [Header("スプレー設定")] [SerializeField] private float sprayDistance = 4f; public float SprayDistance => sprayDistance; [Header("従業員が持つ時に切り替えるレイヤー")] [SerializeField] private int reservedLayer = 2; public bool IsReserved { get; private set; } public bool IsConsumed { get; private set; } private Collider[] cols; private void Start() { cols = GetComponentsInChildren<Collider>(true); } public bool TryReserveAndPickUp(Transform holdPoint) { if (IsConsumed) return false; if (IsReserved) return false; if (transform.parent != null) return false; if (holdPoint == null) return false; IsReserved = true; // レイヤー変更 SetLayerRecursively(transform, reservedLayer); // 当たり判定を無効化 foreach (var c in cols) c.enabled = false; // 物理停止 if (rb != null) { rb.isKinematic = true; rb.linearVelocity = Vector3.zero; rb.angularVelocity = Vector3.zero; } // 手元へ固定 transform.SetParent(holdPoint, false); transform.localPosition = Vector3.zero; transform.localRotation = Quaternion.identity; return true; } public void Consume() { if (IsConsumed) return; IsConsumed = true; Destroy(gameObject); } private void SetLayerRecursively(Transform t, int layer) { t.gameObject.layer = layer; for (int i = 0; i < t.childCount; i++) { SetLayerRecursively(t.GetChild(i), layer); } } } |
スクリプトの解説
このスクリプトは、スプレーを「従業員が持って使えるアイテム」にするためのものです。
もともとのItemBaseの機能を引き継ぎつつ、従業員用の処理を追加しています。
従業員用の状態を持たせる部分
|
1 2 3 4 5 |
[Header("従業員が持つ時に切り替えるレイヤー")] [SerializeField] private int reservedLayer = 2; public bool IsReserved { get; private set; } public bool IsConsumed { get; private set; } |
ここでは、スプレーが今どんな状態なのかを管理しています。
IsReserved は、既に誰かがこのスプレーを使おうとしているかどうかを表します。
IsConsumed は、既に使われて消費されたかどうかを表します。
この情報を持たせることで、複数の従業員が同じスプレーを同時に取りに行ってしまうのを防げます。
最初に当たり判定を集めておく部分
|
1 2 3 4 5 6 |
private Collider[] cols; private void Start() { cols = GetComponentsInChildren<Collider>(true); } |
ここでは、スプレー本体や子オブジェクトについているColliderを最初にまとめて取得しています。
あとで従業員がスプレーを持ったとき、当たり判定をまとめてオフにするため、その準備をしているわけです。
スプレーを持つ処理
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
public bool TryReserveAndPickUp(Transform holdPoint) { if (IsConsumed) return false; if (IsReserved) return false; if (transform.parent != null) return false; if (holdPoint == null) return false; IsReserved = true; // レイヤー変更 SetLayerRecursively(transform, reservedLayer); // 当たり判定を無効化 foreach (var c in cols) c.enabled = false; // 物理停止 if (rb != null) { rb.isKinematic = true; rb.linearVelocity = Vector3.zero; rb.angularVelocity = Vector3.zero; } // 手元へ固定 transform.SetParent(holdPoint, false); transform.localPosition = Vector3.zero; transform.localRotation = Quaternion.identity; return true; } |
このメソッドが、このスクリプトの中心です。
「このスプレーを持てるか確認し、問題なければ実際に持たせる」という処理を行っています。
1.持てるか確認する
|
1 2 3 4 |
if (IsConsumed) return false; if (IsReserved) return false; if (transform.parent != null) return false; if (holdPoint == null) return false; |
ここでは、スプレーを持ってよい状態かを確認しています。
既に使われているもの、誰かが使おうとしているもの、誰かに持たれているものは使えません。
また、持たせる位置が設定されていない場合も処理を中止します。
2.予約状態にする
|
1 |
IsReserved = true; |
持てると判断できたら、このスプレーを予約状態にします。
これで他の従業員は、このスプレーを取りに来なくなります。
3.持った状態に切り替え
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// レイヤー変更 SetLayerRecursively(transform, reservedLayer); // 当たり判定を無効化 foreach (var c in cols) c.enabled = false; // 物理停止 if (rb != null) { rb.isKinematic = true; rb.linearVelocity = Vector3.zero; rb.angularVelocity = Vector3.zero; } // 手元へ固定 transform.SetParent(holdPoint, false); transform.localPosition = Vector3.zero; transform.localRotation = Quaternion.identity; return true; |
ここでは、スプレーを「地面に置かれたアイテム」から「従業員が手に持っているアイテム」へ切り替えています。
レイヤーを変更し、当たり判定を無効にし、物理の動きも止めています。
そのうえで、従業員の手である親オブジェクトスプレーを子オブジェクトとして登録し、位置と向きをぴったり合わせています。
つまりこの部分で、スプレーが自然に手に持たれた状態になります。
従業員のスクリプトを作成しよう
つぎに従業員のスクリプトを作成していきます。
Projectウィンドウから Scripts フォルダを開きます。
フォルダ内で右クリックし、Create > MonoBehaviour Scriptを選択してください。
新しく作成されたスクリプトの名前を「BugSprayEmployee」 に変更しましょう

作成できたら、そのスクリプトをダブルクリックで開き、以下の内容を書き込んでください。
まとめ

今回は、作業を自動で手伝ってくれる3種類の従業員を追加しました。
まず、ハエを退治してくれる従業員を作成しました。
この従業員はハエを見つけるとスプレーを取りに行き、ハエに近づいて自動で退治してくれます。
これにより、作物が腐ってしまう原因に自動で対応できるようになりました。
次に、種を植えてくれる従業員を作成しました。
この従業員はプレイヤーが持っている種を使って、空いている畑を探し、自動で種を植えてくれます。そのため、畑の管理を自分で行うことなく作業を効率化できます。
最後に、収穫して陳列してくれるショップ店員型の従業員を作成しました。
この従業員は収穫された作物を見つけて持ち上げ、空いている棚まで運んで陳列してくれます。
また、途中で動けなくなった場合や対象を持ち運べなくなった場合でも、状況に応じて別の作物を探し直すようになっているため、安定して作業を続けられます。
今回はハエの駆除、種まき、収穫物の陳列をそれぞれ担当するルールベース型のAIエージェント従業員を追加しました。
これによって農業とお店運営の流れをより自動化することができました。
プレイヤーの負担を減らしながら、ゲーム全体の動きもよりにぎやかで本格的なものになったと思います。
次回はいよいよ最終章です。
これまでに作成してきた仕組みをまとめて応用し、ゲームとして完成形へと仕上げていきましょう。
次の記事:
現場レベルのゲーム制作が、すべてここで学べます。






コメント