Help with a combo based system similar to DDR

Hi I’m new to using unity and still trying to grasp the key concepts. I have been trying to make a simple combo based game where a random combo (out of 6 possible combos) will show on the screen (each of which is a image attached to a game object on canvas). the player must then complete the combo without error within a given time to deal damage to the enemy. If they cannot the player will take damage and a new combo will be shown. I have been testing with just one combo and cannot seem to get it right. Any help and guidance would be greatly appreciated.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ComboBreaker : MonoBehaviour
{
public GameObject Set1P;
public GameObject Set2P;
public GameObject Set3P;
public GameObject Set4P;
public GameObject Set5P;
public GameObject Set6P;
public GameObject Set1E;
public GameObject Set2E;
public GameObject Set3E;
public GameObject Set4E;
public GameObject Set5E;
public GameObject Set6E;

public int PlayerHP = 5;
public int EnemyHP = 5;

public KeyCode[] combo;
public int currentIndex = 0;


void Start()
{
//StartCoroutine(functionName());

Set1P = GameObject.FindGameObjectWithTag("S1P"); // Get all Combo Sets s1p= Set One Player/ s1e = Set One enemy
Set2P = GameObject.FindGameObjectWithTag("S2P");
Set3P = GameObject.FindGameObjectWithTag("S3P");
Set4P = GameObject.FindGameObjectWithTag("S4P");
Set5P = GameObject.FindGameObjectWithTag("S5P");
Set6P = GameObject.FindGameObjectWithTag("S6P");

Set1E = GameObject.FindGameObjectWithTag("S1E");
Set2E = GameObject.FindGameObjectWithTag("S2E");
Set3E = GameObject.FindGameObjectWithTag("S3E");
Set4E = GameObject.FindGameObjectWithTag("S4E");
Set5E = GameObject.FindGameObjectWithTag("S5E");
Set6E = GameObject.FindGameObjectWithTag("S6E");

}

void Update()
{

if(EnemyHP > 0 || PlayerHP > 0)
{

System.Random rand = new System.Random();//get random variable for set
int set = rand.Next(1, 2); // random between 1 and 6, only using one to test with

if (set == 1) // Random = 1, Show Set 1 and complete there will be 6
{
Set1P.SetActive(true); // Set Active both set 1's
Set1E.SetActive(true);
Set2E.SetActive(false);
Set3E.SetActive(false);
Set4E.SetActive(false);
Set5E.SetActive(false);
Set6E.SetActive(false);
Set2P.SetActive(false);
Set3P.SetActive(false);
Set4P.SetActive(false);
Set5P.SetActive(false);
Set6P.SetActive(false);


int AIspeed1 = rand.Next(1, 4); // time between 1 and 3 sec/key
int AIspeed2 = rand.Next(1, 4);
int AIspeed3 = rand.Next(1, 4);
int AIspeed4 = rand.Next(1, 4);
float AIcomplete = AIspeed1 + AIspeed2 + AIspeed3 + AIspeed4; // Ai's time to complete combo player must complete faster

AIcomplete -= Time.deltaTime;

if (Input.GetKeyDown(KeyCode.DownArrow) && AIcomplete > 0) // if key correct go to next or take damage
{
if (Input.GetKeyDown(KeyCode.LeftArrow) && AIcomplete > 0)
{
print("Left key pressed");
if (Input.GetKeyDown(KeyCode.UpArrow) && AIcomplete > 0)
{
print("up key pressed");
if (Input.GetKeyDown(KeyCode.RightArrow) && AIcomplete > 0)
{
print("right key pressed");
--EnemyHP;
}
else if (Input.GetKeyDown(KeyCode.LeftArrow) || Input.GetKeyDown(KeyCode.UpArrow) || Input.GetKey(KeyCode.DownArrow))
{
--PlayerHP;
}
}
else if (Input.GetKeyDown(KeyCode.LeftArrow) || Input.GetKeyDown(KeyCode.RightArrow) || Input.GetKeyDown(KeyCode.DownArrow))
{
--PlayerHP;
}
}
else if (Input.GetKeyDown(KeyCode.RightArrow) || Input.GetKeyDown(KeyCode.UpArrow) || Input.GetKeyDown(KeyCode.DownArrow))
{
--PlayerHP;
}
}
else if (Input.GetKeyDown(KeyCode.LeftArrow) || Input.GetKeyDown(KeyCode.UpArrow) || Input.GetKeyDown(KeyCode.RightArrow))
{
--PlayerHP;
}

if (PlayerHP <=0 || EnemyHP <= 0)
{
GameOver();
}

print("looped");
}
}


}

void GameOver()
{
Time.timeScale = 0;
//set GameOver Active
}

}

Please read this post to see how to insert code properly into the forums and then edit your post :slight_smile:

Have you tried some of the tutorials from the Learn section?

Hi methos5k, I have tried some of the tutorials, and do seem to get those to work correctly. I’m just not entirely sure if I attacked this in the correct way, or if there is a error in my input system. When I run the script, it does decrease player hp, but for some reason it decreases no matter the key I press, even if pressed in correct order.

Sorry, I am/was a little too tired to respond to some issues you might have there.

  1. Look into how to connect game objects in the inspector. :slight_smile: Rather than all of those GameObject.Find
  2. Update runs every frame, and you’re getting a new random number there and setting things active/in-active, etc… Pretty sure you don’t want that.
    2b) you’re also doing the same w/ the aispeed which you probably don’t want.

What I think you’re trying to get done, at least in this testing phase, is get the user input and check if it’s part of the combo (in the right sequence)… getting it done before the AI ?

I would start by moving parts that don’t need to be in the Update loop outside of it; either in a setup method, or (for example) a ‘DealDamage’ method. The damage taking could check for death/game over when you lose HP, for instance, rather than polling that check inside update.

I think there could be a bit more, too, but maybe some of that feedback can be helpful? :slight_smile: I hope so…

1 Like

Thank you very much, I will definitely make use of your guidance. I’ve tried it and seems to have more functions working now. I still have to try to add in the get inputs, but seems to be better organized.

One thing I see in your code is that you’re nesting your GetKeyDown’s within each other.(see lines 81-83 for what I’m referring to). This is the wrong way to get combos because Unity is running through this code all in the same frame, not sequentially. In other words, you’ll only ever get to line 84 if the user presses down and left on the exact same frame. Clearly you meant for it to be “if the user presses down, then left”, but that’s not what it does.

You’ll need to track which buttons have been pressed across frames, in other words, in separate run-throughs of the Update function. For example, you may have a int comboCounter which starts at 0, and with each correct key press gets 1 added to it:

int comboCounter = 0;
void Update() {
if (comboCounter == 0 && Input.GetKeyDown(KeyCode.Down) ) comboCounter = 1;
if (comboCounter == 1 && Input.GetKeyDown(KeyCode.Left) ) comboCounter = 2;
if (comboCounter == 2 ) {
//the user has pressed down, then left
}

This will get you to be functional, but it’s still not very good. For one, each keystroke of every combo needs to be tediously hardcoded. For two, any incorrect keystrokes in between these won’t reset the combo.

First thing’s first. My main advice would be to make this driven by data instead of being hardcoded. Start by learning how arrays work. After that tutorial, you’ll be able to create a combo tracker that simply crawls along an array of KeyCodes (which you may assign and modify as a sequence in the inspector):

int comboCounter = 0;
public KeyCode[] combo = new KeyCode[]{KeyCode.Down, KeyCode.Left};

void Update() {
if (comboCounter < combo.Length) {
if (Input.GetKeyDown(combo[comboCounter]) comboCounter++;
//TODO: reset counter on incorrect keystrokes
}
else {
//combo was finished
}
}

For the second issue, you want to detect if the user has pressed a key that isn’t the correct one, and reset the combo counter. Insert this line where that TODO is:

 else if (Input.anyKeyDown) comboCounter = 0;

This should give you a better, more versatile foundation to build your combo system on. From here, you should be able to fairly simply add new and different combos as needed. You could even randomly generate the combos being required if you want.

1 Like

Wow thank you very much StarSanta, yes the combo counter is really useful to me for this program. It seems too be working right now, but updates to fast so I am not able to use enter any key.