// (c) Copyright HutongGames, LLC 2010-2016. All rights reserved. using UnityEngine; namespace HutongGames.PlayMaker.Actions { [ActionCategory(ActionCategory.Physics2D)] [Tooltip("Iterate through a list of all colliders detected by a LineCast" + "The colliders iterated are sorted in order of increasing Z coordinate. No iteration will take place if there are no colliders within the area.")] public class GetNextLineCast2d: FsmStateAction { [ActionSection("Setup")] [Tooltip("Start ray at game object position. \nOr use From Position parameter.")] public FsmOwnerDefault fromGameObject; [Tooltip("Start ray at a vector2 world position. \nOr use fromGameObject parameter. If both define, will add fromPosition to the fromGameObject position")] public FsmVector2 fromPosition; [Tooltip("End ray at game object position. \nOr use From Position parameter.")] public FsmGameObject toGameObject; [Tooltip("End ray at a vector2 world position. \nOr use fromGameObject parameter. If both define, will add toPosition to the ToGameObject position")] public FsmVector2 toPosition; [Tooltip("Only include objects with a Z coordinate (depth) greater than this value. leave to none for no effect")] public FsmInt minDepth; [Tooltip("Only include objects with a Z coordinate (depth) less than this value. leave to none")] public FsmInt maxDepth; [Tooltip("If you want to reset the iteration, raise this flag to true when you enter the state, it will indicate you want to start from the beginning again")] [UIHint(UIHint.Variable)] public FsmBool resetFlag; [ActionSection("Filter")] [UIHint(UIHint.Layer)] [Tooltip("Pick only from these layers.")] public FsmInt[] layerMask; [Tooltip("Invert the mask, so you pick from all layers except those defined above.")] public FsmBool invertMask; [ActionSection("Result")] [Tooltip("Store the number of colliders found for this overlap.")] [UIHint(UIHint.Variable)] public FsmInt collidersCount; [UIHint(UIHint.Variable)] [Tooltip("Store the next collider in a GameObject variable.")] public FsmGameObject storeNextCollider; [Tooltip("Get the 2d position of the next ray hit point and store it in a variable.")] public FsmVector2 storeNextHitPoint; [Tooltip("Get the 2d normal at the next hit point and store it in a variable.")] public FsmVector2 storeNextHitNormal; [Tooltip("Get the distance along the ray to the next hit point and store it in a variable.")] public FsmFloat storeNextHitDistance; [Tooltip("Event to send to get the next collider.")] public FsmEvent loopEvent; [Tooltip("Event to send when there are no more colliders to iterate.")] public FsmEvent finishedEvent; private RaycastHit2D[] hits; private int colliderCount; // increment an index as we loop through children private int nextColliderIndex; public override void Reset() { fromGameObject = null; fromPosition = new FsmVector2 { UseVariable = true }; toGameObject = null; toPosition = new FsmVector2 { UseVariable = true }; minDepth = new FsmInt { UseVariable = true }; maxDepth = new FsmInt { UseVariable = true }; layerMask = new FsmInt[0]; invertMask = false; resetFlag = null; collidersCount = null; storeNextCollider = null; storeNextHitPoint = null; storeNextHitNormal = null; storeNextHitDistance = null; loopEvent = null; finishedEvent = null; } public override void OnEnter() { if (hits == null || resetFlag.Value) { nextColliderIndex = 0; hits = GetLineCastAll(); colliderCount = hits.Length; collidersCount.Value = colliderCount; resetFlag.Value = false; } DoGetNextCollider(); Finish(); } private void DoGetNextCollider() { // no more colliders? // check first to avoid errors. if (nextColliderIndex >= colliderCount) { hits = null; nextColliderIndex = 0; Fsm.Event(finishedEvent); return; } // get next collider Fsm.RecordLastRaycastHit2DInfo(Fsm, hits[nextColliderIndex]); storeNextCollider.Value = hits[nextColliderIndex].collider.gameObject; storeNextHitPoint.Value = hits[nextColliderIndex].point; storeNextHitNormal.Value = hits[nextColliderIndex].normal; storeNextHitDistance.Value = hits[nextColliderIndex].fraction; // no more colliders? // check a second time to avoid process lock and possible infinite loop if the action is called again. // Practically, this enabled calling again this state and it will start again iterating from the first child. if (nextColliderIndex >= colliderCount) { hits = new RaycastHit2D[0]; nextColliderIndex = 0; Fsm.Event(finishedEvent); return; } // iterate the next collider nextColliderIndex++; if (loopEvent != null) { Fsm.Event(loopEvent); } } private RaycastHit2D[] GetLineCastAll() { var fromPos = fromPosition.Value; var fromGo = Fsm.GetOwnerDefaultTarget(fromGameObject); if (fromGo!=null) { fromPos.x += fromGo.transform.position.x; fromPos.y += fromGo.transform.position.y; } var toPos = toPosition.Value; var toGo = toGameObject.Value; if (toGo!=null) { toPos.x += toGo.transform.position.x; toPos.y += toGo.transform.position.y; } if (minDepth.IsNone && maxDepth.IsNone) { return Physics2D.LinecastAll(fromPos,toPos,ActionHelpers.LayerArrayToLayerMask(layerMask, invertMask.Value)); }else{ var _minDepth = minDepth.IsNone? Mathf.NegativeInfinity : minDepth.Value; var _maxDepth = maxDepth.IsNone? Mathf.Infinity : maxDepth.Value; return Physics2D.LinecastAll(fromPos,toPos,ActionHelpers.LayerArrayToLayerMask(layerMask, invertMask.Value),_minDepth,_maxDepth); } } } }