Search Unity

Possible to sense 'Exit' of OnControllerColliderHit(ControllerColliderHit hit)?

Discussion in 'Scripting' started by outtoplay, May 27, 2014.

  1. outtoplay

    outtoplay

    Joined:
    Apr 29, 2009
    Posts:
    741
    Is there an 'exit' type action for this method?

    The Player steps onto an elevator and triggers the UP animation. When he steps off, I couldn't think of a 'step off' method. Eventually I just did this with a trigger so I could have "OnTriggerEnter" and "OnTriggerExit". but I'm curious if there is something like that for this. Thanks.



    Code (csharp):
    1. void OnControllerColliderHit(ControllerColliderHit hit)     // when controller hits a collider while moving. Other = hit
    2.     {
    3.         if(hit.collider.gameObject.tag == "Lift")                          // If Player steps on Elevator, play Up anim.
    4.         {
    5.             Invoke("Up", .5f);                                                          
    6.         }
    7.     }
    8.  
     
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    I wrote a script that I attach to my gameobject with a charactercontroller to handle determining when a controller is entered, stayed, and exited.

    I just track what colliders had hit me last update, and determine the status off that. If the new hit was never in my collection, it's an enter. If it's in my collection, it's a stay. And if there's something in my collection that wasn't hit this update, we exited.

    If ManuallySet is true, you should call Resolve after every move.

    Otherwise, if auto, it presumes that Move is called EVERY Update/FixedUpdate (whichever you flag it for). Because the OnControllerColliderHit message occurs only during the call to Move.

    This script of mine dispatches the enter, stay, exit messages using my custom 'Notification' system. You can dispatch it as custom messages if you'd like, mono/.net events, or your own notification system. I prefer mine because my notification system understands my 'entity' structure which allows messaging between gameobjects in a group of gameobjects that have a 'root' gameobject, as well as being type safe. If you're at all interested in that notification system, I can share that as well.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections.Generic;
    4. using System.Linq;
    5.  
    6. using com.spacepuppy.Collections;
    7.  
    8. namespace com.spacepuppy.Hooks
    9. {
    10.  
    11.     [AddComponentMenu("SpacePuppy/Hooks/CharacterController Collision Notifier")]
    12.     public class CharacterControllerCollisionNotifier : SPComponent
    13.     {
    14.  
    15.         public bool ManuallySet = false;
    16.         public bool UseFixedUpdate = false;
    17.  
    18.         public bool NotifyThisRoot = true;
    19.  
    20.         public bool NotifyOther = false;
    21.         public bool NotifyOtherRoot = false;
    22.  
    23.         private CharacterController _controller;
    24.         private UniqueList<Collider> _stayedColliders = new UniqueList<Collider>();
    25.         private UniqueList<Collider> _enteredColliders = new UniqueList<Collider>();
    26.  
    27.         protected override void Awake()
    28.         {
    29.              base.Awake();
    30.  
    31.             _controller = this.GetComponent<CharacterController>();
    32.         }
    33.  
    34.         void Update()
    35.         {
    36.             if (ManuallySet || UseFixedUpdate) return;
    37.  
    38.             this.Resolve();
    39.         }
    40.  
    41.         void FixedUpdate()
    42.         {
    43.             if (ManuallySet || !UseFixedUpdate) return;
    44.  
    45.             this.Resolve();
    46.         }
    47.  
    48.         public void Resolve()
    49.         {
    50.             //TODO - reimplement this so that we have all the hit information
    51.             var entered = _enteredColliders.Except(_stayedColliders).ToArray();
    52.             var stayed = _stayedColliders.Intersect(_enteredColliders).ToArray();
    53.             var exited = _stayedColliders.Except(_enteredColliders).ToArray();
    54.  
    55.             foreach (var c in entered)
    56.             {
    57.                 _stayedColliders.Add(c);
    58.  
    59.                 var n = new CharacterControllerCollisionEnterNotification(_controller, c);
    60.                 Notification.PostNotification<CharacterControllerCollisionEnterNotification>(this, n, this.NotifyThisRoot);
    61.                 if (this.NotifyOther) Notification.PostNotification<CharacterControllerCollisionEnterNotification>(c, n, this.NotifyOtherRoot);
    62.             }
    63.  
    64.             foreach (var c in stayed)
    65.             {
    66.                 var n = new CharacterControllerCollisionStayNotification(_controller, c);
    67.                 Notification.PostNotification<CharacterControllerCollisionStayNotification>(this, n, this.NotifyThisRoot);
    68.                 if (this.NotifyOther) Notification.PostNotification<CharacterControllerCollisionStayNotification>(c, n, this.NotifyOtherRoot);
    69.             }
    70.  
    71.             foreach (var c in exited)
    72.             {
    73.                 _stayedColliders.Remove(c);
    74.  
    75.                 var n = new CharacterControllerCollisionExitNotification(_controller, c);
    76.                 Notification.PostNotification<CharacterControllerCollisionExitNotification>(this, n, this.NotifyThisRoot);
    77.                 if (this.NotifyOther) Notification.PostNotification<CharacterControllerCollisionExitNotification>(c, n, this.NotifyOtherRoot);
    78.             }
    79.  
    80.             _enteredColliders.Clear();
    81.         }
    82.  
    83.         void OnControllerColliderHit(ControllerColliderHit hit)
    84.         {
    85.             _enteredColliders.Add(hit.collider);
    86.         }
    87.  
    88.     }
    89.  
    90. }
    91.  
    You'll notice my code has a todo note saying to reimplement so that we have all the hit information. Currently I only track the collider that was stayed, and not all the 'hit' info for that stay. So my notification only informs all what collider was entered, stayed, exited. If you need more, then you'll need to store that info as well. I never needed it, so I didn't bother wasting the memory tracking it.

    You'll also notice I use a 'UniqueList', this is a custom list that implements IList<T>. Really all it does is when adding, inserting, and setting, it checks if the item being put in the list already exists or not. Making sure that no item is added twice. You could make your own version of this... or you just test if the list contains the object before adding.
     
    Last edited: May 27, 2014
    SanyaBane likes this.
  3. outtoplay

    outtoplay

    Joined:
    Apr 29, 2009
    Posts:
    741
    Wow.. very cool system. Appreciate your detailed reply and sharing the code. I'll comb through it to make show I understand the flow. I've been forcing myself to really 'get' shared code so I can learn. Seems like the least I can do when someone helps out. And yes, would be very interested in seeing the notification system if you don't mind. then I can distill this down to just play the down elevator anim when I 'exit' the "Lift "

    Digital beers on me...(or since it's already in the 80s here, digital lemonade).