Desarrollo de nodo de árbol de comportamiento de unidad: control y detección remota de objetivos

Se muestra a continuación Unity 行为树节点开发——远程目标检测控制.

using System;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using Pathfinding;
using MR_LBS.Common;
using MR_LBS.Client.Unity3D;
namespace BehaviorDesigner.Runtime.Tasks.Movement
{
    
    
    [TaskDescription("Check to see if the any objects are within sight of the agent.")]
    [TaskCategory("GC_YS")]
    [TaskIcon("Assets/MR_LBS/Behavior Designer Movement/Editor/Icons/{SkinColor}CanSeeObjectIcon.png")]
    public class CanFindObject : Conditional
    {
    
    
        public SharedLayerMask objectLayerMask;

        public SharedFloat checkDistance;

        public SharedGameObject returnedObject;

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

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

        /// <summary>
        /// Agent 身上的碰撞体
        /// </summary>
        CapsuleCollider collider;
        /// <summary>
        /// 物理检测的中心点
        /// </summary>
        Vector3 centerPos;
        BehaviorTree tree;
        /// <summary>
        /// 攻击模型下是否有上一个目标
        /// </summary>
        private bool hasTarget;
        /// <summary>
        /// 物理检测返回的碰撞体数组
        /// </summary>
        Collider[] hitColliders;
        /// <summary>
        /// 上一次攻击的目标
        /// </summary>
        private GameObject lastTarget;

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

        public override void OnStart()
        {
    
    
            try
            {
    
    
                centerPos = transform.TransformPoint(collider.center);
                //Debug.Log(this.FriendlyName + "Start");

                //每次检查目标之前需要将上一次的结果清空
                hitColliders = null;
                if (this.gameObject.CompareTag("AirForce"))
                {
    
    
                    hitColliders = Physics.OverlapSphere(centerPos - Vector3.up * 2f, checkDistance.Value, objectLayerMask.Value);
                }
                else if (!gameObject.CompareTag("AirForce"))
                {
    
    
                    hitColliders = Physics.OverlapSphere(centerPos, checkDistance.Value, 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();
                //Debug.Log(hitColliders.Length);
            }
            catch (Exception e)
            {
    
    
                Debug.Log(e.StackTrace);
            }
        }

        public override TaskStatus OnUpdate()
        {
    
    
            //Debug.Log(this.FriendlyName + "Update");
            //如果是攻击模式下
            if (!IsSeek)
            {
    
    
                // 判断上一次的攻击目标是否为空
                if (hitColliders != null && hitColliders.Length > 0)
                {
    
    
                    // 如果上一次的目标不为空 则在结果里面寻找上一次的目标
                    if (returnedObject.Value != null)
                    {
    
    
                        GameObject target = null;
                        foreach (var item in hitColliders)
                        {
    
    
                            //如果这次和上次看到的目标一样
                            if (item.gameObject.GetInstanceID() == returnedObject.Value.GetInstanceID())
                            {
    
    
                                returnedObject.Value = item.gameObject;
                                break;
                            }
                        }
                        //如果上一次的攻击目标没死,但是这次没找到,则返回一个距离最近的目标
                        if (target == null)
                        {
    
    
                            var DisMin = hitColliders.GetMin(
                                t => Vector3.Distance(t.transform.position, transform.position));
                            returnedObject.Value = DisMin.gameObject;
                            transform.LookAtAroundY(DisMin.transform);
                            return TaskStatus.Success;
                        }
                        //这次和上次的目标一样 可以直接返回成功
                        else
                        {
    
    
                            transform.LookAtAroundY(returnedObject.Value.transform);
                            return TaskStatus.Success;
                        }
                    }
                    // 这个情况和在结果里面没找到目标属于一种情况,直接返回一个距离最近的
                    else
                    {
    
    
                        //Debug.Log("找一个距离最近的");
                        var DisMin = hitColliders.GetMin(
                               t => Vector3.Distance(t.transform.position, transform.position));
                        returnedObject.Value = DisMin.gameObject;
                        transform.LookAtAroundY(returnedObject.Value.transform);
                        return TaskStatus.Success;
                    }
                }
                else return TaskStatus.Failure;
            }
            // Seek 模式下
            else
            {
    
    
                if (hitColliders != null && hitColliders.Length > 0)
                {
    
    
                    var target = hitColliders.GetMin(
                        t => Vector3.Distance(transform.position, t.transform.position));
                    transform.LookAtAroundY(target.transform);
                    returnedObject.Value = target.gameObject;
                    return TaskStatus.Success;
                }
                else return TaskStatus.Failure;
            }
        }
    }
}

Supongo que te gusta

Origin blog.csdn.net/qq_43505432/article/details/111572223
Recomendado
Clasificación