15. プレハブ
15.1 プレハブの作成手順
プレハブとは、元ファイルのようなものです。元ファイルから複製を作成し、元ファイルの変更を複製先に反映させることができます。複製したものから元ファイルに反映させることもできます。Unity2018.3からプレハブ機能が変わりました。
プレハブの作成はヒエラルキーからゲームオブジェクトをドラッグして、Projectにドロップしますが、UEと比較するため、作成を手順に分けます。例えば、猫は次に説明するNested Prefabsで追加することにして、先に猫を飼っている飼い主(Master)オブジェクトのプレハブを作成します。
1) 飼い主のfbxをインポートします。
personajes low poly02_fbx_Collection_2.fbxをUnityのProjectタブのAssetsフォルダにインポートします。
飼い主のアニメーションをループするように設定します。
Assetsフォルダのpersonajes low poly02_fbx_Collection_2をクリックして、InspectorタブのAnimationをクリックします。
ClipsのArmature.001|Armature.001Actionを選択します。
InspectorのArmature.001|Armature.001Actionに関するInspectorが見えるところまでスクロールします。
Loop Timeをチェックします。
Saveします。
これでpersonajes low poly02_fbx_Collection_2のArmature.001|Armature.001Actionについてのアニメーションがループできるようになります。
2) インポートしたモデルの名前をMasterにして、Hierarchyにドラッグ&ドロップします。
MasterをProjectフォルダにドラッグドロップしてプレハブを作成します。名前はMasterにします。このときMasterのfbxモデルとプレハブファイルは区別されますので、同じ名前でも大丈夫です。
HierarchyにあるMasterはプレハブに変更されます。
3) 徘徊するMasterWanderコンポーネントのスクリプトを作成します。
using UnityEngine;
public class MasterWander : MonoBehaviour
{
public float speed = 3.0f;
public float rotationSpeed = 2.0f;
public float wanderRadius = 2.0f;
public float wanderDistance = 5.0f;
public float wanderJitter = 1.0f;
private Vector3 wanderTarget;
void Start()
{
wanderTarget = transform.position + Random.insideUnitSphere * wanderRadius;
wanderTarget.y = transform.position.y; // Y軸は固定
}
void Update()
{
WanderBehavior();
}
void WanderBehavior()
{
// ランダムな方向に少しずつターゲットを移動
Vector3 randomPoint = Random.insideUnitSphere * wanderJitter;
randomPoint.y = 0; // Y軸は固定
wanderTarget += randomPoint;
wanderTarget = wanderTarget.normalized * wanderRadius;
// 前方にターゲットをオフセット
Vector3 targetPosition = transform.position + transform.forward * wanderDistance + wanderTarget;
targetPosition.y = transform.position.y;
// 目的地の方向に回転
Vector3 direction = (targetPosition - transform.position).normalized;
Quaternion targetRotation = Quaternion.LookRotation(direction);
transform.rotation = Quaternion.Slerp( transform.rotation,
targetRotation,
rotationSpeed * Time.deltaTime);
// 前進
transform.position += transform.forward * speed * Time.deltaTime;
}
}
4) ProjectフォルダにあるMasterプレハブを選択してMasterWanderコンポーネントを追加します。
5) アニメーションの実行を簡素化するためにSimpleAnimationコンポーネントを使います。SimpleAnimationコンポーネントはUnityから提供されていますが、Unity標準では搭載されていないのでGithubから入手します。SimpleAnimationコンポーネントについては次の章でも使いますが、ここではインストールの方法とMaster GameObjectに追加する方法を紹介します。
インストール方法は、以下のGithubからzipをダウンロードします。
解凍してから、SimpleAnimation-master\Assets\SimpleAnimationComponent
のSimpleAnimationComponentフォルダ以下すべてをプロジェクトウィンドウにコピーペーストします。
コピーペーストをすると以下のウィンドウが表示された場合は、「Yes, just for there files」をクリックします。
Unityに戻りplayer(GameObject)に以下のようにSimpleAnimationコンポーネントを追加します。SimpleAnimationコンポーネントを追加すると自動的にAnimatorコンポーネントも追加されます。AnimatorコンポーネントのControllerとAvaterには何も登録しなくても大丈夫です。
- Master(GameObject)
- SpriteRendererコンポーネント
- Animatorコンポーネントが追加される
- SimpleAnimationコンポーネントを追加
SimpleAnimationコンポーネントのAnimationにArmature.001|Armature.001Actionを追加します。
Masterを進行方向に向かせます。Masterプレハブを選択して、Masterの子masterを選択します。
masterのRotation Zを180に設定します。
この状態でplayすると、Masterが歩くアニメーションをしながら徘徊することが確認できます。
6) 決められた半径内の円のなかでランダムにMasterを複製するMasterControllerコンポーネントのスクリプトを作成します。
using UnityEngine;
public class MasterController : MonoBehaviour
{
public GameObject masterSpawn; // 作成するゲームオブジェクト
public int numberOfObjects = 10; // 作成するオブジェクトの個数
public float radius = 5f; // 半径
void Start()
{
SpawnObjects();
}
void SpawnObjects()
{
for (int i = 0; i < numberOfObjects; i++)
{
// ランダムな位置を決める
Vector3 randomPosition = transform.position + (Random.insideUnitSphere * radius);
randomPosition.y = 0;
// 指定された位置にオブジェクトを生成
Instantiate(masterSpawn, randomPosition, Quaternion.identity);
}
}
}
7) HierarhyにEmpty GameObjectを作成します。名前はMasterControllerにします。Transformコンポーネントをリセットしておいて、Positionを0,0,0にしておきます。
MasterControllerコンポーネントを追加します。Master SpawnにMasterプレハブを追加します。
Master ControllerコンポーネントはMasterを使って指定した主人の数の分だけMasterを作成して、その辺を歩くようにします。
15.2 プレハブの親子関係 Nested Prefabs
Nested Prefabの歴史を説明します。Unity2018.3から導入されたNested PrefabはUnityの歴史において比較的新しい機能です。Nested Prefabの登場前までは、プレハブにプレハブを埋め込むことはできず、プレハブの階層の下に配置したオブジェクトは、保存する際に強制的に一体化されるため、一つの大きいプレハブとして管理するしかありませんでした。
Nested Prefabやそれに伴って導入されたPrefab Variantの機能はプレハブのワークフローに柔軟性をもたらす半面、機能の複雑化にもつながっています。機能の性質を理解したうえで、ネストしすぎないように気を付ける、プロパティをオーバーライドしすぎないなど、その構造を常にシンプルに保つこと。
飼い主の飼っているいかをNested Prefabsで追加します。
1) いかのfbxをインポートします。
Inkfish_Animations.fbxをUnityのProjectタブのAssetsフォルダにインポートします。
続けてTextureフォルダからT_Inkfish.pngをInkfish_Animations.fbxをAssetsフォルダと同じところにインポートします。
InkfishのモデルにTextureが追加されます。
いかのアニメーションをループするように設定します。
AssetsフォルダのInkfish_Animationsをクリックして、InspectorタブのAnimationをクリックします。
ClipsのIdle_Aを選択します。
InspectorのIdle_Aに関するInspectorが見えるところまでスクロールして、Loop Timeにチェックが入っていることを確認します。
これでInkfishのIdle_Aについてのアニメーションがループできるようになります。
2) インポートしたモデルの名前をInkfishにして、Hierarchyにドラッグ&ドロップします。
InkfishをProjectフォルダにドラッグドロップしてプレハブを作成します。名前はInkfishにします。このときInkfishのfbxモデルとプレハブファイルは区別されますので、同じ名前でも大丈夫です。
HierarchyにあるInkfishはプレハブに変更されます。
3) ProjectフォルダにあるInkfishプレハブにSimpleAnimationコンポーネントを追加します。
- Inkfish(GameObject)
- Animatorコンポーネントが追加される
- SimpleAnimationコンポーネントを追加
SimpleAnimationコンポーネントのAnimationにIdle_Aを追加します。
この状態でplayすると、InkfishがIdleのアニメーションをしながら確認できます。
4) ペットが飼い主に追従するFollowMasterコンポーネントのスクリプトを作成します。
using UnityEngine;
public class FollowMaster : MonoBehaviour
{
private Transform masterTransform;
[SerializeField] private float followDistance = 2.0f;
[SerializeField] private float speed = 5.0f;
[SerializeField] private float rotationSpeed = 5.0f;
public float wanderJitter = 1.0f;
public float wanderRadius = 2.0f;
public float wanderDistance = 5.0f;
private Vector3 wanderTarget;
private void Update()
{
if (transform.parent != null)
{
Vector3 randomPoint = Random.insideUnitSphere * wanderJitter;
randomPoint.y = 0; // Y軸は固定
wanderTarget += randomPoint;
wanderTarget = wanderTarget.normalized * wanderRadius;
// 前方にターゲットをオフセット
masterTransform = transform.parent;
// リーダーの背後をターゲットにする
Vector3 targetPosition = masterTransform.position - masterTransform.forward * followDistance + wanderTarget;
transform.position = Vector3.Lerp(transform.position, targetPosition, speed * Time.deltaTime);
// リーダーの向きに合わせて回転
Quaternion targetRotation = Quaternion.LookRotation(masterTransform.position - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
}
}
}
5) InkfishプレハブにFollowMasterコンポーネントを追加します。
6) MasterプレハブにInkfishプレハブを追加します。
追加方法は、HierarchyでInkfishを選択してドラッグして、Masterにドロップします。
7) Playして、すべてのMasterにInkfishが付いていることを確認します。
15.3 プレハブの派生 Prefab Variants
プレハブの派生の例として、以下の手順で作成していきます。
猫の飼い主に加えて、犬の飼い主を追加するケースを考えます。
1) へびのfbxをインポートします。
Taipan_Animations.fbxをUnityのProjectタブのAssetsフォルダにインポートします。
続けてTextureフォルダからT_Taipan.pngをTaipan_Animations.fbxをAssetsフォルダと同じところにインポートします。
へびのアニメーションをループするように設定します。
AssetsフォルダのTaipan_Animationsをクリックして、InspectorタブのAnimationをクリックします。
ClipsのIdle_Aを選択します。
InspectorのIdle_Aに関するInspectorが見えるところまでスクロールして、Loop Timeにチェックが入っていることを確認します。
これでTaipanのIdle_Aについてのアニメーションがループできるようになります。親子関係で紹介しました手順とは異なり、派生元の抽象クラスを作成してからPrefab Variant用のプレハブを作成するので、モデルの準備はここまでになります。
2) いかとへびの派生元になるペットという抽象クラスを作成します。
抽象クラスと言っても作り方は簡単で、先ほどプレハブの親子完成で作成したFollowMasterbコンポーネントを追加したEmptyObjectを作成して、名前をPetにします。
Petのプレハブを作成します。
ProjectフォルダのPetのプレハブを選択した状態で、右クリック > Create > Prefab Variantを選択します。
名前をInkfish_Variantにします。
Inkfish_Variantをダブルクリックしてプレハブモードの画面が表示されたら、HierarchyにインポートしたInkfishをドラッグドロップします。
Inkfish_Variantの子にあるInkfishのGameObjectを選択した状態で、InkfishのInspectorに、SimpleAnimationを追加します。
SimpleAnimationコンポーネントのAnimationは、プレハブの親子関係でInkfishのGameObjectと同じIdle_Aアニメーションを指定します。
もう一度ProjectフォルダのPetのプレハブを選択した状態で、右クリック > Create > Prefab Variantを選択します。
名前をSnake_Variantにします。
Snake_Variantをダブルクリックしてプレハブモードの画面が表示されたら、HierarchyにインポートしたSnakeをドラッグドロップします。
Snake_VariantのGameObjectを選択した状態で、Snake_VariantのInspectorに、SimpleAnimationを追加します。
SimpleAnimationコンポーネントのAnimationは、プレハブの親子関係でInkfishのGameObjectと同じIdle_Aアニメーションを指定します。
3) Inkfishを飼っているMasterとSnakeを飼っているMasterを作成します。
最初にMasterのプレハブを作成します。プレハブの親子関係で作成したMasterの子にInkfishが追加されている場合は一旦削除してから、プレハブを作成します。
ProjectフォルダのMasterのプレハブを選択した状態で、右クリック > Create > Prefab Variantを選択してMasterのPrefab Variantを作成します。名前をMaster_Inkfishにします。
Master_Inkfishプレハブをダブルクリックして、プレハブモードでMaster_Inkfishを開いて、Inkfish_Variantを追加します。
ProjectフォルダのMasterのプレハブを選択した状態で、右クリック > Create > Prefab Variantを選択してMasterのPrefab Variantを作成します。名前をMaster_Snakeにします。
Master_Snakeプレハブをダブルクリックして、プレハブモードでMaster_Snakeを開いて、Snake_Variantを追加します。
4) Snakeを連れている飼い主Masterも表示できるようにMasterControllerに処理を追加します。
using UnityEngine;
public class MasterController2 : MonoBehaviour
{
public GameObject masterSpawnA; // 1つ目のゲームオブジェクト
public GameObject masterSpawnB; // 2つ目のゲームオブジェクト
public int numberOfObjects = 10; // 作成する合計オブジェクト数
public float radius = 5f; // 生成する範囲の半径
void Start()
{
SpawnObjects();
}
void SpawnObjects()
{
int halfObjects = numberOfObjects / 2; // 均等に分割
for (int i = 0; i < halfObjects; i++)
{
SpawnRandomObject(masterSpawnA);
SpawnRandomObject(masterSpawnB);
}
// 奇数の場合、どちらか一方を追加
if (numberOfObjects % 2 != 0)
{
SpawnRandomObject(Random.value > 0.5f ? masterSpawnA : masterSpawnB);
}
}
void SpawnRandomObject(GameObject obj)
{
Vector3 randomPosition = transform.position + (Random.insideUnitSphere * radius);
randomPosition.y = transform.position.y; // 高さを固定する(地面に配置する場合)
Instantiate(obj, randomPosition, Quaternion.identity);
}
}
5) Playして、Inkfishを連れている飼い主MasterとSnakeを連れている飼い主Masterが作成されていることを確認します。
Petに追加したFollowMasterコンポーネントスクリプトに変数を追加すると、Prefab Variantで作成したプレハブに反映されていることがわかります。
Prefab Variantの機能の紹介はここまでにします。Prefab Variantのより詳しい機能の解説や学習はMake A Gameサイトのプレハブのページで紹介されていますので、そちらをご参照ください。
プレハブで紹介したWanderとFollowはCraig W. Reynolds氏の「Steering Behavior」という考えに基づいて記述しています。特にWanderの考え方はとても興味深い内容ですので、是非一読することをお勧めします。
🔗 参考リンク
Steering Behaviors For Autonomous Characters
自分の場合は、Craig W. Reynolds氏の論文を読んでもコーディングに落とし込む方法が分からなかったので、Unityで解説されている以下のサイトで勉強しましたので、こちらも紹介します。
🔗 参考リンク
The Nature of Code Remixed for Unity
Chapter 6. Autonomous Agents