Search Unity

Animator.Settrigger delay?

Discussion in 'Animation' started by raycosantana, Oct 15, 2015.

  1. raycosantana

    raycosantana

    Joined:
    Dec 23, 2012
    Posts:
    319
    Hi

    I just started using settrigger on the animation for the first time and I have this problem I dont know if is intentional behaviour, I used a trigger to play an ATTACK state, this state only plays while on IDLE state, but if im on RUN state and I press the attack button the game waits until the RUN state is over and then plays the ATTACK state, this happens even if I pressed the attack button 4 years ago, is this intentional? IMO this shouldnt be like this, if the controller isnt on the apropiate state, the conditions are not meet, the controller should ignore the Settrigger command... Maybe im crazy but I dont understand this "save the trigger for later" behaviour :confused:

    It looks like this:

    ATTACK
    ||<------------Settrigger transition
    IDLE =RUN

    If press the attack button while running it waits until I stop running and plays the attack animation, even if I pressed the button 10 minutes ago.

    Code (CSharp):
    1. if (Input.GetButtonDown("Fire1")) {                    
    2.             _Animator.SetTrigger("Attack");          
    3.         }
    How I can stop the controller from doing that?
     
    awsapps likes this.
  2. raycosantana

    raycosantana

    Joined:
    Dec 23, 2012
    Posts:
    319
    I cant find a work around for this, any alternative to Triggers?
     
  3. theANMATOR2b

    theANMATOR2b

    Joined:
    Jul 12, 2014
    Posts:
    7,790
    Does your running animation have exit time set to true?
    I believe this is the answer you are looking for, but I'm not a coder so I can't direct you properly.
    Check into "has exit time" and I believe you will find the solution you want.

    Hope this helps.
     
    Ryan900 likes this.
  4. raycosantana

    raycosantana

    Joined:
    Dec 23, 2012
    Posts:
    319
    Hi, thanks for the reply but im certain that isnt what Im looking for. Ive been doing some research and it seems this is intended behaviour of triggers. I dont understand why it was made that way but is the way it is.
     
  5. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    raycosantana:

    Hi!

    Maybe if you add a guard rule in your if sentence like check what state you are in, only then set a trigger? Meta code: "if in idle state and fire1 pressed" -> Set trigger "Attack" and so on.

    But it's interesting find that it fires after you exit attack state. Now you set the trigger and your animator can be in any state, then when that state is done and transitions to next, it fires?

    From manual: "A trigger parameter is a bool parameter that gets reset to false when it has been used in a transition"
     
  6. raycosantana

    raycosantana

    Joined:
    Dec 23, 2012
    Posts:
    319
    Hi thanks for the reply.

    That wont work for me, I have several states that use that trigger making a rule for each is out of the cuestion, by the way if you read carefuly the manual definition you will understand better the problem I have:

    "A trigger parameter is a bool parameter that gets reset to false when it has been USED in a transition"

    which means the trigger wont turn false unless is used in a transition it doesnt matter if you set the trigger true ten years ago or which state you are in it will fire the transition when it has a chance to do so. IMO the trigger should turn false at the end of the frame no matter what, if it doesnt then is pretty much useless because you have zero control over when the animation will play. This is just my opinion, but im not a engine designer, so there must be a reason for this.
     
  7. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    I fail to see why couldn't you do that;

    You collect your input once in frame, yes? And all other code makes decisions based on that input.

    But then you don't limit your input at all?

    Why not just add guard rule in input? Only allow firing when in idle state? Then that animation would be fired when it should be?

    And I quoted that specific sentence for that particular reason, there won't be transition let's say during 3sec long "idle" and you press fire, it will maybe used in next transition? I'm just guessing as I can't test that right now myself.
     
  8. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    This is basically what I meant:

    Code (csharp):
    1.  
    2. if (Input.GetButtonDown("Fire1") && myAnimator.GetCurrentAnimatorStateInfo(0).IsName("Idle"))
    3. {
    4.         // do stuff
    5. }
    6.  
     
    macka1080 likes this.
  9. raycosantana

    raycosantana

    Joined:
    Dec 23, 2012
    Posts:
    319
    I just told you why I cant make it like that, I dont just use it on the Idle state, there is an attack animation on idle, while crouching, there another while jumping and there is whole second tree, I have quite a complex controller here, thats why I wanted this to work.

    About the triggers, it works like this, you press attack it will mantain the trigger true until is used no matter what, once you get to a transition where that trigger can be used it will use it and turn it false. So exactly like you just say, it will be used in the next transition, does that make sense to you?
     
  10. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    OK, got it. Just throwing this into air (don't get annoyed).

    Maybe just add little checker into each state as state behaviour?

    --> State where you don't want to allow setting trigger, add small behaviour where you do ResetTrigger(). Then just add this generic script to any state that shouldn't have possibility set trigger, then at the end of state, it will force trigger off, no matter how many times user hits fire button during that state, at end, it will be reset, and after transition trigger won't fire any other new transitions.
     
  11. raycosantana

    raycosantana

    Joined:
    Dec 23, 2012
    Posts:
    319
    Dont worry Im not annoyed, I know you are trying to help me, sometimes I may sound like I am but im not. :D

    Please elaborate your idea.
     
  12. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    Actually I tested it, seems to be working. Only annoyance it that you have add that small script to each state that shouldn't allow setting trigger, and if you make public field for trigger name, it can be a generic script for any similar case.
     
  13. raycosantana

    raycosantana

    Joined:
    Dec 23, 2012
    Posts:
    319
    Cool, what did you do? reset trigger on those states? please tell me
     
  14. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    Just only what I mentioned - in (OnExitState method of) State Machine Behaviour script set trigger off using animator.ResetTrigger();
     
  15. raycosantana

    raycosantana

    Joined:
    Dec 23, 2012
    Posts:
    319
    It worked thank you!
    I didnt knew this behaviours stuff existed so I also learned something new:)
     
    theANMATOR2b and eses like this.
  16. Paykoman

    Paykoman

    Joined:
    Jun 26, 2014
    Posts:
    500
    I have a similar issue, for example if im in idle or runing and i press attack it works but if im in middle of attack and start run the player stay stopped running the attackanimation while is moving.. how can i fix this?
     
  17. raycosantana

    raycosantana

    Joined:
    Dec 23, 2012
    Posts:
    319
    You use a float to change from attack to running, something like a "speed" float, right?
    Well in the transition from attack to running, unmark "Has exit time" and on "transition duration" put 0.01, this will interrupt the attack anination and transition instantly from attack to running.



    Hope this work for you
     

    Attached Files:

    theANMATOR2b likes this.
  18. Paykoman

    Paykoman

    Joined:
    Jun 26, 2014
    Posts:
    500
    Ok i will get a shot, and no i dont use float variable i use a transition from run to attack by bool and just transition back without any parameter... i'm very noob with animator, and almost all my game problems are related to this, cuz im doing a top down click to move diablo type rpg and i get to many problems with character animation because the transitions -.- and all tutorials arround the internet about the subject are WASD control oriented so almost no examples for click to move type cuz in WASD we have move forward/back/right/left, in click to move simply idle/run/attack, before i start the skills, but not important for now. i simply want my character to idle, run and attack
     
  19. raycosantana

    raycosantana

    Joined:
    Dec 23, 2012
    Posts:
    319
    If you arent using any parameter you need to have Exit time on it, just use 0.01 as exit time and test how that works for you.
     
  20. Paykoman

    Paykoman

    Joined:
    Jun 26, 2014
    Posts:
    500
    With exit time 0.01 it dont work, but if i set has no exit time it work well. :) Tell me one thing maybe i cant help me here, right now when i click to attack and play animation it gives the damage in the exacte secont i click to attack, its possible to only give damage in a certain time of the animation, like when blade is in front of the enemy, in this case 0.37???
     
  21. raycosantana

    raycosantana

    Joined:
    Dec 23, 2012
    Posts:
    319
    Yes, add a an animation event on the attack animation
     
  22. raycosantana

    raycosantana

    Joined:
    Dec 23, 2012
    Posts:
    319
    >Make the damage function public.
    >Select your character in the scene go to the animation window.
    >Select the attack animation and right click in which frame you want the damage function to run.
    >click on "add animation event" and select the damage function from list.
    >you are done.
     

    Attached Files:

    • as.png
      as.png
      File size:
      82.5 KB
      Views:
      1,259
  23. Paykoman

    Paykoman

    Joined:
    Jun 26, 2014
    Posts:
    500
    when u said make damage function public are u refering the attack function that i use to give the damage?
     
  24. raycosantana

    raycosantana

    Joined:
    Dec 23, 2012
    Posts:
    319
    Yes
     
  25. Paykoman

    Paykoman

    Joined:
    Jun 26, 2014
    Posts:
    500
    The problem is that m attack function is protected override, cuz it inherits from other class, i create it so player enemy can inherit attack function from the main character class.. in that main class the attack function is protected abstract... Is there a way to go arround this? And sry for take ur time
     
  26. Paykoman

    Paykoman

    Joined:
    Jun 26, 2014
    Posts:
    500
    I change my Attack funtion to public then i select my player in scene / animation windows select attack animation the frame, add Event Attack() but it still hits in 1st second of animation..

     
  27. raycosantana

    raycosantana

    Joined:
    Dec 23, 2012
    Posts:
    319

    Hi, sorry but without reading your code I cant tell whats wrong.
     
  28. Paykoman

    Paykoman

    Joined:
    Jun 26, 2014
    Posts:
    500
    There it is..

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.UI;
    4.  
    5. public class Player : HumanoidControl
    6. {
    7.     private static Player instance;
    8.    
    9.     public static Player Instance
    10.     {
    11.         get
    12.         {
    13.             if(instance == null)
    14.             {
    15.                 instance = GameObject.FindObjectOfType<Player>();
    16.             }
    17.             return Player.instance;
    18.         }
    19.     }
    20.    
    21.     public Image healthBar;
    22.    
    23.     public Text healthtext;
    24.    
    25.     public static Transform opponent;
    26.    
    27.     public static Player player;
    28.    
    29.     bool block;
    30.    
    31.     private Animator anim;
    32.    
    33.     private bool attacking;
    34.  
    35.     private bool running;
    36.  
    37.    
    38.     //character base status
    39.     public int baseIntellect;
    40.     public int baseAgility;
    41.     public int baseStrength;
    42.     public int baseStamina;
    43.    
    44.     //character modified status with equipment
    45.     private int intellect;
    46.     private int agility;
    47.     private int strength;
    48.     private int stamina;
    49.    
    50.     public Text statsText;
    51.  
    52.  
    53.  
    54.     void Awake()
    55.     {
    56.         player = this;
    57.        
    58.         anim = GetComponent<Animator>();
    59.     }
    60.    
    61.  
    62.  
    63.     void Start()
    64.     {
    65.         curHealth = maxHealth;
    66.                
    67.         SetStatus (0, 0, 0, 0);
    68.     }
    69.  
    70.  
    71.    
    72.     void Update()
    73.     {
    74.         healthBar.fillAmount = curHealth / maxHealth;
    75.        
    76.         healthtext.text = "Health: " + curHealth + "/" + maxHealth;
    77.        
    78.         Attack();
    79.     }
    80.  
    81.  
    82.    
    83.     public void SetStatus(int intellect, int agility, int strength, int stamina)
    84.     {
    85.         this.intellect = intellect + baseIntellect;
    86.         this.agility = agility + baseAgility;
    87.         this.strength = strength + baseStrength;
    88.         this.stamina = stamina + baseStamina;
    89.  
    90.         statsText.text = string.Format ("Intellect: {0}\nAgility: {1}\nStrength: {2}\nStamina: {3}", this.intellect, this.agility, this.strength, this.stamina);
    91.     }
    92.    
    93.    
    94.    
    95.     void OnTriggerStay(Collider other)
    96.     {
    97.         if (other.name == "HealthRegen")
    98.         {
    99.             curHealth += 10;
    100.         }
    101.         if (curHealth > maxHealth)
    102.         {
    103.             curHealth = maxHealth;
    104.         }
    105.     }
    106.    
    107.    
    108.    
    109.     //protected override void Attack()
    110.     public void Attack()
    111.     {
    112.         if (Input.GetMouseButtonUp (1))
    113.         {
    114.             if(opponent != null && Vector3.Distance(opponent.position, transform.position) < attackRange)
    115.             {
    116.                 if(!block)
    117.                 {
    118.                     transform.LookAt(opponent);
    119.  
    120.                     opponent.GetComponent<Enemy>().GetHit(damage);
    121.                                
    122.                     attacking = true;
    123.                
    124.                     anim.SetTrigger("IsAttacking");
    125.  
    126.                     block = true;
    127.  
    128.                     Invoke("UnBlock", attackSpeed);
    129.                 }
    130.  
    131.                 if(Vector3.Distance(opponent.position, transform.position) < attackRange && opponent != null)
    132.                 {
    133.                     attacking = true;
    134.                 }
    135.                 else
    136.                 {
    137.                     attacking = false;
    138.                 }
    139.                 anim.SetBool ("IsAttacking", attacking);
    140.             }
    141.         }
    142.     }
    143.  
    144.     void UnBlock()
    145.     {
    146.         block = false;
    147.     }
    148. }
     
  29. raycosantana

    raycosantana

    Joined:
    Dec 23, 2012
    Posts:
    319
    Yeah I see the problem, you are running Attack() on update and waiting for input (like you should) but the damage is also inside this function, so it runs when you pess the button not with the event, you should make a separate damage function and use that in your animation event instead.

    something like

    Code (CSharp):
    1. public void GetDamage(){
    2. opponent.GetComponent<Enemy>().GetHit(damage);
    3. }
     
    Paykoman likes this.
  30. Paykoman

    Paykoman

    Joined:
    Jun 26, 2014
    Posts:
    500
    Oh i ser the problem now ... Ty m8 i will get it a shot and back here to tell if works
     
  31. Paykoman

    Paykoman

    Joined:
    Jun 26, 2014
    Posts:
    500
    Ok so i create a separate function called DoDamage() but i call it from my Attack() function so now i hit when i press and when i want, how can i call the DoDamge out of my Attack so i dont get double hit??