Pages

Friday, April 27, 2012

Unity3D + C#: SequenceEqual() // Similarity between the sequence of two arrays

Problem
While working on a combo-related project, I stumble upon a problem on how to check whether my inputs can match any of those in my combo library, thus activating the corresponding action. Such as in those action fighting game where you press punches and kicks in a sequence, in order to unlock an awesome combo animation which instantly kills your opponent.


Originally, I intend to solve the problem by using for loop and while loop... which later on, sent me into an infinite loop of confusion. @_@

Luckily I found a much simpler solution in MSDN, called SequenceEqual() which you could use to compare the contents of arrays and its sequences easily. 

SequenceEqual()
Now I'm gonna show an example on how you can use this function to do the array checking.

1. First, let's create a new C# script called "ComboHandler", and then create a serializable attribute which we can use to store the combo arrays:

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


[System.Serializable]
public class Combo
{
    public string name;
    public string[] comboSequence;
}

The name variable will be the name of the combo you wanna activate, while combo sequence will be... the combos. You can start adding combos by declaring a public variable using the Combo serializable class:

public Combo[] combos;

2. Save and go to the Unity editor. Add in the script into anything, Main Camera or create an empty game object, and you shall see an array called "combos". Expand it, set the size to 2, and start making some combos. For this example, I created two combos: 
- name: "Fire Punch", comboSequence: "Punch", "Punch", "Kick"
- name: "Thunder Kick", comboSequence: "Kick", "Knock", "Kick"



3. Next, declare 3 more variables:

public int comboLimit = 3;
private string comboActivated;
private List<string> comboToAdd;

"comboLimit" => the number of combo sequences you can enter at one time. For default, I set it to 3, because most of the combo sequences I set in part 1, has a size of 3.
"comboActivated" => the combo you activated with the sequence you inputed
"comboToAdd" => the array which stores the sequence of combos which you're gonna input in later on

4. Before using the string List<> array, you need to first "assigned" it in Start(), else it'll give you a crazy NullReferenceException errors:

void Start() 
{
    comboToAdd = new List<string>();
}

5. Create 3 buttons in OnGUI() which you can press and add combo into the "comboToAdd" array, and a box as a displayer of the combo you activated:

void OnGUI() 
{
    if (GUI.Button(new Rect(20, 20, 100, 100), "Punch"))
    {
        comboToAdd.Add("Punch");
    }
    if (GUI.Button(new Rect(130, 20, 100, 100), "Kick"))
    {
        comboToAdd.Add("Kick");
    }
    if (GUI.Button(new Rect(240, 20, 100, 100), "Knock"))
    {
        comboToAdd.Add("Knock");
    }

    GUI.Box(new Rect(20, 140, 320, 50), comboActivated);
}

It should show up as something like this:


6. Finally, in the Update() function, I'm gonna check whether I've inputed more than the maximum combo sequence limit. And if I do, check whether the combo sequence match any of those in the combo arrays I set in part 1. If has a match, set the "comboActivated" (string) variable as the name of the combo matched. Clear everything in the "comboToAdd" array so that player can input more combo sequence into the array and activate other combos:

void Update() 
{
    if (comboToAdd.Count >= comboLimit)
    {
        for (int i=0; i<combos.Length; i++)
        {
            if (comboToAdd.SequenceEqual(combos[i].comboSequence))
            {
                comboActivated = combos[i].name;
            }
        }
        comboToAdd.Clear();
    }
}

7. By right, SequenceEqual() will not be available if you have not added "using System.Linq" at the top of the script. So add one now right away:

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

8. Press 'Play' in the editor, and you shall see the combo in the works.


Combos:
Fire Punch - "Punch" + "Punch" + "Kick"
Thunder Kick - "Kick" + "Knock" + "Kick"


Download the complete script

Equal() and ReferenceEqual()
Even before I learned about SequenceEqual(), there's already something called Equals() and ReferenceEqual(), which according to its description, "helps determine whether the specific object is equal to the current instance". 

Now I'm not really an IT person, but what I can understand so far when testing with it is that, the Equal() function (which returns a boolean) helps check whether array B is of a clone of array A. If you are comparing array A with a newly created array B, even if you add in similar contents and sequences in it as array A, it will still return a false.

No comments: