Flyweightパターンを使って、敵のオブジェクトを登録管理してみました。敵を取得するときにすでにインスタンスがあれば新規作成しません。
まず敵のプレハブを3種類作って全てに同じスクリプトを付けました。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class TestAgent : MonoBehaviour
{
NavMeshAgent agent;
// Start is called before the first frame update
void Start()
{
agent = GetComponent<NavMeshAgent>();
GoNextPoint();
}
// Update is called once per frame
void Update()
{
if (!agent.pathPending && agent.remainingDistance < 0.5f)
{
GoNextPoint();
}
}
// 次の目的地を設定
void GoNextPoint()
{
agent.destination = TestAgentFactory.GetInstance().GetRandomPoint().position;
}
// 大きくなる
public void Bigger()
{
Vector3 scale = transform.localScale;
scale *= 2f;
transform.localScale = scale;
}
// 小さくなる
public void Smaller()
{
Vector3 scale = transform.localScale;
scale *= 0.5f;
transform.localScale = scale;
}
}
敵は常に徘徊していて、目的地は管理クラスからランダムに取得します。スケールを変えるメソッドも作りました。
床に小さなCubeをいくつか置いてそれを一つの空のゲームオブジェクトの子にします。敵はこれらを目指します。
管理クラスにこのルートのオブジェクトと敵のプレハブをアタッチします。
管理クラスのインスタンスは静的メソッドで取得できます。敵を取得するメソッドが呼ばれると、辞書にあるか調べて、なければプレハブをインスタンス化して返します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestAgentFactory : MonoBehaviour
{
static TestAgentFactory instance;
public static TestAgentFactory GetInstance()
{
return instance;
}
[SerializeField] Transform points;
[SerializeField] TestAgent spherePrefab;
[SerializeField] TestAgent cubePrefab;
[SerializeField] TestAgent capsulePrefab;
Dictionary<string, TestAgent> agents = new Dictionary<string, TestAgent>();
private void Awake()
{
instance = this;
}
// 目的地をランダムで返す
public Transform GetRandomPoint()
{
return points.GetChild(Random.Range(0, points.childCount));
}
public TestAgent GetAgent(string agentName)
{
// すでにあるとき
if(agents.ContainsKey(agentName))
{
// 辞書にあるものを返す
return agents[agentName];
}
// 無い時
else
{
TestAgent agentPrefab;
// プレハブを選択
switch(agentName)
{
case "sphere":
case "Sphere":
agentPrefab = spherePrefab;
break;
case "cube":
case "Cube":
agentPrefab = cubePrefab;
break;
case "capsule":
case "Capsule":
agentPrefab = capsulePrefab;
break;
default:
return null;
}
// 出現ポイントをランダムで選ぶ
Transform point = GetRandomPoint();
// インスタンス化
TestAgent testAgent = Instantiate(agentPrefab.gameObject, point.position, point.rotation).GetComponent<TestAgent>();
// 辞書に登録
agents.Add(agentName, testAgent);
// 返す
return testAgent;
}
}
}
このメソッドで敵を取得して、敵のスケールを変えるメソッドを呼ぶと、敵の登録が無いときはスケールが変わる前にインスタンス化され辞書に登録されます。あるときはシーン上のインスタンスのスケールが変わります。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameScript2 : MonoBehaviour
{
// Update is called once per frame
void Update()
{
if(Input.GetKey(KeyCode.Alpha1))
{
if(Input.GetKeyDown(KeyCode.UpArrow))
{
TestAgentFactory.GetInstance().GetAgent("Sphere").Bigger();
}
else if (Input.GetKeyDown(KeyCode.DownArrow))
{
TestAgentFactory.GetInstance().GetAgent("Sphere").Smaller();
}
}
else if (Input.GetKey(KeyCode.Alpha2))
{
if (Input.GetKeyDown(KeyCode.UpArrow))
{
TestAgentFactory.GetInstance().GetAgent("Cube").Bigger();
}
else if (Input.GetKeyDown(KeyCode.DownArrow))
{
TestAgentFactory.GetInstance().GetAgent("Cube").Smaller();
}
}
else if (Input.GetKey(KeyCode.Alpha3))
{
if (Input.GetKeyDown(KeyCode.UpArrow))
{
TestAgentFactory.GetInstance().GetAgent("Capsule").Bigger();
}
else if (Input.GetKeyDown(KeyCode.DownArrow))
{
TestAgentFactory.GetInstance().GetAgent("Capsule").Smaller();
}
}
}
}