// (c) Copyright HutongGames, LLC 2010-2013. All rights reserved. using UnityEngine; namespace HutongGames.PlayMaker.Actions { [ActionCategory(ActionCategory.Physics)] [Tooltip("Detect collisions between Game Objects that have RigidBody/Collider components.")] public class CollisionEvent : FsmStateAction { [Tooltip("The GameObject to detect collisions on.")] public FsmOwnerDefault gameObject; [Tooltip("The type of collision to detect.")] public CollisionType collision; [UIHint(UIHint.TagMenu)] [Tooltip("Filter by Tag.")] public FsmString collideTag; [Tooltip("Event to send if a collision is detected.")] public FsmEvent sendEvent; [UIHint(UIHint.Variable)] [Tooltip("Store the GameObject that collided with the Owner of this FSM.")] public FsmGameObject storeCollider; [UIHint(UIHint.Variable)] [Tooltip("Store the force of the collision. NOTE: Use Get Collision Info to get more info about the collision.")] public FsmFloat storeForce; // cached proxy component for callbacks private PlayMakerProxyBase cachedProxy; public override void Reset() { gameObject = null; collision = CollisionType.OnCollisionEnter; collideTag = ""; sendEvent = null; storeCollider = null; storeForce = null; } public override void OnPreprocess() { if (gameObject == null) gameObject = new FsmOwnerDefault(); if (gameObject.OwnerOption == OwnerDefaultOption.UseOwner) { switch (collision) { case CollisionType.OnCollisionEnter: Fsm.HandleCollisionEnter = true; break; case CollisionType.OnCollisionStay: Fsm.HandleCollisionStay = true; break; case CollisionType.OnCollisionExit: Fsm.HandleCollisionExit = true; break; case CollisionType.OnControllerColliderHit: Fsm.HandleControllerColliderHit = true; break; case CollisionType.OnParticleCollision: Fsm.HandleParticleCollision = true; break; } } else { // Add proxy components now if we can GetProxyComponent(); } } public override void OnEnter() { if (gameObject.OwnerOption == OwnerDefaultOption.UseOwner) return; if (cachedProxy == null) GetProxyComponent(); AddCallback(); gameObject.GameObject.OnChange += UpdateCallback; } public override void OnExit() { if (gameObject.OwnerOption == OwnerDefaultOption.UseOwner) return; RemoveCallback(); gameObject.GameObject.OnChange -= UpdateCallback; } private void UpdateCallback() { RemoveCallback(); GetProxyComponent(); AddCallback(); } private void GetProxyComponent() { cachedProxy = null; var source = gameObject.GameObject.Value; if (source == null) return; switch (collision) { case CollisionType.OnCollisionEnter: cachedProxy = PlayMakerFSM.GetEventHandlerComponent(source); break; case CollisionType.OnCollisionStay: cachedProxy = PlayMakerFSM.GetEventHandlerComponent(source); break; case CollisionType.OnCollisionExit: cachedProxy = PlayMakerFSM.GetEventHandlerComponent(source); break; case CollisionType.OnParticleCollision: cachedProxy = PlayMakerFSM.GetEventHandlerComponent(source); break; case CollisionType.OnControllerColliderHit: cachedProxy = PlayMakerFSM.GetEventHandlerComponent(source); break; } } private void AddCallback() { if (cachedProxy == null) return; switch (collision) { case CollisionType.OnCollisionEnter: cachedProxy.AddCollisionEventCallback(CollisionEnter); break; case CollisionType.OnCollisionStay: cachedProxy.AddCollisionEventCallback(CollisionStay); break; case CollisionType.OnCollisionExit: cachedProxy.AddCollisionEventCallback(CollisionExit); break; case CollisionType.OnParticleCollision: cachedProxy.AddParticleCollisionEventCallback(ParticleCollision); break; case CollisionType.OnControllerColliderHit: cachedProxy.AddControllerCollisionEventCallback(ControllerColliderHit); break; } } private void RemoveCallback() { if (cachedProxy == null) return; switch (collision) { case CollisionType.OnCollisionEnter: cachedProxy.RemoveCollisionEventCallback(CollisionEnter); break; case CollisionType.OnCollisionStay: cachedProxy.RemoveCollisionEventCallback(CollisionStay); break; case CollisionType.OnCollisionExit: cachedProxy.RemoveCollisionEventCallback(CollisionExit); break; case CollisionType.OnParticleCollision: cachedProxy.RemoveParticleCollisionEventCallback(ParticleCollision); break; case CollisionType.OnControllerColliderHit: cachedProxy.RemoveControllerCollisionEventCallback(ControllerColliderHit); break; } } private void StoreCollisionInfo(Collision collisionInfo) { storeCollider.Value = collisionInfo.gameObject; storeForce.Value = collisionInfo.relativeVelocity.magnitude; } public override void DoCollisionEnter(Collision collisionInfo) { if (gameObject.OwnerOption == OwnerDefaultOption.UseOwner) CollisionEnter(collisionInfo); } public override void DoCollisionStay(Collision collisionInfo) { if (gameObject.OwnerOption == OwnerDefaultOption.UseOwner) CollisionStay(collisionInfo); } public override void DoCollisionExit(Collision collisionInfo) { if (gameObject.OwnerOption == OwnerDefaultOption.UseOwner) CollisionExit(collisionInfo); } public override void DoControllerColliderHit(ControllerColliderHit collisionInfo) { if (gameObject.OwnerOption == OwnerDefaultOption.UseOwner) ControllerColliderHit(collisionInfo); } public override void DoParticleCollision(GameObject other) { if (gameObject.OwnerOption == OwnerDefaultOption.UseOwner) ParticleCollision(other); } private void CollisionEnter(Collision collisionInfo) { if (collision == CollisionType.OnCollisionEnter) { if (TagMatches(collideTag, collisionInfo)) { StoreCollisionInfo(collisionInfo); Fsm.Event(sendEvent); } } } private void CollisionStay(Collision collisionInfo) { if (collision == CollisionType.OnCollisionStay) { if (TagMatches(collideTag, collisionInfo)) { StoreCollisionInfo(collisionInfo); Fsm.Event(sendEvent); } } } private void CollisionExit(Collision collisionInfo) { if (collision == CollisionType.OnCollisionExit) { if (TagMatches(collideTag, collisionInfo)) { StoreCollisionInfo(collisionInfo); Fsm.Event(sendEvent); } } } private void ControllerColliderHit(ControllerColliderHit collisionInfo) { if (collision == CollisionType.OnControllerColliderHit) { if (TagMatches(collideTag, collisionInfo)) { if (storeCollider != null) storeCollider.Value = collisionInfo.gameObject; storeForce.Value = 0f; //TODO: impact force? Fsm.Event(sendEvent); } } } private void ParticleCollision(GameObject other) { if (collision == CollisionType.OnParticleCollision) { if (TagMatches(collideTag, other)) { if (storeCollider != null) storeCollider.Value = other; storeForce.Value = 0f; //TODO: impact force? Fsm.Event(sendEvent); } } } public override string ErrorCheck() { return ActionHelpers.CheckPhysicsSetup(Fsm.GetOwnerDefaultTarget(gameObject)); } } }