Unity behavior tree node development-melee target detection control

Shown below Unity 行为树节点开发——近战目标检测控制.

using System;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using MR_LBS.Client.Unity3D;
using Pathfinding;
using MR_LBS.Common;


namespace BehaviorDesigner.Runtime.Tasks.Movement
{
    
    
    [TaskDescription("Check to see if the any objects are within sight of the agent.")]
    [TaskCategory("GC_CL")]
    [TaskIcon("Assets/MR_LBS/Behavior Designer Movement/Editor/Icons/{SkinColor}CanSeeObjectIcon.png")]
    public class CanFindObject_Short : Conditional
    {
    
    
        public SharedLayerMask objectLayerMask;

        public SharedFloat checkDistance;//skillD攻击距离/初始距离

        public float atkDistance;//当前攻击距离

        public SharedGameObject returnedObject;
        /// <summary>
        /// 当前宠物即将释放的下一个技能
        /// </summary>
        public SharedAnimalState stateNext;

        [Tooltip("如果为真,则是 seek 模式,如果为假,则是攻击模式")]
        public bool IsSeek;

        /// <summary>
        /// 是否移除 跟自己不一样标签的结果
        /// </summary>
        public bool IfRemoveTag = false;

        /// <summary>
        /// Agent 身上的碰撞体
        /// </summary>
        CapsuleCollider collider;

        /// <summary>
        /// 物理检测的中心点
        /// </summary>
        Vector3 centerPos;

        /// <summary>
        /// 行为树
        /// </summary>
        BehaviorTree tree;

        /// <summary>
        /// 攻击模型下是否有上一个目标
        /// </summary>
        private bool hasTarget;

        /// <summary>
        /// 物理检测返回的碰撞体数组
        /// </summary>
        Collider[] hitColliders;

        /// <summary>
        /// 上一次攻击的目标
        /// </summary>
        private Collider lastTarget;

        private MonsterControlBase control;

        public override void OnAwake()
        {
    
    
            collider = this.gameObject.GetComponent<CapsuleCollider>();
            tree = this.gameObject.GetComponent<BehaviorTree>();
        }

        public override void OnStart()
        {
    
    
            //每次检查目标之前需要将上一次的结果清空
            hitColliders = null;
            //中心点是值类型,需要重新获取
            centerPos = transform.TransformPoint(collider.center);
            //不同技能拥有不同攻击距离
            //普攻使用控制器中的距离
            if (stateNext != null && stateNext.Value != MonsterState.SkillD)
            {
    
    
                control = gameObject.GetComponentInPorC<MonsterControlBase>();
                //float getDistance = 0;
                //非普攻使用shootRange
                switch (stateNext.Value)
                {
    
    
                    case MonsterState.SkillC:
                        atkDistance = (float)control.Monster_P.SkillC.ShootRange;
                        //Debug.Log("实际距离:" + atkDistance);

                        break;
                    case MonsterState.SkillA:
                        atkDistance = (float)control.Monster_P.SkillA.ShootRange;
                        break;
                    case MonsterState.SkillS:
                        atkDistance = (float)control.Monster_P.SkillS.ShootRange;
                        break;
                    default: break;
                }
                if (atkDistance > 50)
                    atkDistance = 50;
                //当获取到的距离大于0时,才可以使用(由于近战兵数值文件的攻击距离默认为0,但实际上不是0)
                if (atkDistance < checkDistance.Value)
                    atkDistance = checkDistance.Value;
                //Debug.Log("技能:" + stateNext.Value + "实际距离:" + checkDistance.Value + "getDistance:" + atkDistance);
            }
            else
                atkDistance = checkDistance.Value;
            //Debug.Log("实际距离:" + atkDistance);
        }

        public override TaskStatus OnUpdate()
        {
    
    
            //每次进入 Update 之前都要把将要返回的值设置为空
            returnedObject.Value = null;
            if (lastTarget == null)
            {
    
    
                hitColliders = GetColliders();
                if (hitColliders.Length > 0)
                {
    
    
                    lastTarget = hitColliders.GetMin(t => Vector3.Distance(t.transform.position, transform.position));
                    returnedObject.Value = lastTarget.gameObject;
                    transform.LookAtAroundY(returnedObject.Value.transform);
                    return TaskStatus.Success;
                }
                else
                {
    
    
                    return TaskStatus.Failure;
                }
            }
            //如果上一次获取到目标
            else
            {
    
          
                //判断这一次能否获取到上一次的目标
                hitColliders = GetColliders();
                if (hitColliders.Length>0)
                {
    
    
                    //如果获取到了就返回
                    if (hitColliders.Contains(lastTarget))
                    {
    
    
                        returnedObject.Value = lastTarget.gameObject;
                    }
                    //如果没有获取到就返回可以返回的距离最近的一个
                    else
                    {
    
    
                        returnedObject.Value = hitColliders.GetMin(t => Vector3.Distance
                        (transform.position, t.transform.position)).gameObject;
                    }
                    if (returnedObject.Value != null)
                    {
    
    
                        transform.LookAtAroundY(returnedObject.Value.transform);
                        return TaskStatus.Success;
                    }
                    else
                    {
    
    
                        return TaskStatus.Failure;
                    }
                }
                else
                {
    
    
                    return TaskStatus.Failure;
                }
            }
        }

        public Collider[] GetColliders()
        {
    
    
            if (this.gameObject.tag == "AirForce")
            {
    
    
                hitColliders = Physics.OverlapSphere(centerPos, atkDistance, objectLayerMask.Value);
            }
            else if (gameObject.tag != "AirForce")
            {
    
    
                hitColliders = Physics.OverlapSphere(centerPos, atkDistance, objectLayerMask.Value);
                //近战的怪物应该只能看到和自己 tag 一样的物体
                if (IfRemoveTag)
                {
    
    
                    //近战单位在用物理检测后要剔除数组里面标签和自己不一样的单位
                    List<Collider> temp = hitColliders.ToList();
                    List<Collider> tag = new List<Collider>();
                    temp.ForEach(t =>
                    {
    
    
                        if (t.gameObject.tag != this.gameObject.tag)
                        {
    
    
                            tag.Add(t);
                        }
                    });
                    tag.ForEach(t => temp.Remove(t));
                    hitColliders = temp.ToArray();
                }
            }

            //下面这段代码移除的是处于不可攻击或者不可 Seek 状态的单位
            List<Collider> middle = hitColliders.ToList();
            List<Collider> remove = new List<Collider>();
            middle.ForEach(t =>
            {
    
    
                //凡是处于已下两种情况的都要移除
                //当前处于隐身状态,
                if (t.gameObject.GetComponentInPorC<MonsterControlBase>().OnInvisible ||
                //当前处于刚出生不能攻击的状态
                !t.gameObject.GetComponentInPorC<MonsterControlBase>().getPetTypes)
                {
    
    
                    remove.Add(t);
                }
            });
            remove.ForEach(t => middle.Remove(t));
            hitColliders = middle.ToArray();
            return hitColliders;
        }
    }
}

Guess you like

Origin blog.csdn.net/qq_43505432/article/details/111572409