Unity 攻击槽系统教程之四 Enemy的槽位排列实现

2025-10-25 10:43:07

1、攻击槽系统:

      攻击槽系统通常相当简单,可以使战斗看起来更好。 基本上,他们的做法是为每个攻击者分配一个攻击位置,以便攻击者不受束缚,位置可以是围绕攻击者,或者正面排列面对玩家。 如果您一次只希望有一个攻击者,那这个系统就不会有任何帮助,但是有两个以上的攻击者这可能是一个非常有用的工具。

1、在场景中,拷贝多个 Enemy,运行场景,多个 Enemy 都围绕 Player 移动,具体如下图

Unity 攻击槽系统教程之四 Enemy的槽位排列实现

Unity 攻击槽系统教程之四 Enemy的槽位排列实现

Unity 攻击槽系统教程之四 Enemy的槽位排列实现

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

Unity 攻击槽系统教程之四 Enemy的槽位排列实现

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

Unity 攻击槽系统教程之四 Enemy的槽位排列实现

Unity 攻击槽系统教程之四 Enemy的槽位排列实现

Unity 攻击槽系统教程之四 Enemy的槽位排列实现

Unity 攻击槽系统教程之四 Enemy的槽位排列实现

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 脚本的内容,具体的代码好代码说明如下图

Unity 攻击槽系统教程之四 Enemy的槽位排列实现

Unity 攻击槽系统教程之四 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 物体上,参数根据自己的建模和合理设置即可,具体如下图

Unity 攻击槽系统教程之四 Enemy的槽位排列实现

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

Unity 攻击槽系统教程之四 Enemy的槽位排列实现

Unity 攻击槽系统教程之四 Enemy的槽位排列实现

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

Unity 攻击槽系统教程之四 Enemy的槽位排列实现

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

声明:本网站引用、摘录或转载内容仅供网站访问者交流或参考,不代表本站立场,如存在版权或非法内容,请联系站长删除,联系邮箱:site.kefu@qq.com。
猜你喜欢