我的游戏中有很多不同类型的 NPC,当然它们在逻辑上相似,它们有健康、有远见、可以使用代理和其他东西导航。
但是每种 NPC 类型都有自己的自定义行为,包括状态、动作、决策和钩子。这些脚本需要各种特定的数据,如协程运行、目标高度或当前跳跃方向。
而且我必须将其存储或保存在 NPC 单声道行为中,因此可以在状态脚本中访问它(它们是从 NPC 单声道行为调用的可编写脚本的对象)
现在我所做的是为每种数据类型指定数组,并在 NPC 预制件上分配它的计数。而且感觉不对...
public class Npc : MonoBehaviour
{
public static Dictionary<int, Npc> npcs = new Dictionary<int, Npc>();
public int npcId;
public NpcType type;
public Transform shootOrigin;
public Transform head;
public float maxHealth = 50f;
public float visionRange = 15;
public float visionAngle = 60;
public float headAngle = 120;
public float movementSpeed = 4.5f;
public int indexedActionsCount = 0;
[HideInInspector] public float[] lastActTimeIndexed;
[HideInInspector] public bool[] wasActionCompletedIndexed;
public int indexedVector3DataCount = 0;
[HideInInspector] public Vector3[] vector3DataIndexed;
public int indexedFloatDataCount = 0;
[HideInInspector] public float[] floatDataIndexed;
public int indexedBoolDataCount = 0;
[HideInInspector] public bool[] boolDataIndexed;
public int indexedCoroutineDataCount = 0;
[HideInInspector] public IEnumerator[] coroutineDataIndexed;
public NpcState currentState;
public NpcState remainState;
public float Health { get; private set; }
[HideInInspector] public NavMeshAgent agent;
public static int decisionUpdatesPerSecond = 2; // Check for decisions in 2FPS
public static int actionUpdatesPerSecond = 5; // Act in 5FPS
public static int reportUpdatesPerSecond = 15; // Report in 15FPS
private static int nextNpcId = 10000;
public void Awake()
{
agent = GetComponent<NavMeshAgent>();
}
public void Start()
{
npcId = nextNpcId;
nextNpcId++;
npcs.Add(npcId, this);
Health = maxHealth;
agent.speed = movementSpeed;
lastActTimeIndexed = new float[indexedActionsCount];
wasActionCompletedIndexed = new bool[indexedActionsCount];
floatDataIndexed = new float[indexedFloatDataCount];
boolDataIndexed = new bool[indexedBoolDataCount];
vector3DataIndexed = new Vector3[indexedVector3DataCount];
coroutineDataIndexed = new IEnumerator[indexedCoroutineDataCount];
ServerSend.SpawnNpc(npcId, type, transform.position);
InvokeRepeating("GetTarget", 1.0f, 1.0f);
InvokeRepeating("UpdateDecisions", 0.0f, 1.0f / decisionUpdatesPerSecond);
InvokeRepeating("UpdateActions", 0.0f, 1.0f / actionUpdatesPerSecond);
InvokeRepeating("SendUpdates", 0.0f, 1.0f / reportUpdatesPerSecond);
OnEnterState();
}
public void TakeDamage(float _damage)
{
}
public bool GoTo(Vector3 location)
{
}
public void TransitionToState(NpcState nextState)
{
OnExitState();
currentState = nextState;
OnEnterState();
}
public void StartCoroutineOnNpc(IEnumerator routine)
{
StartCoroutine(routine);
}
public void StopCoroutineOnNpc(IEnumerator routine)
{
StopCoroutine(routine);
}
private void OnEnterState()
{
var hooks = currentState.onEnterHooks;
for (int i = 0; i < hooks.Length; i++)
{
hooks[i].Apply(this);
}
stateTimeOnEnter = Time.time;
wasActionCompleted = false;
}
private void OnExitState()
{
var hooks = currentState.onExitHooks;
for (int i = 0; i < hooks.Length; i++)
{
hooks[i].Apply(this);
}
}
private void UpdateDecisions()
{
currentState.UpdateDecisions(this);
}
private void UpdateActions()
{
currentState.UpdateState(this);
}
private void SendUpdates()
{
ServerSend.NpcState(this);
}
}
在 JavaScript 世界中,我将只有 1 个数组或对象,并将该特定 NPC 需要的任何数据放入其中。但是在 C# 中,我需要一个强类型的地方来放置我的脚本可能需要的每种数据类型的数据。
脚本中的数据使用示例:
我不认为在 MonoBehavior 上有这么多数组和计数器是一个好主意,尤其是现场可能有很多 NPC。在保持脚本灵活性的同时构建更好的存储有什么建议吗?
澄清: 所有行为逻辑都由灵活的ScriptableObject状态控制。问题是这些对象不能存储任何运行时数据,但它们可以访问我的 Npc MonoBehavior(组件)实例。
这种方法的初始代码来自Unity 教程