How to identify and count prefab collisions at Unity

6

I'm developing a game for android on the unity platform that is similar to the Tetris game, the difference that is geared towards chemistry, and instead of going down the tetrominos will go down the elements to compose a molecule. Well, what logic I'm trying to apply: to form a carbon it is necessary that the C has 4 H around it to close. From there I used flags for the prefabs carbons and for hydrogens. My idea is when to lower the C, check if there is C, then it will go to the next conditions, which is to know if there is an H on some of its sides, when the counter reaches 4 is because the C closed with the 4 H. However, in practice it did not work. Can anyone help me with this logic, or an easier suggestion? In the image below the C is composed of 4 H, hence was to punctuate and delete these 5 pieces (4 H and C).

heisnotdoingthechecks;

Andhere'smycode:

publicvoidChecks(){for(inty=0;y<gridHeight;++y){for(intx=0;x<gridWidth;++x){if(Grid[x,y]!=null){if(Grid[x,y].tag=="CARBONO") {
                    Debug.Log ("EXISTE C: ");
                    if (Grid [x + 1, y].tag == "HIDROGENIO") {
                        cont++;
                    }
                    if (Grid [x - 1, y].tag == "HIDROGENIO") {
                        cont++;
                    }
                    if (Grid [x, y + 1].tag == "HIDROGENIO") {
                        cont++;
                    }
                    if (Grid [x, y - 1].tag == "HIDROGENIO") {
                        cont++;
                    }
                }
                Debug.Log ("contador: " + cont); //teste
            }
        }
    }
}

GAME Class:

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class Game : MonoBehaviour {

public static int gridWidth = 10;
public static int gridHeight = 20;
public static Transform[,] Grid = new Transform[gridWidth, gridHeight];
public static Tetromino[,] model = new Tetromino[gridWidth, gridHeight];
private GameObject previewTetromino;
private GameObject nextTetromino;
private bool gameStarted = false;
public int scoreOneLine = 40;
public int scoreTwoLine = 100;
public int cont = 0;
private int numerOfRowsThisTurn = 0;
public Text hud_score;
public static int currentScore = 0;
private Vector2 previewTetrominoPosition = new Vector2 (13.88f, 11.08f);


// Use this for initialization
void Start () {
    SpawnNextTetromino ();


    //AudioSource = GetComponent<AudioSource> ();
} 

void Update () {
    Checks ();
    UpdateScore ();
    UpdateUI ();
}

// Update is called once per frame
public void UpdateScore(){
    if (numerOfRowsThisTurn > 0) {

        if (numerOfRowsThisTurn == 1) {
            ClearedOneLine ();
        } else if (numerOfRowsThisTurn == 2) {
            ClearedTwoLine ();
        }
        numerOfRowsThisTurn = 0;
    }
}

public void Checks(){

    for (int y = 0; y < gridHeight; ++y) {
        for (int x = 0; x < gridWidth; ++x) {
            if (Grid [x, y] != null) {

                if (Grid [x, y].tag == "CARBONO") {
                    Debug.Log ("EXISTE C: ");
                    if (Grid [x + 1, y].tag == "HIDROGENIO") {
                        cont++;
                    }
                    if (Grid [x - 1, y].tag == "HIDROGENIO") {
                        cont++;
                    }
                    if (Grid [x, y + 1].tag == "HIDROGENIO") {
                        cont++;
                    }
                    if (Grid [x, y - 1].tag == "HIDROGENIO") {
                        cont++;
                    }
                }
                Debug.Log ("contador: " + cont); //teste
            }
        }
    }
}

public void UpdateUI(){
    hud_score.text = currentScore.ToString ();
}



public void ClearedOneLine(){
    currentScore += scoreOneLine;
}
public void ClearedTwoLine(){
    currentScore += scoreTwoLine;
}

public bool CheckIsAboveGrid(Tetromino tetromino){
    for(int x = 0; x < gridWidth; ++x){
        foreach(Transform mino in tetromino.transform){
            Vector2 pos = Round (mino.position);
            if(pos.y > gridHeight - 1){
                return true;
            }
        }
    }
    return false;
}

public bool IsFullRowAt(int y){
    for (int x = 0; x < gridWidth; ++x){
        if(Grid[x,y] = null){
            return false;
        }
    }
    numerOfRowsThisTurn++;
    return true;
}

public void updateGrid (Tetromino tetromino) {
    for (int y = 0; y <gridHeight; ++y) {
        for (int x = 0; x <gridWidth; ++x) {
            if (Grid [x, y] != null) {
                if (Grid [x, y].parent == tetromino.transform) {
                    Grid [x, y] = null;
                    model [x, y] = null;
                }
            }
        }
    }
    foreach (Transform mino in tetromino.transform) {
        Vector2 pos = Round (mino.position);
        if (pos.y < gridHeight) {
            Grid [(int)pos.x, (int)pos.y] = mino;
            model [(int)pos.x, (int)pos.y] = tetromino;
        }
    }
}
public Transform GetTransformAtGetPosition (Vector2 pos) {
    if (pos.y > gridHeight - 1) {
        return null;
    } else {
        return Grid [(int)pos.x, (int)pos.y];
    }

}

public void SpawnNextTetromino () {
    if (!gameStarted) {

        gameStarted = true;
        nextTetromino = (GameObject)Instantiate(Resources.Load(GetRandomTetromino(), typeof(GameObject)), new Vector2 (5.0f, 22.0f), Quaternion.identity);
        previewTetromino = (GameObject)Instantiate (Resources.Load (GetRandomTetromino (), typeof(GameObject)), previewTetrominoPosition, Quaternion.identity);
        previewTetromino.GetComponent<Tetromino> ().enabled = false;

    } else {
        previewTetromino.transform.localPosition = new Vector2 (5.0f, 20.0f);
        nextTetromino = previewTetromino;
        nextTetromino.GetComponent<Tetromino> ().enabled = true;

        previewTetromino = (GameObject)Instantiate (Resources.Load (GetRandomTetromino (), typeof(GameObject)), previewTetrominoPosition, Quaternion.identity);
        previewTetromino.GetComponent<Tetromino> ().enabled = false;
    }

}


public bool CheckIsInsideGrid (Vector2 pos){
    return ((int)pos.x >= 0 && (int)pos.x < gridWidth && (int)pos.y >= 0);
}

public Vector2 Round (Vector2 pos){
    return new Vector2 (Mathf.Round(pos.x), Mathf.Round(pos.y));
}

string GetRandomTetromino(){
    int randomTetromino = Random.Range (1, 5);
    string randomTetrominoName = "Prefabs/C";
    switch (randomTetromino) {
    case 1:
        randomTetrominoName = "Prefabs/H";

        break;
    case 2:
        randomTetrominoName = "Prefabs/C";
        break;
    case 3:
        randomTetrominoName = "Prefabs/H";
        break;
    case 4:
        randomTetrominoName = "Prefabs/C";
        break;

    }
    return randomTetrominoName;


}

TETROMINO Class:

using UnityEngine;
using System.Collections;

public class Tetromino : MonoBehaviour {

float fall = 0;
public float fallSpeed = 2;
public bool allowRotation = true;
public bool limitRoatation = false;

public int individualScore = 100;
private float individualScoreTime;

public static int UP = 1;  
public static int DOWN = 2;
public static int RIGHT = 3;
public static int LEFT = 4;
private bool visited = false;
private bool fullConection = false;
private Tetromino[] connections = new Tetromino[4];


// Update is called once per frame
void Update () {

    CheckUserInput ();
    UpdateIndividualScore ();
}

public void UpdateIndividualScore(){

    if (individualScoreTime < 1) {

        individualScoreTime += Time.deltaTime;

    } else {

        individualScoreTime = 0;

        individualScore = Mathf.Max (individualScore - 10, 0);
    }
}
public void CheckUserInput () {
            if (Input.GetKeyDown(KeyCode.RightArrow)) {

                transform.position += new Vector3(1, 0, 0);

                if (CheckIsValidPosition()) {

                    FindObjectOfType<Game>().updateGrid(this);
                    FindObjectOfType<Game> ().Checks ();
                } else {

                    transform.position += new Vector3(-1, 0, 0);
                }

            } else if (Input.GetKeyDown(KeyCode.LeftArrow)) {

                transform.position += new Vector3(-1, 0, 0);

                if (CheckIsValidPosition()) {

                    FindObjectOfType<Game>().updateGrid(this);
                    FindObjectOfType<Game> ().Checks ();
                } else {

                    transform.position += new Vector3(1, 0, 0);
                }
            } else if (Input.GetKeyDown(KeyCode.UpArrow)) {

                if (allowRotation) {

                    if (limitRoatation) {

                        if (transform.rotation.eulerAngles.z >= 90) {

                            //transform.Rotate(0, 0, -90);

                        } else {

                            //transform.Rotate(0, 0, 90);
                        }
                    } else {
                        transform.Rotate (0, 0, 90);
                    }

                    if (CheckIsValidPosition()) {

                        FindObjectOfType<Game>().updateGrid(this);
                        FindObjectOfType<Game> ().Checks ();
                    } else {

                        if (transform.rotation.eulerAngles.z >= 90) {

                            //transform.Rotate(0, 0, -90);

                        } else {
                            /*if (limitRoatation) {
                                transform.Rotate (0, 0, 90);

                            }*/

                            //transform.Rotate (0, 0, -90);
                        }
                    }
                }

            } else if (Input.GetKeyDown(KeyCode.DownArrow) || Time.time - fall >= fallSpeed) {

                transform.position += new Vector3(0, -1, 0);

                if (CheckIsValidPosition()) {

                    FindObjectOfType<Game>().updateGrid(this);
                    //FindObjectOfType<Game> ().Checks ();

                } else {

                    transform.position += new Vector3(0, 1, 0);

                    if (FindObjectOfType<Game> ().CheckIsAboveGrid (this)) {
                        FindObjectOfType<Game> ().GameOver ();
                    }

                    enabled = false;


                    FindObjectOfType<Game> ().updateConnection (this);
                    FindObjectOfType<Game> ().Checks ();
                    FindObjectOfType<Game> ().SpawnNextTetromino ();

                    Game.currentScore += individualScore;


                }

                fall = Time.time;
            }
        }

bool CheckIsValidPosition () {

    foreach (Transform mino in transform) {

    Vector2 pos = FindObjectOfType<Game>().Round (mino.position);

    if (FindObjectOfType<Game>().CheckIsInsideGrid (pos) == false) {

            return false;
        }

        if (FindObjectOfType<Game>().GetTransformAtGetPosition(pos) != null && FindObjectOfType<Game>().GetTransformAtGetPosition(pos).parent != transform) {

            return false;
        }
    }

    return true;
}
    
asked by anonymous 20.06.2016 / 16:52

1 answer

3

Before suggesting an algorithm to deal with what you actually need, I'll take the liberty of offering some tips that may help you perhaps even another future reader:

  • Use comments . Your code has virtually no comment on what it does. Okay, it could be your style of programming. But that makes it difficult for someone else to understand what you have produced. It even hinders its own future maintenance, since it is common for us to forget the details of what we did after a long time without working on the project. You could comment on the methods, indicating what they serve or what they do, and at least on the attributes of the classes to indicate what they are / are used for.

  • Organize the code . Your code is a bit messy, too. Again, each one has its own style. But indentation is not just for aesthetics: it facilitates reading and makes it easy to find where things are defined.

  • Use Object Orientation well . The OO exists because of an important principle: it facilitates thinking about the problem. If you do not follow it, you lose the advantage of using it. Okay, not everyone understands these concepts deeply, but it does not cost to study properly right? In your case, for example, you put behaviors that should be of the moving part (which I deem to be the Tetromino's) in the class that controls the game. The verification behavior of molecule formation may seem to make more sense in the game class, but it is not the last Tetromino that moves that is capable of forming a molecule (after all, the others that are already stacked have not formed anything yet, because they would have disappeared and turned into points, right?). An indicator that there are problems there is the fact that there is code in the Tetromino class that often invokes methods of the Game class (the check method, for example).

    li>

    Well, about your solution, colleague @SoeiroMass gave a nice tip . But supposing that you will not only have these two elements (hydrogen and carbon), this type of verification will become impractical. What I suggest is that you program in the Tetromino class , a list engine that holds the neighboring elements (that is, already connected). Thus, given any Tetromino, it will be possible to query from it (via a method call of type getNeighbours ) which elements are already connected to it.

    This list will be kept for each of the individual Tetrominos , from its detection of collision ". To do this, add a Unity collider and set it to "trigger" (since you do not need the physics and do the translation manually). So, create the OnTriggerEnter2D method (I'm assuming your game is 2D) to capture the event in the Tetromino class. Note that each element will receive this event, since they all have their colliders / triggers. So when A collides with B, A will add B to your list, and B will add A to your list.

    Once you have this list and a method of accessing it, you can make the Game class receive an event (a warning via method call even) when Tetromino is currently falling down . He is the only one that matters from the point of view of the game, since only he is able to build a valid molecule (right? After all, if the already positioned ones had valid molecules, they would already have been "treated" by the game). The game then requests the list of neighbors and compares it with a template. This template is for you to know if the union of neighbors forms something real (the carbon molecule, for example), and can be kept in a configuration file read and ideally accessed by another class specific to it. There are several ways to implement this template and its comparison. One is to have a simple sum of characters. Assuming each element has an identifier that is its letter (i.e. C , H , etc.), combinations of them will also be simple counting strings (i.e. CHHH or HCHH , etc). In fact, this string with the letters can be the one that returns the method of consultation to the neighbors, and is even easier to compare with the template if in assembling this string the alphabetical order of the letters is guaranteed.

        
  • 24.06.2016 / 19:35