Search Unity

attack combo system help with C#

Discussion in 'Scripting' started by yeshua_black, Apr 17, 2014.

  1. yeshua_black

    yeshua_black

    Joined:
    Nov 4, 2012
    Posts:
    32
    So I've been learning scripting in unity with C# so far I've learnt quite a lot from tutorials, books and the community. So I decided to script a basic attack combo system,

    so here is my attempt at a 2 button consecutive press system.

    So I've tried like 3 ways to achieve this but still keep running into other problems.

    So here is my most recent attempt.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class New_Combo_System : MonoBehaviour
    6. {
    7.     public bool firstButtonPress = false;
    8.     public bool secondButtonPress = false;
    9.     public bool thirdButtonPress = false;
    10.     public float comboTimer = 0.5f;
    11.     public int currentComboState = 1;
    12.  
    13.     // Use this for initialization
    14.     void Start ()
    15.     {
    16.    
    17.     }
    18.    
    19.     // Update is called once per frame
    20.     void Update ()
    21.     {
    22.         NewComboSystem ();
    23.     }
    24.  
    25.     void ComboStateUpdate ()
    26.     {
    27.         currentComboState ++;
    28.         // increments combo state by 1
    29.     }
    30.  
    31.     void ResetComboState()
    32.     {
    33.         currentComboState = 1;
    34.         //resets combo state to it's default value of 1
    35.     }
    36.  
    37.     void NewComboSystem()
    38.     {
    39.         if (Input.GetKeyDown (KeyCode.Z)  currentComboState == 1)
    40.         {
    41.             Debug.Log("1 hit");
    42.             firstButtonPress = true;
    43.             ComboStateUpdate();
    44.  
    45.             Invoke("ResetComboState",comboTimer);
    46.         }
    47.  
    48.         if (Input.GetKeyDown (KeyCode.Z)  currentComboState == 2  firstButtonPress == true)
    49.         {
    50.             Debug.Log("2 hits");
    51.             firstButtonPress = false;
    52.             ResetComboState();
    53.         }
    54.  
    55.     }
    56. }
    57.  
    58.  
    I'm stuck :(

    On my output console, the first time I hit the Z key it outputs both "1 hit" and "2 hits" at the same time. Could someone please look through it and tell me what's wrong with my code.

    And also if possible, point me in the right direction or suggest a better approach to making a combo system
     
  2. Zaladur

    Zaladur

    Joined:
    Oct 20, 2012
    Posts:
    392
    Your two If statements run one after the other. Input.GetKeyDown will return true for the entire frame that it is pressed down, and the code from your first if statement sets conditions true for the second. This means combo 2 will always run after combo 1.

    There are a few ways to approach the system as whole, but a quick fix for this issue would be to put the combos in reverse order in the code (2, then 1), to ensure the frame changes between the condition checks.
     
  3. yeshua_black

    yeshua_black

    Joined:
    Nov 4, 2012
    Posts:
    32
    So what your saying is that the moment I hit the Z key, the code in the first if statement becomes true and thus combo run will run. and since combo 1 sets the conditions to run combo 2 to true combo 2 runs immediately as well and all this happens in one frame?
     
  4. Zaladur

    Zaladur

    Joined:
    Oct 20, 2012
    Posts:
    392
    Correct. Update is run once per frame, and you call your combo code within update. That means the entire function is being run in the same frame, and any GetKeyDown or similar functions will be consistently true or false through the entire frame.
     
  5. yeshua_black

    yeshua_black

    Joined:
    Nov 4, 2012
    Posts:
    32
    I see. Thank you for clearing that up for me.Any ideas of how I should tackle this then? I read somewhere that coroutines allows the code to continue from the previous frame or something like that. I'm yet to study them though so I have no idea how they work.
    I'm still studying lists and dictionaries at the moment.

    Would a coroutine solve my problem?
     
    Last edited: Apr 17, 2014
  6. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,539
    I know how I would tackle this, but I don't have the time to put it all together right now.

    It would deal with Coroutines though, I'd wait a frame with the coroutine (my yielding null you wait one frame).

    I'd also have a collection of all the known combos of course.

    When a key was pushed down I'd then push that into some queue, and I create a temporary list of the reduced list of known combos that would start with this key strike.

    Now I wait for another key to be pressed. If a duration of time passes, I dump the temporary list of reduced of known combos and start over.

    If a key is pressed, reduce the list again to only those combos that this combination matches. If there aren't any, dump the temp list and start over.

    If a match is a perfect match, then a combo was performed, signal for that combo to be performed.
     
    pltc325 likes this.
  7. yeshua_black

    yeshua_black

    Joined:
    Nov 4, 2012
    Posts:
    32
    Thank you for the reply. If you do have time later on I'll like to see your solution to this. Seems like I have to study coroutines sooner than I planned.

    I don't really understand your solution. I guess I'm still very inexperienced. Maybe it would make more sense to me in code.I'll read up on coroutines and see if I can implement them. Thanks again for the reply.
     
  8. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,539
    Tonight after work maybe.
     
  9. yeshua_black

    yeshua_black

    Joined:
    Nov 4, 2012
    Posts:
    32
    That would do :)

    I'm off to go study some more..
     
  10. Rphysx

    Rphysx

    Joined:
    Mar 26, 2014
    Posts:
    54
    Just today I had to do a double button-check to make a "sprint" style movement for a 2d character, but before telling you directly my code i'll try to take a look at yours to see if it can work without having to completely change it

    Code (csharp):
    1.  
    2. public class New_Combo_System : MonoBehaviour
    3.     {
    4.  
    5.         bool ActivateTimerToReset = false;
    6. //The more bools, the less readibility, try to stick with the essentials.
    7. //If you were to press 10 buttons in a row
    8. //having 10 booleans to check for those would be confusing
    9.  
    10.         public float comboTimer = 0.5f;
    11.         public int currentComboState = 0;
    12.  
    13.         // Update is called once per frame, yeah everybody knows this
    14.  
    15.         void Update()
    16.         {
    17.             NewComboSystem();
    18. //Initially set to false, so the method won't start
    19.             ResetComboState(ActivateTimerToReset);  
    20.         }
    21.  
    22.         void ResetComboState(bool ChooseYourWonderfulBoolName)
    23.         {
    24.             if (ChooseYourWonderfulBoolName)      
    25.  //if the bool that you pass to the method is true
    26.  // (aka if ActivateTimerToReset is true, then the timer start
    27.             {
    28.                 comboTimer -= Time.Deltatime;  
    29. //If the parameter bool is set to true, a timer start, when the timer
    30. //runs out (because you don't press fast enought Z the second time)
    31. //currentComboState is set again to zero, and you need to press it twice again
    32.                 if (comboTimer <= 0)
    33.                 {
    34.                     currentComboState = 0;
    35.                     ActivateTimerToReset = false;
    36.                     comboTimer = 0.5f;
    37.                 }
    38.             }
    39.         }
    40.  
    41.         void NewComboSystem()
    42.         {
    43.             if (Input.GetKeyDown(KeyCode.Z))
    44.             {
    45.  
    46. //Note that I'm to lazy to setup a switch statement
    47. //that would be WAY more readable than 3 if's in a row
    48.  
    49.                 if (currentComboState == 0)
    50.                 {
    51.                     currentComboState++;  
    52. //No need to create a comboStateUpdate()
    53. //function while you can directly
    54. //increment a variable using ++ operator
    55.  
    56.                     ActivateTimerToReset = true;    
    57. //Okay, you pressed Z once, so now the resetcombostate Function is
    58. //set to true, and the timer starts to reset the currcombostate
    59.                     Debug.Log("1 hit");
    60.                 }
    61.  
    62.                 if (currentComboState == 1)
    63.                 {
    64.                     currentComboState++;
    65.                     Debug.Log("2 hit, The combo Should Start");
    66.  //Do your awesome stuff there and combokill the bitches
    67.                 }
    68.  
    69.                 if (currentComboState >= 2)
    70.                 {
    71.                     Debug.Log("Whooaaa 3 hits in half a second!");
    72.  //I bet this will blast everthing off the screen
    73.                 }
    74.  
    75.  
    76.             }
    77.         }
    78.  
    79.     }
    80.  
    Note that I wrote this at 3:20am without testing it and it surely has few bugs in it but It's here just to give you an idea on how to solve the issue. By the way you should really learn coroutines since they have a lot of uses and this kind of code could be much more elegant with those and you would avoid the overuse of the update() function since it's resource-intensive
     
    Last edited: Apr 18, 2014
  11. msl_manni

    msl_manni

    Joined:
    Jul 5, 2011
    Posts:
    272
  12. yeshua_black

    yeshua_black

    Joined:
    Nov 4, 2012
    Posts:
    32
    Amazing. Simply amazing. now I know how to create a timer :)
    Thanks for taking time out of your busy schedule to write this. And I will study coroutines in time( still stuck on state machines).
     
  13. yeshua_black

    yeshua_black

    Joined:
    Nov 4, 2012
    Posts:
    32
    Just what I was looking for. Thank you for linking me to this.

    I also want to say a big thank you to everyone who replied this thread. the Unity community is amazing..
    Now I'm reassured that if I do stumble into future roadbloacks they're people who would help me out. (off to go study some more)
     
  14. CodeFriendlyArt

    CodeFriendlyArt

    Joined:
    Jun 3, 2016
    Posts:
    10
    Kinda surprised no one updated this one so far so will share the revised version to the original code base provided by Rphysx, hope you can find it useful:


    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class ComboMonitorTemplate : MonoBehaviour {
    6.  
    7.     bool ActivateTimerToReset = false;
    8.     //The more bools, the less readibility, try to stick with the essentials.
    9.     //If you were to press 10 buttons in a row
    10.     //having 10 booleans to check for those would be confusing
    11.  
    12.     public float currentComboTimer;
    13.     public int currentComboState = 0;
    14.  
    15.     float origTimer;
    16.  
    17.     void Start()
    18.     {
    19.         // Store original timer reset duration
    20.         origTimer = currentComboTimer;
    21.     }
    22.  
    23.     // Update is called once per frame, yeah everybody knows this
    24.  
    25.     void Update()
    26.     {
    27.         NewComboSystem();
    28.         //Initially set to false, so the method won't start
    29.         ResetComboState(ActivateTimerToReset);
    30.     }
    31.  
    32.     void ResetComboState(bool resetTimer)
    33.     {
    34.         if (resetTimer)
    35.         //if the bool that you pass to the method is true
    36.         // (aka if ActivateTimerToReset is true, then the timer start
    37.         {
    38.             currentComboTimer -= Time.deltaTime;
    39.             //If the parameter bool is set to true, a timer start, when the timer
    40.             //runs out (because you don't press fast enought Z the second time)
    41.             //currentComboState is set again to zero, and you need to press it twice again
    42.             if (currentComboTimer <= 0)
    43.             {
    44.                 currentComboState = 0;
    45.                 ActivateTimerToReset = false;
    46.                 currentComboTimer = origTimer;
    47.             }
    48.         }
    49.     }
    50.  
    51.     void NewComboSystem()
    52.     {
    53.         if (Input.GetKeyDown(KeyCode.Z))
    54.         {
    55.  
    56.             //No need to create a comboStateUpdate()
    57.             //function while you can directly
    58.             //increment a variable using ++ operator
    59.             currentComboState++;
    60.  
    61.             //Okay, you pressed Z once, so now the resetcombostate Function is
    62.             //set to true, and the timer starts to reset the currcombostate
    63.             ActivateTimerToReset = true;
    64.  
    65.             //Note that I'm to lazy to setup a switch statement
    66.             //that would be WAY more readable than 3 if's in a row
    67.             if (currentComboState == 1)
    68.             {
    69.            
    70.                 Debug.Log("1 hit");
    71.             }
    72.             if (currentComboState == 2)
    73.             {            
    74.                 Debug.Log("2 hit, The combo Should Start");
    75.                 //Do your awesome stuff there and combokill the bitches
    76.             }
    77.             if (currentComboState >= 3)
    78.             {
    79.                 Debug.Log("Whooaaa 3 hits in half a second!");
    80.                 //I bet this will blast everthing off the screen
    81.             }
    82.         }
    83.     }
    84. }
     
  15. franciscochong

    franciscochong

    Joined:
    Jul 9, 2015
    Posts:
    30
    Hi @FirstLightStudios thanks for posting your revised code!
    I was wondering tho, how would you make this work with an Animator.
    for example not all my animations durations are 0.5f seconds, should i create an animation event that tells your code if the timer should activate?

    A little confused.

    I hope you see this hehe.
     
    Zusero100 likes this.
  16. Silver_Weave

    Silver_Weave

    Joined:
    Jul 18, 2012
    Posts:
    7
    You could try getting the length of your animation clips and set the combo timer to that each time you press the combo button.
     
  17. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    I really dont understand why people dont use Enums types instead of bool types.


    Code (CSharp):
    1. public enum ComboType
    2. {
    3.     Combo1,
    4.     Combo2,
    5.     Combo3
    6. }
     
  18. MathewHI

    MathewHI

    Joined:
    Mar 29, 2016
    Posts:
    501
    This is a great system but it only runs 1 time because your resetting the timer in the Start() method the timer never resets.
    I just hard coded my time like this in ResetComboState
    currentComboTimer = .2f;
     
  19. MathewHI

    MathewHI

    Joined:
    Mar 29, 2016
    Posts:
    501
    How can I make the last button press be different from the Z key?