Search Unity

Overlapping animations problem

Discussion in 'Animation' started by Rodolfo Marques, Mar 1, 2015.

  1. Rodolfo Marques

    Rodolfo Marques

    Joined:
    Mar 1, 2015
    Posts:
    9
    Hello! First time poster here! Please be kind! Ahahhaha


    So, I've been working with unity for the last week and I already learned a lot either from the tutorials in the unity website, posts here and YouTube videos, but I'm having a problem that I can't seem to find a solution. Hope you guys can help me out!


    For a first experience and adaptation I decided to create a 2d game similar to an early pokemon game. My character moves through a dungeon and has to kill enemies in order to get items and get stronger or to move to other areas. The character moves in a grid like environment (no diagonals, just like pokemon) and the enemies are stationary ( just like the trainers in pokemon) with an up and down bouncy animation. To battle the enemy, the player has to walk over it.

    So, up to this point, everything was OK. I managed to do everything just like I imagined and I'm pretty proud! 


    Problem is the actual battle. Player has hit/attack/defense points and so does the enemy. Each "turn" the enemy loses (player attack - enemy deffense) health points and player loses (enemy attack - player defense) health points and it all goes until one of them dies. The player has no control over this. The player simply moves to the enemy, watches the battle and either survives and keeps playing or loses the game. For all this, I want to have an animation in the player that loops for the number of turns and only in the end of it destroys the enemy gameobject (so the enemy stays visible under the animation until the last frame of the battle) and gives control back to the player or destroys the player gameobject and ends the game.


    What I managed to do was make the enemy a trigger. That part was simple and allows the player to go over the enemy. I added the battle animation and the changed the state machine for it to play when the player is over the enemy. So far so good. Getting the number of necessary turns for one of them to die is simple math, but how do I change the looping variable? Keep in mind that for different enemies the number of turns is different and that even for the same enemy, if the player has different stats, the number of turns also changes.


    Possible solutions I thought of:

    1.I played with the exit time condition and noticed I can control the looping with it. But how do I dynamically change it? And how do I know it ended so I can call the destroy function only at the end?

    2. I could add one animation for 1loop, another for two, another for three and then choose the one I want, but I really think this is the worst possible way of solving it...I was looking for a more elegant solution...

    3. I could move the animation to the enemy and maybe it would be easier to call the destroy function at the end, but I would still have the problem of the looping...


    Any ideas of how to go about this?


    R.
     
  2. bloomingdedalus

    bloomingdedalus

    Joined:
    Aug 13, 2012
    Posts:
    139
    Just like "Pokemon?" - young one... what decade were you born in?

    Let me introduce you to your true heritage:



    :p

    I'm kind of confused by your question as it sounds like from what you're able to do that you should be able to do what you're talking about already. Each transition can have a parameter associated with it in the animator. When you change the parameter to the conditions that allow a transition to another animation, it should automatically transition your animation. Example, you have two bool paramaters: Fighting and EndOfFight... Your script switches "Fighting" to true and because your animation is set to transition from idle to fighting when "Fighting" is true, the animator controller switches it to Fighting. There's a transition from the fighting animation to the end fight animation which carries the condition "EndOfFight" is true. When the enemy dies, you simply switch "EndOfFight" to true and "Fighting" to false and make it one way and it should transition to your animation to "end fight." If the animation is not set up to loop, you can have it transition back to idle or whatever after it plays.

    In short, the animation controller allows you to define parameters for transitions and it should transition them automatically for you when the conditions are such that a different state is called for...

    But maybe I'm confused by what you're asking.... I don't really have a specific example of what you're describing so it's hard to be sure what your problem is... I'm kind of assuming you know how to define state transitions by parameters already and therefore I'm confused why you're having trouble syncing your animations.

    There's always "Crossfade" or, in desperate attempts, "Play" to force an animation transition if the state machine just won't do what you want...
     
  3. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    You cannot change an transition exit time at runtime.


    One thing you could do is add a monobehaviour script that check how many loop you have done and exit when you hit the number of loop that you would like. For looping clip you can always look at the normalizedTime value to know how many loop you have done.

    http://docs.unity3d.com/ScriptReference/Animator.GetCurrentAnimatorStateInfo.html
    http://docs.unity3d.com/ScriptReference/AnimatorStateInfo-normalizedTime.html

    Code (CSharp):
    1.  
    2. public class MyMonoBehaviour : MonoBehaviour
    3. {
    4.     Animator animator;
    5.     int numberOfLoop;
    6.  
    7.     public void Start()
    8.     {
    9.         animator = GetComponent<Animator>();
    10.         numberOfLoop = 1;
    11.     }
    12.     public void Update()
    13.     {
    14.         if (animator.GetCurrentAnimatorStateInfo(0).normalizedTime > numberOfLoop)
    15.         {
    16.             // stop animation
    17.         }
    18.     }
    19. }
    20.  
     
    Rodolfo Marques likes this.
  4. Rodolfo Marques

    Rodolfo Marques

    Joined:
    Mar 1, 2015
    Posts:
    9
    Well.... You're absolutely right.... Ahahah Pokemon was just the first example that popped in my mind with the situations I needed.... Ahahah

    Regarding the rest of your comment, i think you didn't get what I (very poorly) tried to ask... Although I'm very new to unity, I know perfectly well the concept of state machines so it wasn't hard for me to start working with the animator and as you say add a transition variable between two states and then change it via the script. :D

    My problem is that I want to loop an animation a different amount of times depending on certain conditions. In my case, my hero will battle an enemy. Let's say it takes 5hits for the hero to kill a vampire. I want the animation to loop 5 times on that encounter. But let's say that after the hero encounters a werewolf and it takes 7 hits to kill it. Now I want the same animation to loop 7 times. Or, in another case, let's say the hero faces again a vampire, but he has a buffer and only takes 2hits to kill it. Now the animation will only loop twice.

    My first thought on simplifying this situation was to create only one battle state in the animator, with one loop of my animation and with the Exit Time as the condition to leave that state. In the heroController script I would dynamically change the Exit Time to whatever value I needed.

    As Mecanim.Dev stated:
    I cannot do it... :(

    So I'm looking for alternatives to that...

    Thank you for your solution Mecanim.Dev! I will surely give it a try and post the results here! ;)

    I would like to ask a question in the meantime. I was googling around a bit and found a possible way: using a ANIMATION (not Transition) EVENT to call a function during the animation. I thought I might initialize a counter before I actually make the transition to the battle state and on that function keep tabs on how many loops were done and when the counter reaches zero, leave the battle state. Would this be a good way? Are transition events for situations like this one or is this a sort of 'shady hack' my mind is creating? Ahahah :oops:

    R.
     
    Last edited: Mar 5, 2015
  5. bloomingdedalus

    bloomingdedalus

    Joined:
    Aug 13, 2012
    Posts:
    139
    That's similar to what I was trying to convey I think... although I'm not sure exactly what you're talking about a "transition event" - do you mean a C# event? Does the animator produce events on transtion changes? I was unaware... here's an example I just made of what I was talking about - I just flip a bool to let it switch states... I'm confused as to why you think this won't work for you (might have to maximize and put the youtube video into 720p to see what's going on)...



    I'm still confused... you need to to transition from battle state to the next state in the middle of the loop? But, yes, that's what I was trying to convey, you're going to have to count your loops and flip your bool when you want to leave the state via script... I figure your enemy is going to have some sort of indicator when it's dead - so whatever conditions are necessary for your enemy to die, just tell the animator to switch out of battle state at that time.

    As for Pokemon... I just like poking fun at it... It's a very successful franchise though so I'm just messing around because I like the things Pokemon was based on so much.

    PS - you can get the number of loops that have taken place of a state via this: http://docs.unity3d.com/ScriptReference/AnimatorStateInfo-normalizedTime.html
     
    Last edited: Mar 3, 2015
  6. Rodolfo Marques

    Rodolfo Marques

    Joined:
    Mar 1, 2015
    Posts:
    9
    This was my mistake... I'm sorry about it. I corrected it in my previous post. What I meant was an Animation Event. As far as I know there are no events on transition changes, although you can always use the Animator.GetCurrentAnimatorStateInfo and Animator.GetNextAnimatorStateInfo for somewhat the same thing I guess...

    Well I'll try to explain again! ahaha :D So imagine this. I have a moving up/down/left/right hero and I have a stationary enemy (as simple as possible, no diagonal, no multiple enemies, just the basic). Since the enemy doesn't move, to battle the enemy the hero needs to move on top of it. Overlapping here is no problem since the enemy has a trigger box collider. So, when this happens, the player looses control of the game. No choosing attack, no dodging, nothing. He can only watch until the fight ends. And the fight is turn based: hero always starts and hits the enemy. Enemy looses health and attacks hero. Hero looses health and attacks enemy. Etc etc etc until one of them has health lower or equal to zero, time when they die (destroying the enemy gameobject or ending the game, depending on who dies). NOTE: when I say "turn" i mean one attack of the hero AND one attack of the enemy. That's a full turn. I have an animation which has the duration of one full turn.
    What I want to do is to play that animation for the X amount of turns it will take for either the hero or the enemy to die. Problem here is that this amount is not fixed. I can calculate it beforehand and will always know it, but I have different enemies with different stats and the hero itself will vary it's stats during gameplay, changing that amount of turns.

    So, I have no problem changing from whatever state to idle/movement/battle. My problem is what is the best and simplest way to dynamically change the transition condition out of the battle state or maybe how to "force" the state machine to keep looping the battle state X times, where X changes from fight to fight.

    Is that a bit more clear? :D


    Well actually it's the other way around. That's the information I have (or can calculate). What I want is to force the animation to loop that amount of times and then stop... ahahah But maybe I can calculate said amount beforehand and then keep checking how many loops the state did. And if it gives me the value I calculated, stop it and transition then? But I think I won't have a good control over it will I? At what point of the animation is this normalizedTime updated? Won't I need a shady logic to control the loop times with this?

    Well, I am an assumed Pokemon fan. Not saying that it's better (I actually think that Zelda is at the top best), but I loved the first games. I knew all original 150 by name and order! xD but then they started to come up with all these thousands and thousands of new pokemon and I started to loose interest. I never actually played the first few Final Fantasy so no comment / comparison I can do there... ahahahha
     
  7. bloomingdedalus

    bloomingdedalus

    Joined:
    Aug 13, 2012
    Posts:
    139
    I'm just confused why you don't just flip a bool to exit the battle loop when the enemy dies... As you can see in my video - I'm perfectly able to exit the loop whenever I want by flicking the bool. You should be able to calculate when your enemy is dead long before your attack animation gets to the end of it's attack loop and, hence, ready to transition back to non-combat... unless the attack loop ends, for some reason, at the exact moment of an attack.

    I played some dorky (but fun) web game called "The Enchanted Cave" on Kongregate that has a fight sequence like you're talking, where you just sit there and let your guy pummel on the enemy.

    Still, if you want to do it the hard way, there's still normalizedTime like I linked above...

    How I would do what you're talking about is:

    1. Have a script monitoring the life of the enemy.
    2. Have a script monitoring the life of the player.
    3. When the enemy and player start fighting, I exchange script references through collision or whatever method I use to start the fight between the player and that specific enemy.
    4. If the enemy dies, I access my Animator and flip a bool to leave my attack loop.
    5. If my player dies, I access my Animator and flip a different bool to leave my attack loop and start a death animation.
     
    Rodolfo Marques likes this.
  8. Rodolfo Marques

    Rodolfo Marques

    Joined:
    Mar 1, 2015
    Posts:
    9
    Well, actually that's one hell of an example! Thanks! That's exactly it. (and you got me a bit addicted to that little thing.. ahahah)

    Well I don't know, maybe I was overthink and complicating... I was focusing on the "I want to dinamically change the loop" and I think I just wasn't seeing any other possibilities. I'll give it a try as you suggested!

    Thanks!