Unity 攻击槽系统教程之四 Enemy的槽位排列实现
1、攻击槽系统:
攻击槽系统通常相当简单,可以使战斗看起来更好。 基本上,他们的做法是为每个攻击者分配一个攻击位置,以便攻击者不受束缚,位置可以是围绕攻击者,或者正面排列面对玩家。 如果您一次只希望有一个攻击者,那这个系统就不会有任何帮助,但是有两个以上的攻击者这可能是一个非常有用的工具。
1、在场景中,拷贝多个 Enemy,运行场景,多个 Enemy 都围绕 Player 移动,具体如下图



2、在工程中,新建一个脚本 SlotManager,双击打开或右键“Open C# Project”进行编辑,具体如下图

3、SlotManager 脚本的具体代码和代码说明如下图




4、SlotManager 脚本的具体内容如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SlotManager : MonoBehaviour
{
//储存Enemy的槽列表,槽的个数以及Enemy与Player的距离
private List<GameObject> slots;
public int count = 6;
public float distance = 0.8f;
void Start()
{
///初始化槽列表,存储null
slots = new List<GameObject>();
for (int index = 0; index < count; ++index)
{
slots.Add(null);
}
}
/// <summary>
/// 获取对应索引操的位置
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public Vector3 GetSlotPosition(int index)
{
//每个操的角度间距,计算出槽相对Player的具体位置,并返回
float degreesPerIndex = 360f / count;
Vector3 pos = transform.position;
Vector3 offset = new Vector3(0f, 0f, distance);
return pos + (Quaternion.Euler(new Vector3(0f, degreesPerIndex * index, 0f)) * offset);
}
/// <summary>
/// 储存Enemy,并返回当前的槽位数
/// </summary>
/// <param name="attacker"></param>
/// <returns></returns>
public int Reserve(GameObject attacker)
{
//计算当前Enemy和Player的normalized * distance位置
Vector3 bestPosition = transform.position;
Vector3 offset = (attacker.transform.position - bestPosition).normalized * distance;
bestPosition += offset;
//初始化bestSlot和bestDist
int bestSlot = -1;
float bestDist = 99999f;
//遍历槽,把Enemy存到 对应空槽上
for (int index = 0; index < slots.Count; ++index)
{
if (slots[index] != null)
continue;
float dist = (GetSlotPosition(index) - bestPosition).sqrMagnitude;
if (dist < bestDist)
{
bestSlot = index;
bestDist = dist;
}
}
//把Enemy存到 对应空槽上,并返回当前槽位数
if (bestSlot != -1)
slots[bestSlot] = attacker;
return bestSlot;
}
/// <summary>
/// 释放槽上的Enemy
/// </summary>
/// <param name="slot"></param>
public void Release(int slot)
{
slots[slot] = null;
}
//在场景中画出Player周围的对应槽
void OnDrawGizmosSelected()
{
//遍历所有槽,根据是否为空槽,画出对应半径0.3f的WireSphere
for (int index = 0; index < count; ++index)
{
if (slots == null || slots.Count <= index || slots[index] == null)
Gizmos.color = Color.white;
else
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(GetSlotPosition(index), 0.3f);
}
}
}
5、更新 Enemy 脚本的内容,具体的代码好代码说明如下图


6、Enemy 脚本的具体内容如下:
using UnityEngine;
using UnityEngine.AI;
public class Enemy : MonoBehaviour
{
//追随目标设置和刷新位置事件介个设置
GameObject target = null;
float pathTime = 0f;
//槽位数初始化
int slot = -1;
// Use this for initialization
void Start()
{
//获取追随目标
target = GameObject.Find("Player");
}
// Update is called once per frame
void Update()
{
//每0.5秒刷新进入If分支
pathTime += Time.deltaTime;
if (pathTime > 0.5f)
{
pathTime = 0f;
//获得 SlotManager 脚本,为空怎不进入下面If分支
SlotManager slotManager = target.GetComponent<SlotManager>();
if (slotManager != null)
{
//存储获取槽位数
if (slot == -1)
slot = slotManager.Reserve(gameObject);
//如果没有槽了即返回
if (slot == -1)
return;
//获取 NvaMeshAgent,没有则返回,否则设置目标位置移动
var agent = GetComponent<NavMeshAgent>();
if (agent == null)
return;
agent.destination = slotManager.GetSlotPosition(slot);
}
}
}
}
7、脚本编译正确,回到Unity界面,把 SlotManager 脚本挂载到 Player 物体上,参数根据自己的建模和合理设置即可,具体如下图

8、运行场景,Enemy 跟随 Player 在槽位上围绕 Player,具体如下图


9、其中,在 Scene 中的 WireSphere,绘制如下图

10、到此,《Unity 攻击槽系统教程之四 Enemy的槽位排列实现》讲解结束,谢谢