Search Unity

Event system for Mecanim

Discussion in 'Assets and Asset Store' started by G1NurX, Dec 25, 2012.

  1. G1NurX

    G1NurX

    Joined:
    Dec 25, 2012
    Posts:
    69
    This asset is FREE now.
    You can check out from Github
    https://github.com/Ginurx/MecanimEventSystem

    I have too little time to maintain it. Bugs can't be fixed in a hurry as old time.
    It needs help from community.

    DONT BUY IT IN ASSET STORE NOW. IT'S GOING TO BE FREE.

    Thank you all.

    ---------------------------------------------------------------------------------------------

    $Capture0.PNG
    $c1.PNG
     
    Last edited: May 29, 2015
  2. Lypheus

    Lypheus

    Joined:
    Apr 16, 2010
    Posts:
    664
    A badly needed component for using mecanim - will give this a shot after xmas here, thanks G1!
     
  3. fireheadd

    fireheadd

    Joined:
    Jan 6, 2013
    Posts:
    3
    Hi G1NurX,
    I'm a bit of a noob here.
    I did set everything up as discribed (I think.)
    I have Two Events on an animationclip, at it's start and end with the same name.
    The first with an Int32 set to 1.
    The second with an Int32 set to 0.

    Now I want to play a soundclip when the Int32 is set to 1 and stop it when it's set to 0.
    In javascript. Could you tell me how to do that? I simply don't know.
    Thank you.
     
  4. G1NurX

    G1NurX

    Joined:
    Dec 25, 2012
    Posts:
    69
    I'd like to add the first event named PlaySound and the second one named StopSound.

    In your case, write a function, for example, Bang with an int argument.
    Attach the script contains this function to the gameobject emit the event.
     
    Last edited: Jan 7, 2013
  5. panta

    panta

    Joined:
    Aug 10, 2012
    Posts:
    71
    Thank goodness! I can't wait to download this and see how it works. I've been struggling with trying to get footsteps in Mecanim for the past hour using curves. That feature is not implemented as well as I had hoped from watching the Mecanim demo videos. It's advertised as a way to manipulate data, but the values returned are not reliable, so it's really only good for tweening animations in blend trees and imprecise scalings for colliders.

    You are the best! Expect a purchase in the next five minutes.
     
  6. Lypheus

    Lypheus

    Joined:
    Apr 16, 2010
    Posts:
    664
    G1 - Can your event system guarantee that an event is called? I'd like to see it where if I define a method "OnFire" @ 0.95 time index, I can check off an option to ensure that OnFire will be called once each time the animation is played regardless of whether it is reached or not. This way we can rely on the fact that any time I hit a particular state in the state machine, i'll know that i'm gauranteed to receive a callback by the end of it for each "guaranteed" method.

    The reason for this is because if we have some code that must be executed to keep our games state valid, we could rely on an event coming back. For example, I currently have several states for weapons/combat, to keep it simple called two FIRING and READY. When the player hits the fire button, I set the state to FIRING - this blocks ALL attempts at reloading, firing, etc... again until we are back in the READY state. For each of the firing events, I have a OnFireStart and OnFireEnd. The OnFireStart is not critical, it just produces the muzzle flash and sound at the correct time in the animation to line things up nicely. The OnFireEnd however, is critical, it resets the weapon back to a READY state.

    Currently I've tried getting state lengths, etc... to handle this, the best I've come up with is having a recoverTime which is Time.time + fireDuration, then check this in the Update loop and reset to READY if the OnFireEnd event is missed.

    However, having the notion of an event which is guaranteed to be executed once each time the state is visited - would be great, even if the event is placed near the tail end of the animation and that animation is transitioned from before the event is reached (in this case, as soon as we leave the pure state and start to transition, execute all outstanding 'guaranteed' events).

    I can handle this in my own code here, but imo this feature would make for a very solid event handling asset.
     
  7. SteveB

    SteveB

    Joined:
    Jan 17, 2009
    Posts:
    1,451
    Excellent asset G1. I've been rather surprised that this functionality was missing from Mecanim.

    Also I second Lypheus query. :D
     
  8. G1NurX

    G1NurX

    Joined:
    Dec 25, 2012
    Posts:
    69
    Hi, Lypheus
    I used to reset a state at the beginning. For example, a mob has a state named hurt. The mob will transit to hurt state - set Hurt parameter to true -when it received a damage event. Then I raise a ResetHurt event to set Hurt parameter to false at the beginning of hurt state by event system. Hurt state will automatically exit when it reached ExitTime - a parameter defined by engine. In this way, hurt state won't be triggered again until another damage event handled.

    Actually, I took this functionality you mentioned into consideration in the first released version. But some unexpected behavior is will be encountered because of blend-tree. I removed this guarantee finally for stability.

    If you think this guarantee is very necessary just send me an email to confirm. I'll work it out in a few days and send you a branch version.
     
    Last edited: Feb 28, 2013
  9. Lypheus

    Lypheus

    Joined:
    Apr 16, 2010
    Posts:
    664
    Ya I'm not sure what the best approach is for that, I mean what I currently do right now is to assign durations to each "timed" attribute of my weapon (draw time, holster time, fire time, reload time). Then, using those I setup a "clearToReady" time for the gun, and a "lockAnyState" variable to block any re-entrant attempts at the animations until its "ready" again.

    Instead of using all those events, my approach is to simply start a coroutine and wait two frames then set the "Hurt" parameter back to false so it's as "set and forget" as I can make it, something like:

    Code (csharp):
    1.  
    2.     public IEnumerator ExecuteFire( Animator animator, float fireRate )
    3.     {
    4.         // yield a couple frames for animator to start next state transition
    5.         yield return new WaitForFixedUpdate( );
    6.         yield return new WaitForFixedUpdate( );
    7.  
    8.         // next, clear animation flags to ensure no sequence repeats
    9.         animator.SetBool( "firePrimary", false );
    10.         animator.SetBool( "fireAlternate", false );
    11.     }
    12.  
    I don't know what the best approach is here, IDEALLY I'd like to be able to control the state duration from within code, so then we'd at least be able to fetch projected state duration and then set the time to clear back to ready as the current time + state duration. But I see no way of handling this with mecanims current API (am I missing a reliable way to find the duration of a state? state.length seems to not be it :( ).

    Anyhow, with regards to guaranteed events - if what you roughed out was not reliable, i'll keep on with existing code here and go that route, but it'd be nice to see something like this in the future.
     
  10. G1NurX

    G1NurX

    Joined:
    Dec 25, 2012
    Posts:
    69
    Mecanim missing the feature to scale a specific state at runtime. It can only scale animations globally.
    You want to control the duration within code, but I doubt will animation be played completely without scaling.:confused:
     
  11. SteveB

    SteveB

    Joined:
    Jan 17, 2009
    Posts:
    1,451
    Hey G1, just purchased this and so far so good...couple of notes:

    1) Would be nice if the editor automatically loaded the last Controller you were working on. For a brief moment I thought I lost all the work I had done, then realizing I had to load the controller again. Not a big deal, but a nice 'detail' if it's easy for you to implement.

    2) Any reason why there isn't a boolean parameter? Sure I can use an int32 and pass a 1 or 0, though a bool option would seem like another 'nice detail' to have, and it would parallel Mecanims available parameters.

    Thanks G1


    EDIT: Oops forgot a BIG one!!

    3) You need to make it easier to select and scrub the animation. Currently when the event tick is sitting at the frame you need the event, if the 'anim scrub' button is underneath the tick, its damn near impossible to select and move it to a new frame without accidentally selecting the event tick. Either make the scrub handle much larger or have a dedicated point above or below to grab it, or make the ticks smaller...or just separate the two so the event tick sits above the timeline as a small triangle for example. It doesn't need to be as large as it is nor interfere with selecting the scrub.
     
    Last edited: Mar 1, 2013
  12. SteveB

    SteveB

    Joined:
    Jan 17, 2009
    Posts:
    1,451
    Ah, didn't notice this during my cursory first-use!

    4) There doesn't appear to be any way to drill down into a state. In other words I have a 'Movement' state, that internally blends through a large variety of animations, including Walking, Jogging and Running and each of their directionals. The only animation that appears when I select this state is the WalkF animation; I essentially can only add events to WalkF?

    Thanks again G1

    -Steve
     
  13. G1NurX

    G1NurX

    Joined:
    Dec 25, 2012
    Posts:
    69
    Thank you for your support, Steve

    1) I will merge this feature from branch into trunk in a few days.

    2) It does what legacy system does. But I think it is necessary in order to make this system convenient. So boolean type will be supported in next release.

    3) I will make it better.

    4) Events were added to the state that contains the blend-tree, but not for a specific animation clip. Events will be raised in normalized time. Footsteps can't be a problem if animation clips are synchronized - scaled into homogeneous time.
     
  14. SteveB

    SteveB

    Joined:
    Jan 17, 2009
    Posts:
    1,451
    Hey G1, good news all around then, yay!

    ...except number 4; I didn't quite understand what you're saying.

    Either way two things are currently a problem regardless of time throughout the animation:

    A) I will want to have different events fire for different animations within a single blendtree, which has nothing to do with time, and not necessarily just footsteps or even sounds at all. This is why it makes more sense to have events fire on the animation level, not just time.

    B) Currently I can't see my entire tree of blended motion to ensure event timing...I only see the first animation out of say 20. This problem furthers the case of per-animation events.

    Thanks G1

    -Steve
     
  15. G1NurX

    G1NurX

    Joined:
    Dec 25, 2012
    Posts:
    69
    I'm sorry that there is no way to add events to a animation clip within a blend-tree.
    All animation clips in a blend-tree are running simultaneously. There's no boundary among them - they were blended linearly. Let's assume that I added a event to run animation, but this event will be raised even if character is walking. It's not we expected.

    To solve this problem my opinion is that don't use blend-tree unless all animation clips within it share the same events.
     
  16. SteveB

    SteveB

    Joined:
    Jan 17, 2009
    Posts:
    1,451
    I understand what you're saying, but there's always a solution, even if limited.

    You could simply impose a strict event return based on anim weight; we won't have "event-blending", but simply enforce a priority based on which animation has the greatest effect on blending.

    In other words if you have two animations, blended at 60/40, the animation that is weighted at 60% would have it's events executing.

    Perhaps instead of events on a per-anim basis, you could use conditional events based on where we are in the blendtree. You still have the linear aspect of your event firing as it currently is, but then based on parameter input, just as Mecanim uses, events could be fired if and only when a parameter condition is met. This would still require we be able to preview our entire blendtree when creating events, not just the first animation.

    Regardless, Mecanim's primary strength, even the reason it exists is it's sophisticated blending. Limiting events to a single level is rather restrictive and asking to not use animation blending is unrealistic.

    There's always a solution G1, even if not ideal, so I hope you consider this.
     
  17. SteveB

    SteveB

    Joined:
    Jan 17, 2009
    Posts:
    1,451
    Gin and I have been working on improving this tool, and is definitely what you'll want if you plan on using Mecanim to any great degree. He should be updating both the asset and improved documentation to understand how to use it better.

    Cheers

    -Steve

    PS. Oh and for clarity, I'm just a customer who pestered him privately into working more on it...and now I'm pretty satisfied so I wanted to make sure people knew this.
     
  18. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,697
    This is a really helpful feature! In the next version, could you include the parameter? Right now, I have an event like this:

    Message: ClearBool
    Parameter Type: String
    Parameter: Jump

    In the list, it shows as "ClearBool@0.0100".

    It would be very helpful if it showed as "ClearBool(Jump)@0.0100".

    Thanks!
     
  19. Jesse_Pixelsmith

    Jesse_Pixelsmith

    Joined:
    Nov 22, 2009
    Posts:
    296
    Looks like a great asset. Buying. And I'm glad the dev is able to work with customers in Steve B's case
     
  20. broken

    broken

    Joined:
    Mar 14, 2013
    Posts:
    30
    It would be great to be able to copy events from one state to another. For example, i have a left leg kick and right leg kick (mirror), they have the same events, in the same time, such as raised his leg, and it would be great to just copy the existing events from other states.
     
  21. G1NurX

    G1NurX

    Joined:
    Dec 25, 2012
    Posts:
    69
    You will see it soon.
     
  22. broken

    broken

    Joined:
    Mar 14, 2013
    Posts:
    30
    I'm making a fighting game and use your Asset to determine the start of the strike, and the strike of the active phase (when you need to define a collision) So, when the speed of the animation = 1, then everything is fine. When the speed of the animation is done quickly, for example the value is 2, then the events do not come right away and strikes are not properly defined collision. Delays associated with SendMessage? And whether you can somehow get around this?
    The higher animator.speed of the later event comes :(
    Thanks!
     
    Last edited: Apr 30, 2013
  23. G1NurX

    G1NurX

    Joined:
    Dec 25, 2012
    Posts:
    69
    Delays were not caused by SendMessage. SendMessage calls function immediatly.

    Higher animaiton speed will lead to missing of frames. System can't react in time because the (animation) frames that events were defined are just skipped.
    This is a common problem of animation system. Neither you nor I could fix it.

    But you could try another way that using the feature of conditional events. You duplicate the event of normal speed and advance it. Add a condition - limit by speed - to it .
     
  24. G1NurX

    G1NurX

    Joined:
    Dec 25, 2012
    Posts:
    69
    Hi, Lypheus

    I submitted a new version that support a type of event - critical event - which will never be missed.
     
  25. broken

    broken

    Joined:
    Mar 14, 2013
    Posts:
    30
    Version in Asset Store is still 2.3.

    Did not quite understand what you mean.
    For example, I have an animation - HighStrike. Animation speed default = 1. There are a number of events (OnStartStrike, OnAllowStrike - active phase, OnEndStrike).
    In the event editor, I create the timeline to 0.0 OnStartStrike event, OnEndStrike event in 0.99, and 0.45 for example - OnAllowStrike.
    What more needs to be done to get the timely start of the animation event, given that I am in the code will set animator.speed = 1.75 or more?

    Thanks!
     
  26. Lypheus

    Lypheus

    Joined:
    Apr 16, 2010
    Posts:
    664
    Awesome stuff G1, i'll update and take a look :) - i've been using your asset in my current TPC project with great success.
     
  27. G1NurX

    G1NurX

    Joined:
    Dec 25, 2012
    Posts:
    69
    Here is a tutorial of how to add conditional event.

    Condition parameter need to be defined by yourself in animator controller.
    In your case, you should create a paremter GlobalAnimSpeed of float type for example.
    And set it - animator.SetFloat("GlobalAnimSpeed ", currentSpeed).
    Make conditional event by this parameter.

    ----------------------------------------------------------------------------

    2.5 is reviewing by assetstore. It'll be there soon.
     

    Attached Files:

  28. sefou

    sefou

    Joined:
    Aug 30, 2011
    Posts:
    287
    Hi G1,
    i can't open your conditional_event.pdf .Cn you fixe it ?

    Thanks.
     
  29. broken

    broken

    Joined:
    Mar 14, 2013
    Posts:
    30
    I saw your tutorial, thank you.
    And I thought about what to emit an event in advance. But how to make the start of the event is emitted immediately after it can not be fit in time less than 0.0.
    Now I have a dictionary of animation in which each state by hash is put in the appropriate complete information (fight strike animation - punch, kick, head) over bumps and other things.
    For example:
    Dictionary <int, FightAnimation> dict
    FightAnimation (nameHash, name, speed, type etc.)

    In the Update () I process the Input.keys and exhibit types beats animator through animator.SetInteger(StrikeType)
    So, I wanted to strike at the start of the animation, I was taken by hash value from the dictionary of animation speed and immediately exhibited in the animator. In this case, to obtain timely event and the possibility of hitting the end of the animation.
    But since the start of the event does not come immediately, I can not handle the animation timely hit (to set the speed of the new animations etc).

    Probably I will have to tinker with the code of noodles :(
    Code (csharp):
    1.  
    2. _currentState = _animator.GetCurrentAnimatorStateInfo (0);
    3. _nextState = _animator.GetNextAnimatorStateInfo (0);
    4. _isInTransition = _animator.IsInTransition (0);
    5. _transitionInfo = _animator.GetAnimatorTransitionInfo (0);
    6.  
    7. for example:
    8. if (_currentState.tagHash == IDLES)
    9. {
    10.     if (!_isInTransition )
    11.     {
    12.         _currentIdleAnimation = _animationDictionary.GetIdleAnimationByHash(_currentState.nameHash) // IdleFightAnimation
    13.         _currentFightAnimation = _currentIdleAnimation; // IdleFightAnimation : FightAnimation
    14.     }
    15.     else
    16.     {
    17.         if (_nextState.tagHash == STRIKES)
    18.         {
    19.             _currentStrikeAnimation = _animationDictionary.GetStrikeAnimationByHash(_currentState.nameHash) // StrikeFightAnimation
    20.             _currentFightAnimation = _currentStrikeAnimation ; // StrikeFightAnimation : FightAnimation (hash, name, speed ...)
    21.         }
    22.     }
    23. }
    24.  
    25. if (_currentFightAnimation != null)
    26. {
    27.     _animator.speed = _currentFightAnimation.speed;
    28. }
    29.  
    Ideally it would be the following (example):
    Code (csharp):
    1.  
    2. void OnStrikeStart()
    3. {
    4.     _currentStrikeAnimation = _animationDictionary.GetStrikeAnimationByHash(_currentState.nameHash) // StrikeFightAnimation
    5.     _currentFightAnimation = _currentStrikeAnimation ; // StrikeFightAnimation : FightAnimation (hash, name, speed ...)
    6.     _animator.speed = _currentFightAnimation.speed;
    7.     if (_currentStrikeAnimation.allowStrkeBoxesAtStart)
    8.         _strikeBoxes.enabled = true; // for collisions
    9. }
    10.  
    11. void OnStrikeAllow(bool allow)
    12. {
    13.     _strikeBoxes.enabled = allow;
    14. }
    15.  
    16. void OnStrikeEnd()
    17. {
    18.     _currentStrikeAnimation = null;
    19. }
    20.  
    Even if the speed of the animation set in advance for each state separately in the editor and not through the code, I do not think that the situation will change.

    PS. Sorry for my English, it is translated.
     
    Last edited: May 4, 2013
  30. G1NurX

    G1NurX

    Joined:
    Dec 25, 2012
    Posts:
    69
    Last edited: May 5, 2013
  31. G1NurX

    G1NurX

    Joined:
    Dec 25, 2012
    Posts:
    69
    @broken

    $Capture.PNG

    $Capture1.PNG
     
    Last edited: May 5, 2013
  32. broken

    broken

    Joined:
    Mar 14, 2013
    Posts:
    30
    yes, that is probably what you need. why can not we add the ability to emit an event, even if it is in a state of transition?
    Thanks!
     
  33. MacHulk

    MacHulk

    Joined:
    Apr 24, 2013
    Posts:
    23
    bump for 天朝
     
  34. G1NurX

    G1NurX

    Joined:
    Dec 25, 2012
    Posts:
    69
    In fact, a transition could be interrupted (by other one , if current one is not atom).
    When this happened, then, unexpected behaviour raise.

    -----------------------------------------------
    It only need to change a few lines code in MecanimEventManger.cs to get it working as you expected. :wink:
     
  35. broken

    broken

    Joined:
    Mar 14, 2013
    Posts:
    30
    Now for a more flexible definition of the beginning and end of the animation I use for internal state and for inner animation events - Mecanim Event System.
    Code (csharp):
    1.  
    2.     void FixedUpdate()
    3.     {
    4.         AnimatorStateInfo currentStateInfo = _animator.GetCurrentAnimatorStateInfo(0);
    5.         AnimatorStateInfo nextStateInfo = _animator.GetNextAnimatorStateInfo(0);
    6.        
    7.         // OnEnd
    8.         if (currentStateInfo.nameHash != _lastState.nameHash)
    9.         {
    10.             UpdateEndEvents(_lastState.tagHash);
    11.         }
    12.        
    13.         // OnStart
    14.         if (nextStateInfo.nameHash != _nextState.nameHash)
    15.         {
    16.             UpdateStartEvents(nextStateInfo.tagHash, nextStateInfo.nameHash);
    17.         }
    18.        
    19.         _lastState = currentStateInfo;
    20.         _nextState = nextStateInfo;
    21.     }
    22.  
     
  36. broken

    broken

    Joined:
    Mar 14, 2013
    Posts:
    30
    It would be great to have the following features in the editor:
    1. Filter transitions states on the event name
    2. Grouping by the sub-states names
    3. Quick renaming event in all states
    4. Add an event simultaneously in all states or groups of states, for example, OnStart at 0.0
     
    Last edited: May 8, 2013
  37. snarge7781

    snarge7781

    Joined:
    May 13, 2013
    Posts:
    4
    Is there anyone else who has tried using the event system with mecanim and asset bundles? Since I've started putting all my info in asset bundles, my animation events have seemed to stop firing.
     
  38. G1NurX

    G1NurX

    Joined:
    Dec 25, 2012
    Posts:
    69
    There was a user reported this problem but he fixed himself.
    This problem caused by unity in fact. I'm trying to fix it.
     
  39. broken

    broken

    Joined:
    Mar 14, 2013
    Posts:
    30
    Feature request: common input parameter of the event, which contains some information on the state from which it was due, for example:
    Code (csharp):
    1.  
    2. void OnStrikeStart(MecanimEvent e, ...)
    3. {
    4.     // e.tagHash, e.nameHash, e.name ...
    5. }
    6.  
     
  40. snarge7781

    snarge7781

    Joined:
    May 13, 2013
    Posts:
    4
    Yes, I figured it was something with Unity, as they've had some issues with Mecanim and asset bundles since the release. Did that user post the solution online? I haven't seen anything from my various searches. Thanks!
     
  41. G1NurX

    G1NurX

    Joined:
    Dec 25, 2012
    Posts:
    69
    I built my AssetBundle but it worked perfectly. I think event data node, animator controller and character should be built into one AssetBundle in order to have a same animator controller id.

    He fixed it manually. :D
     
  42. G1NurX

    G1NurX

    Joined:
    Dec 25, 2012
    Posts:
    69
    You will see it in next release
     
  43. lighting

    lighting

    Joined:
    Dec 21, 2011
    Posts:
    42
    Hi,

    I'm using the system since Febuary and I see new versions. How to upgrade ?
     
  44. G1NurX

    G1NurX

    Joined:
    Dec 25, 2012
    Posts:
    69
    First, bakup your project .
    Get most recent version and replace all scripts in EventSystem folder.
    New version is backward compatible in theary.
     
  45. G1NurX

    G1NurX

    Joined:
    Dec 25, 2012
    Posts:
    69
    @Broken

    You can get context when handling event now by accessing MecanimEvent.Conext
     
  46. broken

    broken

    Joined:
    Mar 14, 2013
    Posts:
    30
    Yes, thanks, I already updated.
     
  47. broken

    broken

    Joined:
    Mar 14, 2013
    Posts:
    30
    What are your plans for the introduction of new functionality into your Asset? (roadmap) :)
     
  48. G1NurX

    G1NurX

    Joined:
    Dec 25, 2012
    Posts:
    69
    Hello,
    No feature will be added in the near future. In fact, a data manager tool has already being there, which is disabled by default.
    Current version is pretty good for most customers.
    I would like to take a break and to be ready for the next coming Unity release.
     
  49. pixelknight

    pixelknight

    Joined:
    Jul 12, 2011
    Posts:
    93
    So happy about the potential this product has and that it is being supported. I'd love to recommend its use to friends in other studios.

    After purchasing, we're looking forward to blend trees being supported or finding a possible workaround. An earlier post about prioritized events really made sense. The blendtree being the reason we're using mecanim instead of making a legacy movement system.

    Keep up the good work and thanks in advance for your active support.
     
  50. broken

    broken

    Joined:
    Mar 14, 2013
    Posts:
    30
    Hello!

    I create a fighting game.

    I have a lot of animations, and a common Animator Controller. All animators fighters has own avatar and use this common AnimatorController.
    I also use your Asset (Mecanim Event System), and there is an common Game Object on the scene with a MecanimEventSetupHelper. I just have one common Prefab (Mecanim Event Data).

    Аfter the selection of fighters in the menu, players start fight at a random location (scene).
    Fight location (scene) and fighters must dynamically loadable via Asset Bundles.
    When I create a scene Asset Bundle through BuildPipeline.BuildStreamedSceneAssetBundle, it includes all the animations fighters, as I understand this is due to the presence of the Game Object with MecanimEventSetupHelper (link to Mecanim Event Data).

    How to do the right loading Scene AssetBundle and Fighters AssetBundle separately? I think the scene should not contain animations depending on.
    And how better to do AssetBundle for each fighter? What should they contain (AnimatorController, Model, Animations)? Or animation to load separately?

    Sorry for the question, he is half relates to your Asset.

    Thanks!