/// <summary> /// Remove an object from the list explicitly. /// This works even if the object is still in range, effectivley hiding it from the /// perimiter. /// </summary> /// <param name="target">The Target to remove</param> /// <returns>True if somethign was removed</returns> public bool Remove(Target target) { // Quit if nothing was removed if (!this.targets.Remove(target)) { return(false); } // Silence errors on game exit / unload clean-up if (target.transform == null || this.transform == null || this.transform.parent == null) { return(false); } #if UNITY_EDITOR if (this.targetTracker.debugLevel > DEBUG_LEVELS.Off) // If on at all { Debug.Log(string.Format ( "{0} : Target Removed - {1}", this.targetTracker, target.targetable )); } #endif // Trigger the delegate execution for this event if (this.targetTracker.onNotDetectedDelegates != null) { this.targetTracker.onNotDetectedDelegates(this.targetTracker, target); } target.targetable.OnNotDetected(this.targetTracker); // Trigger target update: Sorting, filtering, events. // This uses AddRange internally to copy the targets so '=' is safe this.targetTracker.targets = this.targets; return(true); }
protected void FilterTrackerTargetList(TargetTracker source, TargetList targets) { // Quit if the mask is set to nothing == OFF if (this.targetTrackerLayerMask.value == 0) { return; } Vector3 fromPos; if (this.tracker.area != null) { fromPos = this.tracker.area.transform.position; } else { fromPos = this.tracker.transform.position; } LayerMask mask = this.targetTrackerLayerMask; this.FilterTargetList(targets, mask, fromPos, Color.red); }
protected void FilterFireTargetList(TargetList targets) { // Quit if the mask is set to nothing == OFF if (this.fireControllerLayerMask.value == 0) { return; } Vector3 fromPos; if (this.fireCtrl.spawnEventTriggerAtTransform != null) { fromPos = this.fireCtrl.spawnEventTriggerAtTransform.position; } else { fromPos = this.fireCtrl.transform.position; } LayerMask mask = this.fireControllerLayerMask; this.FilterTargetList(targets, mask, fromPos, Color.yellow); }
public TargetList(TargetList targetList) : base(targetList) { }
protected void FilterTargetList(TargetList targets, LayerMask mask, Vector3 fromPos, Color debugLineColor) { #if UNITY_EDITOR var debugRemoveNames = new List <string>(); #endif Vector3 toPos; bool isNotLOS; var iterTargets = new List <Target>(targets); Collider2D targetColl2D; Collider targetColl; Vector3 ext; bool use2d; foreach (Target target in iterTargets) { use2d = target.targetable.coll2D != null; isNotLOS = false; if (this.testMode == TEST_MODE.BoundingBox) { if (use2d) { targetColl2D = target.targetable.coll2D; ext = targetColl2D.bounds.extents * 0.5f; } else { targetColl = target.targetable.coll; ext = targetColl.bounds.extents * 0.5f; } // This solution works with rotation pretty well Matrix4x4 mtx = target.targetable.transform.localToWorldMatrix; var bboxPnts = new Vector3[8]; bboxPnts[0] = mtx.MultiplyPoint3x4(ext); bboxPnts[1] = mtx.MultiplyPoint3x4(new Vector3(-ext.x, ext.y, ext.z)); bboxPnts[2] = mtx.MultiplyPoint3x4(new Vector3(ext.x, ext.y, -ext.z)); bboxPnts[3] = mtx.MultiplyPoint3x4(new Vector3(-ext.x, ext.y, -ext.z)); bboxPnts[4] = mtx.MultiplyPoint3x4(new Vector3(ext.x, -ext.y, ext.z)); bboxPnts[5] = mtx.MultiplyPoint3x4(new Vector3(-ext.x, -ext.y, ext.z)); bboxPnts[6] = mtx.MultiplyPoint3x4(new Vector3(ext.x, -ext.y, -ext.z)); bboxPnts[7] = mtx.MultiplyPoint3x4(-ext); for (int i = 0; i < bboxPnts.Length; i++) { if (use2d) { isNotLOS = Physics2D.Linecast(fromPos, bboxPnts[i], mask); } else { isNotLOS = Physics.Linecast(fromPos, bboxPnts[i], mask); } // Quit loop at first positive test if (isNotLOS) { #if UNITY_EDITOR if (this.debugLevel > DEBUG_LEVELS.Off) { Debug.DrawLine(fromPos, bboxPnts[i], debugLineColor, 0.01f); } #endif continue; } else { break; } } } else { toPos = target.targetable.transform.position; if (use2d) { isNotLOS = Physics2D.Linecast(fromPos, toPos, mask); } else { isNotLOS = Physics.Linecast(fromPos, toPos, mask); } #if UNITY_EDITOR if (isNotLOS && this.debugLevel > DEBUG_LEVELS.Off) { Debug.DrawLine(fromPos, toPos, debugLineColor, 0.01f); } #endif } if (isNotLOS) { targets.Remove(target); #if UNITY_EDITOR debugRemoveNames.Add(target.targetable.name); #endif } } #if UNITY_EDITOR if (this.debugLevel == DEBUG_LEVELS.High && debugRemoveNames.Count > 0) { Debug.Log("Holding fire for LOS: " + string.Join(",", debugRemoveNames.ToArray())); } #endif }
/// <summary> /// Handles all firing events including target aquisition and firing. /// Events are: /// OnStart() : /// Runs once when the firing system first becomes active /// OnUpdate() : /// Runs each frame while the firing system is active /// OnTargetUpdate() : /// Runs each frame while tracking a target (there is at least one target.) /// OnIdleUpdate() : /// Runs each frame while the firing system is idle (no targets) /// OnFire() : /// Runs when it is time to fire. /// /// Counter Behavior Notes: /// * If there are no targets. the counter will keep running up. /// This means the next target to enter will be fired upon /// immediatly. /// /// * The counter is always active so if the last target exits, then a /// new target enters right after that, there may still be a wait. /// </summary> protected IEnumerator FiringSystem() { if (this.targetTracker == null) { this.targetTracker = this.GetComponent <TargetTracker>(); if (this.targetTracker == null) { // Give it a frame to see if this.targetTracker is being set by code. yield return(null); if (this.targetTracker == null) { throw new MissingComponentException ( "FireControllers must be on the same GameObject as a TargetTracker " + "or have it's targetTracker property set by code or drag-and-drop " + "in the inspector." ); } } } // While (true) because of the timer, we want this to run all the time, not // start and stop based on targets in range if (this.initIntervalCountdownAtZero) { this.fireIntervalCounter = 0; } else { this.fireIntervalCounter = this.interval; } this.targets.Clear(); this.OnStart(); // EVENT TRIGGER this.keepFiring = true; // Can be turned off elsewhere to kill the firing system while (this.keepFiring) { // if there is no target, counter++, handle idle behavior, and // try next frame. // Will init this.targets for child classes as well. this.targets = new TargetList(this.targetTracker.targets); if (this.targets.Count != 0) { if (this.fireIntervalCounter <= 0) { // Let the delegate filter a copy of the list just for the OnFire // Test. We still want this.targets to remain as is. // Do this in here to still trigger OnTargetUpdate this.targetsCopy.Clear(); this.targetsCopy.AddRange(this.targets); if (targetsCopy.Count != 0 && this.onPreFireDelegates != null) { this.onPreFireDelegates(this.targetsCopy); } // If all is right, fire // Check targetsCopy incase of pre-fire delegate changes if (targetsCopy.Count != 0) { this.Fire(); this.fireIntervalCounter = this.interval; // Reset } } // Update event while tracking a target this.OnTargetUpdate(this.targets); // EVENT TRIGGER } else { // Update event while NOT tracking a target this.OnIdleUpdate(); // EVENT TRIGGER } this.fireIntervalCounter -= Time.deltaTime; // Update event no matter what this.OnUpdate(); // EVENT TRIGGER // Stager calls to get Target (the whole system actually) yield return(null); } // Wipe out the target list when stopped this.targets.Clear(); }
/// <summary> /// Fire on the targets /// </summary> protected void Fire() { #if UNITY_EDITOR // Log a message to show what is being fired on if (this.debugLevel > DEBUG_LEVELS.Off) { string[] names = new string[this.targets.Count]; for (int i = 0; i < this.targets.Count; i++) { names[i] = this.targets[i].transform.name; } string msg = string.Format ( "Firing on: {0}\nEventInfo: {1}", string.Join(", ", names), this.eventInfoList.ToString() ); Debug.Log(string.Format("{0}: {1}", this, msg)); } #endif // // Create a new list of targets which have this fire controller reference. // var targetCopies = new TargetList(); Target newTarget; foreach (Target target in this.targets) { // Can't edit a struct in a foreach loop, so need to copy and store newTarget = new Target(target); newTarget.fireController = this; // Add reference. null before this targetCopies.Add(newTarget); } // Write the result over the old target list. This is for output so targets // which are handled at all by this target tracker are stamped with a // reference. this.targets = targetCopies; // // Hnadle delivery // foreach (Target target in this.targets) { switch (this.notifyTargets) { case NOTIFY_TARGET_OPTIONS.Direct: target.targetable.OnHit(this.eventInfoList, target); break; case NOTIFY_TARGET_OPTIONS.PassInfoToEventTrigger: this.SpawnEventTrigger(target, true); break; case NOTIFY_TARGET_OPTIONS.UseEventTriggerInfo: this.SpawnEventTrigger(target, false); break; } } #if UNITY_EDITOR // When in the editor, if debugging, draw a line to each hit target. if (this.debugLevel > DEBUG_LEVELS.Off && this.notifyTargets > NOTIFY_TARGET_OPTIONS.Off) { foreach (Target target in this.targets) { Debug.DrawLine(this.spawnEventTriggerAtTransform.position, target.transform.position, Color.red); } } #endif // Trigger the delegates if (this.onFireDelegates != null) { this.onFireDelegates(this.targets); } }
protected void FilterFireTargetList(TargetList targets) { // Get the position expected to be used to fire from. Vector3 fromPos = this.origin.position; #if UNITY_EDITOR var debugRemoveNames = new List <string>(); #endif this.iterTargets.Clear(); this.iterTargets.AddRange(targets); float dist; for (int i = 0; i < iterTargets.Count; i++) { this.currentTarget = iterTargets[i]; dist = this.currentTarget.targetable.GetDistToPos(fromPos); // Skip if the target is in the distance range if (dist > this.minDistance && dist < this.maxDistance) { #if UNITY_EDITOR if (this.debugLevel > DEBUG_LEVELS.Off) { Debug.DrawLine ( fromPos, this.currentTarget.targetable.transform.position, Color.green, 0.01f ); } #endif continue; } #if UNITY_EDITOR if (this.debugLevel > DEBUG_LEVELS.Off) { Debug.DrawLine ( fromPos, this.currentTarget.targetable.transform.position, Color.red, 0.01f ); } #endif targets.Remove(this.currentTarget); #if UNITY_EDITOR debugRemoveNames.Add(this.currentTarget.targetable.name); #endif } #if UNITY_EDITOR if (this.debugLevel == DEBUG_LEVELS.High && debugRemoveNames.Count > 0) { string msg = string.Format ( "Holding fire due to distance: {0}", string.Join(", ", debugRemoveNames.ToArray()) ); Debug.Log(string.Format("{0}: {1}", this, msg)); } #endif }