Exemple #1
0
        public void Forget(SensedObject target)
        {
            if (!SensedObjects.ContainsKey(target))
            {
                return;
            }

            GameObject go = target.TargetObject;

            SensedObjects.Remove(target);
            if (null != go)
            {
                rememberedObjects.Remove(go);
                seenObjects.Remove(go);
                heardObjects.Remove(go);
                smelledObjects.Remove(go);
                implicitDetectedObjects.Remove(go);
            }

            if (NearestSensedObject == target)
            {
                var e = SensedObjects.GetEnumerator();
                e.MoveNext();
                NearestSensedObject = e.Current.Value;
                nearestSensedChanged?.Invoke(target, NearestSensedObject);
            }
            sensedObjectForgottenListener?.Invoke(target);
        }
Exemple #2
0
 /// <summary>
 /// Fully reset the senses state. Callbacks will be left intact, but no callbacks will be issued.
 /// </summary>
 public void Reset()
 {
     SensedObjects.Clear();
     rememberedObjects.Clear();
     seenObjects.Clear();
     heardObjects.Clear();
     smelledObjects.Clear();
     implicitDetectedObjects.Clear();
 }
        protected override void OnUpdateSenses()
        {
            if (!HasAdrenaline && frame++ < frequency)
            {
                return;
            }
            frame = 0;
            float nearest = float.MaxValue;

            Collider[]   colliders   = null;
            GameObject[] gameObjects = null;
            int          possibleTargetCount;

            if (useSphereCast)
            {
                colliders           = Physics.OverlapSphere(transform.position, maxSenseRange, targetMask);
                possibleTargetCount = colliders.Length;
            }
            else
            {
                gameObjects         = SensableObject.Registry;
                possibleTargetCount = gameObjects.Length;
            }
            seenObjects.Clear();
            heardObjects.Clear();
            smelledObjects.Clear();

            // TODO: We may want to think about creating a new set each frame. This was just updating
            // the set, but I was getting a concurrent modification exception from AnimalUtilityData since
            // it is operating in a coroutine instead of on the main thread. Let's discuss how to properly
            // optimize this. We could potentially go with a static list and create a copy for consumers
            // that request the list when they want it. We can also optimize consumers of the list to use
            // the OnNewObjectsSensed listener for updates
            var   sensedObjects      = new SortedSet <SensedObject>();
            var   newlySensedObjects = new HashSet <SensedObject>();
            float detectionTime      = Time.fixedTime;

            for (int i = 0; i < possibleTargetCount; i++)
            {
                GameObject   targetObject = useSphereCast ? colliders[i].gameObject : gameObjects[i];
                SensedObject sensedObject;

                float actualDistance = Vector3.Distance(targetObject.transform.position, transform.position);
                if (actualDistance > maxSenseRange)
                {
                    continue;
                }

                if (targetObject == gameObject)
                {
                    continue;
                }
                if (null != sensedObjectValidationListener && !sensedObjectValidationListener(targetObject))
                {
                    continue;
                }


                sensedObject = RememberSensedObject(targetObject);

                float sensedDistance = actualDistance;

                // Detection from least accurate to most.
                if (actualDistance < scentRange)
                {
                    smelledObjects.Add(targetObject);
                    if (sensedObject.actualPosition != targetObject.transform.position)
                    {
                        sensedObject.position = targetObject.transform.position + UnityEngine.Random.insideUnitSphere * scentAccuracyRadius;
                    }
                    sensedDistance       = Vector3.Distance(targetObject.transform.position, transform.position);
                    sensedObject.smelled = true;
                }
                if (CanSee(targetObject))
                {
                    seenObjects.Add(targetObject);
                    sensedObject.position = targetObject.transform.position;
                    sensedObject.seen     = true;
                }
                if (actualDistance < implicitDetectionRange)
                {
                    implicitDetectedObjects.Add(targetObject);
                    sensedObject.position           = targetObject.transform.position;
                    sensedObject.implicitlyDetected = true;
                }

                sensedObject.actualPosition = targetObject.transform.position;
                sensedObject.distance       = sensedDistance;

                if (lastSenseTime != sensedObject.lastDetection)
                {
                    newlySensedObjects.Add(sensedObject);
                }

                sensedObject.lastDetection  = detectionTime;
                SensedObjects[sensedObject] = sensedObject;

                while (SensedObjects.Count > nearbySenseCapacity)
                {
                    SensedObjects.RemoveAt(nearbySenseCapacity);
                }
            }
            if (newlySensedObjects.Count > 0)
            {
                OnSensedNewObjects(newlySensedObjects);
            }

            lastSenseTime = detectionTime;

            SensedObject old = NearestSensedObject;

            NearestSensedObject = SensedObjects.Count > 0 ? SensedObjects.First().Value : null;

            if (null != NearestSensedObject && Time.fixedTime - NearestSensedObject.lastDetection > timeToRetainNearest)
            {
                NearestSensedObject = null;
                nearest             = float.PositiveInfinity;
                nearestSensedChanged?.Invoke(old, null);
            }
            else if (old != NearestSensedObject)
            {
                nearestSensedChanged?.Invoke(old, null);
            }
        }