Esempio n. 1
0
        /// <summary>
        /// Grabs the combatants that fit the specified criteria
        /// </summary>
        /// <param name="rHunter">Transform who is searching for the combatants</param>
        /// <param name="rSeekOrigin">Combat origin of the hunter</param>
        /// <param name="rFilter">Filters we'll use to limit which combatants are returned</param>
        /// <param name="rCombatantHits">List of CombatantHit values who are the combatants</param>
        /// <param name="rIgnore">Transform that we won't consider a target (typically the character)</param>
        /// <returns>Count of combatants returned</returns>
        public static int QueryCombatTargets(Transform rSeeker, Vector3 rSeekOrigin, CombatFilter rFilter, List <CombatTarget> rCombatTargets, Transform rIgnore)
        {
            if (rSeeker == null)
            {
                return(0);
            }
            if (rCombatTargets == null)
            {
                return(0);
            }

#if OOTII_PROFILE
            com.ootii.Utilities.Profiler.Start(rSeeker.name + ".QueryCombatTargets");
#endif

            Collider[] lHitColliders;

            rCombatTargets.Clear();

            int lHitCount = RaycastExt.SafeOverlapSphere(rSeekOrigin, rFilter.MaxDistance, out lHitColliders, rFilter.Layers, rIgnore);
            for (int i = 0; i < lHitCount; i++)
            {
                GameObject lGameObject = lHitColliders[i].gameObject;

                // Don't count the ignore
                if (lGameObject.transform == rSeeker)
                {
                    continue;
                }
                if (lGameObject.transform == rIgnore)
                {
                    continue;
                }

                // Determine if the combatant has the appropriate tag
                if (rFilter.Tag != null && rFilter.Tag.Length > 0)
                {
                    if (!lGameObject.CompareTag(rFilter.Tag))
                    {
                        continue;
                    }
                }

                // We only care about combatants we'll enage with
                ICombatant lCombatant = null;

                Transform lHitTransform = lHitColliders[i].transform;
                while (lHitTransform != null)
                {
                    lCombatant = lGameObject.GetComponent <ICombatant>();
                    if (lCombatant != null)
                    {
                        break;
                    }

                    lHitTransform = lHitTransform.parent;
                }

                if (rFilter.RequireCombatant && lCombatant == null)
                {
                    continue;
                }

                // Determine if the combatant is within range
                Vector3         lClosestPoint    = Vector3.zero;
                ActorController lActorController = lGameObject.GetComponent <ActorController>();
                if (lActorController != null)
                {
                    lClosestPoint = lActorController.ClosestPoint(rSeekOrigin);
                }
                else
                {
                    lClosestPoint = GeometryExt.ClosestPoint(rSeekOrigin, lHitColliders[i]);
                }

                // If we have an invalid point, stop
                if (lClosestPoint == Vector3Ext.Null)
                {
                    continue;
                }

                // Determine if the point is in range
                bool    lIsValid        = true;
                Vector3 lToClosestPoint = lClosestPoint - rSeekOrigin;

                float lDistance = lToClosestPoint.magnitude;
                if (rFilter.MinDistance > 0f && lDistance < rFilter.MinDistance)
                {
                    lIsValid = false;
                }
                if (rFilter.MaxDistance > 0f && lDistance > rFilter.MaxDistance)
                {
                    lIsValid = false;
                }

                // Ensure we're not ontop of the combatant. In that case, it's probably the ground
                Vector3 lDirection = lToClosestPoint.normalized;
                if (lDirection == -rSeeker.up)
                {
                    lIsValid = false;
                }

                // Check if we're within the field of view
                float lHAngle = Vector3Ext.HorizontalAngleTo(rSeeker.forward, lDirection, rSeeker.up);
                if (rFilter.HorizontalFOA > 0f && Mathf.Abs(lHAngle) > rFilter.HorizontalFOA * 0.5f)
                {
                    lIsValid = false;
                }

                float lVAngle = Vector3Ext.HorizontalAngleTo(rSeeker.forward, lDirection, rSeeker.right);
                if (rFilter.VerticalFOA > 0f && Mathf.Abs(lVAngle) > rFilter.VerticalFOA * 0.5f)
                {
                    lIsValid = false;
                }

                // This is an odd test, but we have to do it. If the closest point of a sphere is out of the FOA, it may
                // be that the top of the sphere is in the FOA. So, we'll grab the top of the sphere and test it.
                if (!lIsValid && lCombatant != null && lHitColliders[i] is SphereCollider)
                {
                    lIsValid = true;
                    SphereCollider lSphereCollider = lHitColliders[i] as SphereCollider;

                    lClosestPoint   = lCombatant.Transform.position + (lCombatant.Transform.rotation * (lSphereCollider.center + (Vector3.up * lSphereCollider.radius)));
                    lToClosestPoint = lClosestPoint - rSeekOrigin;

                    lDistance = lToClosestPoint.magnitude;
                    if (rFilter.MinDistance > 0f && lDistance < rFilter.MinDistance)
                    {
                        lIsValid = false;
                    }
                    if (rFilter.MaxDistance > 0f && lDistance > rFilter.MaxDistance)
                    {
                        lIsValid = false;
                    }

                    // Ensure we're not ontop of the combatant. In that case, it's probably the ground
                    lDirection = lToClosestPoint.normalized;
                    if (lDirection == -rSeeker.up)
                    {
                        lIsValid = false;
                    }

                    // Check if we're within the field of view
                    lHAngle = Vector3Ext.HorizontalAngleTo(rSeeker.forward, lDirection, rSeeker.up);
                    if (rFilter.HorizontalFOA > 0f && Mathf.Abs(lHAngle) > rFilter.HorizontalFOA * 0.5f)
                    {
                        lIsValid = false;
                    }

                    lVAngle = Vector3Ext.HorizontalAngleTo(rSeeker.forward, lDirection, rSeeker.right);
                    if (rFilter.VerticalFOA > 0f && Mathf.Abs(lVAngle) > rFilter.VerticalFOA * 0.5f)
                    {
                        lIsValid = false;
                    }
                }

                if (mShowDebug)
                {
                    GraphicsManager.DrawPoint(rSeekOrigin, Color.white, null, 2f);
                    GraphicsManager.DrawPoint(lClosestPoint, Color.red, null, 2f);
                }

                if (lIsValid)
                {
                    // Add the combatant to our list
                    CombatTarget lTargetInfo = new CombatTarget();
                    lTargetInfo.SeekOrigin      = rSeekOrigin;
                    lTargetInfo.Collider        = lHitColliders[i];
                    lTargetInfo.Combatant       = lCombatant;
                    lTargetInfo.ClosestPoint    = lClosestPoint;
                    lTargetInfo.Distance        = lDistance;
                    lTargetInfo.Direction       = lDirection;
                    lTargetInfo.HorizontalAngle = lHAngle;
                    lTargetInfo.VerticalAngle   = lVAngle;

                    rCombatTargets.Add(lTargetInfo);
                }
            }

            // Sort the combatants by distance
            if (rCombatTargets.Count > 1)
            {
                rCombatTargets.Sort((rLeft, rRight) => rLeft.Distance.CompareTo(rRight.Distance));

                // We also want to remove duplicates
                for (int i = 0; i < rCombatTargets.Count; i++)
                {
                    Transform lTarget = rCombatTargets[i].Collider.transform;
                    if (rCombatTargets[i].Combatant != null)
                    {
                        lTarget = rCombatTargets[i].Combatant.Transform;
                    }

                    // Check if there's a duplicate and remove it
                    for (int j = rCombatTargets.Count - 1; j > i && j > 0; j--)
                    {
                        Transform lNextTarget = rCombatTargets[j].Collider.transform;
                        if (rCombatTargets[j].Combatant != null)
                        {
                            lNextTarget = rCombatTargets[j].Combatant.Transform;
                        }

                        if (lNextTarget == lTarget)
                        {
                            rCombatTargets.RemoveAt(j);
                        }
                    }
                }
            }

#if OOTII_PROFILE
            float lTime = Utilities.Profiler.Stop(rSeeker.name + ".QueryCombatTargets");
            //Utilities.Debug.Log.FileWrite(rSeeker.name + ".QueryCombatTargets time:" + lTime.ToString("f5") + "ms");
#endif

            // Finally, return the count
            return(rCombatTargets.Count);
        }