Search Unity

  1. Unity 2020.2 has been released.
    Dismiss Notice
  2. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Animation Event - Can you limit the scope of the method call?

Discussion in 'Animation' started by Rob-Meade, Mar 15, 2019.

  1. Rob-Meade

    Rob-Meade

    Joined:
    Oct 27, 2016
    Posts:
    56
    Hi all,

    I ran into an issue earlier where a method was being called twice whilst trying to use an Animation Event.

    I had created a separate class to act as an intermediary, which would then raise its own event, other classes could subscribe to that event. It just happened that in one of those other classes the name of the method I used was the same as the method in the class linked to the Animation Event.

    It would appear that the Animation Event method call looks at methods from an object level rather than at a component level. As such, when the Animation Even called the method, there were two methods on the object with the same name and this is why my desired behaviour occurred twice.

    What I would like to know is whether it is possible to limit the scope of the method call from the Animation Event to specific components instead? In my specific case, I would like to only call the method on the component acting as the intermediary - if any other components happened to have a method of the same name, these would be ignored.

    I'm assuming this isn't possible and that the method call process is behaving exactly like SendMessage, which I note is stipulated as being similar to that method in the documentation for the Animation Event, but it doesn't state in how it may differ.

    It could potentially become difficult to avoid accidentally calling a method where a method shares its name with a method in another class, attached to the same GameObject. The only thought at the moment to create that separation would be to create a child GameObject and change the hierarchy so that there are no other script components on the child or parent GameObject. That seems like a lot of unnecessary effort.

    Any thoughts would be appreciated - thanks in advance :)
     
  2. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    1,372
    I don't know any more than you about the internals, but for the purpose of this thread, events are exactly the same as SendMessage.

    Events are stored as part of AnimationClip assets, and assets cannot have anything resembling a direct reference to a scene object such as a component. So a feature to let you restrict the target of an event would need a bunch of hackery to put together (by Unity, we don't have access to the parts that would need modifying) and the result would be a decrease in performance for all events, which doesn't seem worth it, even if it's only small.

    Simply renaming the methods you don't want invoked by events would obviously work (and be the most efficient), but I can think of a few other possible workarounds:
    • Move the method out to a static class and make it an extension method.
    • Figure out how it determines which method to call if you give it multiple viable overloads. For example, if it calls parameterless methods first, make an empty parameterless method private that you never call so it's just there to intercept the events, then just give your real method some parameters.
    • Use the parameters to determine who called it. If you give the method you want to hide a string parameter, when an AnimationEvent calls it the value will never be null, so return immediately to ignore any calls that aren't null. And make the parameter's default value null so you don't even need to specify it when calling.
    Actually, that might be how it differs from SendMessage. AnimationEvents just sort of magically pick the right parameter type for each receiver method where an actual SendMessage call takes a specific parameter and tries to pass that into every receiver it finds. An AnimationEvent could call both MyMethod(int) and MyMethod(string) with the values you set while a SendMessage call would have to take either an int or string.
     
    Rob-Meade likes this.
  3. Rob-Meade

    Rob-Meade

    Joined:
    Oct 27, 2016
    Posts:
    56
    Hi,

    Thanks for the reply and the information regarding the animation clips being stored as assets, whilst staring me straight in the face I hadn't even considered that, so your explanation makes perfect sense.

    > Simply renaming the methods you don't want invoked by events would obviously work

    It would, but, when you're not looking at the animations specifically, and just looking at code in Visual Studio, you wouldn't necessarily know which methods are being used within the Animation Event, as such, if you happened to create a new class and use a method name that was already in play, you'd end up, potentially, with the problem I had earlier.

    I've never really been very keen on Animation Events generally, I didn't like how they were separated from the main code but at the moment I feel, at least for what I'm working on, they may be a necessary evil.

    The UI could have a tweak which would help, at least on the Unity side, it wouldn't benefit when in Visual Studio for example, but this;

    upload_2019-3-15_17-3-55.png

    ..I don't think is overly helpful, as it just shows every method across the entire GameObjects, in my case there are about 4 script components here, having the name of each script component as a header, with then the methods listed underneath would be nice. From what I can tell from the above, the methods are already in the order of the scripts, and the methods (and properties) listed then in the order they appear in the scripts.

    The properties are a bit weird being shown here though, and the names are not what I have in code, e.g. get_Lives is from;

    Code (CSharp):
    1. public int Lives
    2. {
    3.     get { return _lives; }
    4.     set { _lives = value; }
    5. }
    6.  
    ..so that seems a little bit weird too. In another sense, the fact that a lot of these methods are private also strikes me as odd that they should be displayed, I'd have thought that perhaps they should at least require some form of attribute tag, along the lines of [SeralizeField] in order to be displayed at all here.

    You could elaborate on the "move the method out to a static class and make an extension method" suggestion above? Are you referring to the intermediary method which I mentioned earlier?
     
  4. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    1,372
    I don't either, but I've never thought of a better solution. I've managed to get rid of magic strings when using resources, layers, and animations, so maybe I'll eventually figure out a good way to do it for animation events too.

    But the whole point of events is that they're tied to a specific pose/keyframe that can be adjusted while previewing the animation rather than being closer to the code side. Having an [AnimationEvent] attribute to put on methods would be nice though, to let you clearly indicate the intent for a method to be called by events.

    That's because properties are just methods with slightly different syntax. If you try to write a method called get_Lives or set_Lives it won't compile because those methods already exist.

    If you take the method you don't want events to call out of its class, events won't be able to call it. But if you make it an extension method, you'll still be able to call it in mostly the same way as if it were still part of the class.
     
    Storm4_ likes this.
unityunity