0

I'm currently working on a match-3 game genre in the Unity engine, and I'm using some gem artwork for it. I've encountered a situation where, after storing the gem positions in a 2D array and swapping them, I need to update the array again.

I have two questions:

Why do we need to update a 2D array again, considering it's already been updated? What is this concept called in programming? Could you please recommend a book or tutorial to learn more about it?

And please note that there's no need to read all of the code; please only focus on the sections where I've mentioned in the comments

class 1 :


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

    public class Board : MonoBehaviour
    {
    public int width;
    public int height;
    public GameObject backgroundTilePrefab;

    public Gem[] gems;
    
    //this one
    public Gem[,] allGems;

    public float gemSpeed;

    public MatchFinder matchFinder;

    private void Awake()
    {
        matchFinder = FindObjectOfType<MatchFinder>();
    }
    private void Start()
    {  
        //this one
        allGems = new Gem[width, height];
        
        Setup();
        

    }

    private void Update()
    {
        matchFinder.FindAllMatches();
    }
    private void Setup()
    {
        for (int x = 0; x < width; x++)
        {
            for (int y = 0; y < height; y++)
            {
                Vector2 pos = new Vector2(x, y);
                GameObject backgroundTile = Instantiate(backgroundTilePrefab,pos,Quaternion.identity);
                backgroundTile.transform.parent = transform;
                backgroundTile.transform.name = "Background Tile " + x + "," + y;

                int gemToUse = Random.Range(0, gems.Length);

                int iterations = 0;
                while (MatchesAt(new Vector2Int(x,y), gems[gemToUse]) && iterations < 100)
                {
                    gemToUse = Random.Range(0, gems.Length);
                    print("already matched found");
                    iterations++;
                }

                SpawnGem(gems[gemToUse],new Vector2Int(x,y));

                
            }
        }
    }

    private void SpawnGem(Gem gemToSpawn,Vector2Int pos)
    {
        Gem gem = Instantiate(gemToSpawn,new Vector3(pos.x,pos.y,0),Quaternion.identity);
        gem.transform.parent = transform;
        gem.transform.name = "Gem " + pos.x + "," + pos.y;

        //this one
        allGems[pos.x, pos.y] = gem;

        gem.SetupGem(pos,this);
    }

    bool MatchesAt(Vector2Int posToCheck, Gem gemToCheck)
    {
        if (posToCheck.x > 1)
        {
            if (allGems[posToCheck.x - 1,posToCheck.y].gemTypes == gemToCheck.gemTypes && allGems[posToCheck.x - 2, posToCheck.y].gemTypes == gemToCheck.gemTypes)
            {
                return true;
            }
        }


        if (posToCheck.y > 1)
        {
            if (allGems[posToCheck.x, posToCheck.y - 1].gemTypes == gemToCheck.gemTypes && allGems[posToCheck.x, posToCheck.y -2].gemTypes == gemToCheck.gemTypes)
            {
                return true;
            }
        }

        return false;
    }

    public void DestroyMatchesGemAt(Vector2Int pos)
    {
        if (allGems[pos.x,pos.y] != null)
        {
            if (allGems[pos.x,pos.y].isMatched)
            {
                Destroy(allGems[pos.x,pos.y].gameObject);
                allGems[pos.x,pos.y] = null;
            }
        }
    }

    public void DestroyMatches()
    {
        for (int i=0; i < matchFinder.currentMatches.Count; i++)
        {
            if (matchFinder.currentMatches[i] != null)
            {
                DestroyMatchesGemAt(matchFinder.currentMatches[i].posIndex);
            }
        }
        StartCoroutine(DecreaseRowCoroutine());
    }

    public int nullCounter;
    IEnumerator DecreaseRowCoroutine()
    {
        yield return new WaitForSeconds(0.2f);

        nullCounter = 0;

        for (int x=0; x < width; x++)
        {
            for (int y=0;y<height;y++)
            {
                if (allGems[x,y] == null)
                {
                    nullCounter++;

                }else if (nullCounter > 0)
                {
                    
                    allGems[x, y - nullCounter] = allGems[x, y];
                    allGems[x, y - nullCounter].posIndex.y -= nullCounter;
                    allGems[x, y] = null;

                }
            }
        }
    }
}

class 2 :

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

    public class Gem : MonoBehaviour
    {
    public Vector2Int posIndex;
    public Board board;
    public enum GemTypes { blue, green, red,purple,yellow }
    public GemTypes gemTypes;
    public bool isMatched;

    public Vector2Int previousPos;
    // Start is called before the first frame update
    void Start()
    {
       
    }

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

        

        if (mousePressed && Input.GetMouseButtonUp(0))
        {
            mousePressed = false;
            finalTouchPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            CalculateAngle();
            

        }

        if (Vector2.Distance(transform.position,posIndex) > 0.01f)
        {
            transform.position = Vector2.Lerp(transform.position, posIndex, board.gemSpeed * Time.deltaTime);
        }else
        {
            transform.position = new Vector3(posIndex.x,posIndex.y);
            board.allGems[posIndex.x,posIndex.y] = this;
        }
    }

    public void SetupGem(Vector2Int posIndex,Board board)
    {
        this.posIndex = posIndex;
        this.board = board;
    }

    public Vector2 firstTouchPosition;
    public bool mousePressed;
    public Vector2 finalTouchPosition;
    public float swipeAngle;


    private void OnMouseDown()
    {
        firstTouchPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        //Debug.Log(firstTouchPosition);
        mousePressed = true;
    }

    private void CalculateAngle()
    {
        swipeAngle = Mathf.Atan2(finalTouchPosition.y - firstTouchPosition.y, finalTouchPosition.x - firstTouchPosition.x);
        swipeAngle = swipeAngle * 180 / Mathf.PI;
        print(swipeAngle);

        if (Vector2.Distance(firstTouchPosition,finalTouchPosition) > 0.5f)
        {
            MovePieces();
        }
    }

    Gem otherGem;
    private void MovePieces()
    {

        previousPos = posIndex;

        //drag left to right
        
        if (swipeAngle < 45 && swipeAngle > -45 && posIndex.x < board.width - 1)
        {
            otherGem = board.allGems[posIndex.x + 1, posIndex.y];
            otherGem.posIndex.x--;
            posIndex.x++;
        }
        //drag down to up

        else if (swipeAngle > 45 && swipeAngle < 135 && posIndex.y < board.height - 1)
        {
            otherGem = board.allGems[posIndex.x , posIndex.y + 1];
            otherGem.posIndex.y--;
            posIndex.y++;
        }

        //drag up to down

        else if (swipeAngle < -45 && swipeAngle > -135 && posIndex.y  > 0)
        {
            otherGem = board.allGems[posIndex.x, posIndex.y - 1];
            otherGem.posIndex.y++;
            posIndex.y--;
        }

        //drag right to left

        else if (swipeAngle > 135 || swipeAngle < -135 && posIndex.x > 0)
        {
            otherGem = board.allGems[posIndex.x - 1, posIndex.y];
            otherGem.posIndex.x++;
            posIndex.x--;

        }
        //my main problem is these 2 following lines

        board.allGems[posIndex.x, posIndex.y] = this;
        board.allGems[otherGem.posIndex.x,otherGem.posIndex.y] = otherGem;

        

        StartCoroutine(CheckMoveCoroutine());

    }//MovePieces()

    public IEnumerator CheckMoveCoroutine()
    {
        yield return new WaitForSeconds(0.5f);

        //board.matchFinder.FindAllMatches();

        if (otherGem != null)
        {
            if (!isMatched && !otherGem.isMatched)
            {
                otherGem.posIndex = posIndex;
                posIndex = previousPos;

                board.allGems[posIndex.x, posIndex.y] = this;
                board.allGems[otherGem.posIndex.x, otherGem.posIndex.y] = otherGem;
            }else
            {
                board.DestroyMatches();
            }
        }
    }



}//class
1
  • Your question isnt clear, you ask why you update a 2d array when you declare allgems as 2d..
    – BugFinder
    Commented Mar 24 at 12:45

1 Answer 1

0

if I understanded correctly by updating array you mean this part:

private void SpawnGem(Gem gemToSpawn,Vector2Int pos)
{
    Gem gem = Instantiate(gemToSpawn,new Vector3(pos.x,pos.y,0),Quaternion.identity);
    gem.transform.parent = transform;
    gem.transform.name = "Gem " + pos.x + "," + pos.y;

    //this one
    allGems[pos.x, pos.y] = gem;

    gem.SetupGem(pos,this);
}

I think you misunderstood Instantiate functionality. when you call Instantiate you should give it a reference to prefab then it will clone that prefab into new GameObject in scene. if you give it an already existing GameObject in scene it will do similar thing (clone it into new GameObject) that most likely is not desired behavior.

so I think that is the problem, gem freshly created in this method and no one has reference to it so you need to assign it in array. after instantiating, gem and gemToSpawn have nothing to do with each other.

or maybe I didn't understand your problem correctly if so, please specify the part of code that you had problem with, those are very large portion of codes to track.

4
  • thanks for your time sir but my code works fine and my question is in Gem class and i want to know why we have to update a 2d array - there is two line that i commented with this text : // main problem
    – Play Plus
    Commented Mar 24 at 11:14
  • you are tracking your board state with that 2D array (as far as I can see), if you don't update array you'll have a gem with e.g. posIndex = {3, 0} that stayed at previous position in array that is [4, 0]. in this design you have to keep posIndex in gem objects and their indexes in array in sync.
    – Noobogami
    Commented Mar 24 at 12:47
  • is this have specific name in programming ?
    – Play Plus
    Commented Mar 25 at 11:17
  • if it has, I don't know but it's redundancy and (as I know) somehow is a bad practice, exactly because of your question. you always have to keep in mind and track two similar data changes.
    – Noobogami
    Commented Mar 25 at 13:44

Not the answer you're looking for? Browse other questions tagged or ask your own question.