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.
using UnityEngine;
using System.Collections;
public class New_Combo_System : MonoBehaviour
{
public bool firstButtonPress = false;
public bool secondButtonPress = false;
public bool thirdButtonPress = false;
public float comboTimer = 0.5f;
public int currentComboState = 1;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
NewComboSystem ();
}
void ComboStateUpdate ()
{
currentComboState ++;
// increments combo state by 1
}
void ResetComboState()
{
currentComboState = 1;
//resets combo state to it's default value of 1
}
void NewComboSystem()
{
if (Input.GetKeyDown (KeyCode.Z) currentComboState == 1)
{
Debug.Log("1 hit");
firstButtonPress = true;
ComboStateUpdate();
Invoke("ResetComboState",comboTimer);
}
if (Input.GetKeyDown (KeyCode.Z) currentComboState == 2 firstButtonPress == true)
{
Debug.Log("2 hits");
firstButtonPress = false;
ResetComboState();
}
}
}
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
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.
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?
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.
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.
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.
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.
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
public class New_Combo_System : MonoBehaviour
{
bool ActivateTimerToReset = false;
//The more bools, the less readibility, try to stick with the essentials.
//If you were to press 10 buttons in a row
//having 10 booleans to check for those would be confusing
public float comboTimer = 0.5f;
public int currentComboState = 0;
// Update is called once per frame, yeah everybody knows this
void Update()
{
NewComboSystem();
//Initially set to false, so the method won't start
ResetComboState(ActivateTimerToReset);
}
void ResetComboState(bool ChooseYourWonderfulBoolName)
{
if (ChooseYourWonderfulBoolName)
//if the bool that you pass to the method is true
// (aka if ActivateTimerToReset is true, then the timer start
{
comboTimer -= Time.Deltatime;
//If the parameter bool is set to true, a timer start, when the timer
//runs out (because you don't press fast enought Z the second time)
//currentComboState is set again to zero, and you need to press it twice again
if (comboTimer <= 0)
{
currentComboState = 0;
ActivateTimerToReset = false;
comboTimer = 0.5f;
}
}
}
void NewComboSystem()
{
if (Input.GetKeyDown(KeyCode.Z))
{
//Note that I'm to lazy to setup a switch statement
//that would be WAY more readable than 3 if's in a row
if (currentComboState == 0)
{
currentComboState++;
//No need to create a comboStateUpdate()
//function while you can directly
//increment a variable using ++ operator
ActivateTimerToReset = true;
//Okay, you pressed Z once, so now the resetcombostate Function is
//set to true, and the timer starts to reset the currcombostate
Debug.Log("1 hit");
}
if (currentComboState == 1)
{
currentComboState++;
Debug.Log("2 hit, The combo Should Start");
//Do your awesome stuff there and combokill the bitches
}
if (currentComboState >= 2)
{
Debug.Log("Whooaaa 3 hits in half a second!");
//I bet this will blast everthing off the screen
}
}
}
}
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
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).
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)
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:
using UnityEngine;
using System.Collections;
public class ComboMonitorTemplate : MonoBehaviour {
bool ActivateTimerToReset = false;
//The more bools, the less readibility, try to stick with the essentials.
//If you were to press 10 buttons in a row
//having 10 booleans to check for those would be confusing
public float currentComboTimer;
public int currentComboState = 0;
float origTimer;
void Start()
{
// Store original timer reset duration
origTimer = currentComboTimer;
}
// Update is called once per frame, yeah everybody knows this
void Update()
{
NewComboSystem();
//Initially set to false, so the method won't start
ResetComboState(ActivateTimerToReset);
}
void ResetComboState(bool resetTimer)
{
if (resetTimer)
//if the bool that you pass to the method is true
// (aka if ActivateTimerToReset is true, then the timer start
{
currentComboTimer -= Time.deltaTime;
//If the parameter bool is set to true, a timer start, when the timer
//runs out (because you don't press fast enought Z the second time)
//currentComboState is set again to zero, and you need to press it twice again
if (currentComboTimer <= 0)
{
currentComboState = 0;
ActivateTimerToReset = false;
currentComboTimer = origTimer;
}
}
}
void NewComboSystem()
{
if (Input.GetKeyDown(KeyCode.Z))
{
//No need to create a comboStateUpdate()
//function while you can directly
//increment a variable using ++ operator
currentComboState++;
//Okay, you pressed Z once, so now the resetcombostate Function is
//set to true, and the timer starts to reset the currcombostate
ActivateTimerToReset = true;
//Note that I'm to lazy to setup a switch statement
//that would be WAY more readable than 3 if's in a row
if (currentComboState == 1)
{
Debug.Log("1 hit");
}
if (currentComboState == 2)
{
Debug.Log("2 hit, The combo Should Start");
//Do your awesome stuff there and combokill the bitches
}
if (currentComboState >= 3)
{
Debug.Log("Whooaaa 3 hits in half a second!");
//I bet this will blast everthing off the screen
}
}
}
}
Hi @CodeFriendlyArt 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?
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;