How can I speed up my current solution?

Essentially, I am creating an 8x8 grid with tiles that can be clicked on. When a tile is clicked it changes to one of 6 tile types, all in a preset order. Additionally when that tile is clicked the tile in the “opposite” position changes to reflect the same tile type (grid position 0,0 changes, so does position 63,63 and vice versa). The end goal for this is a mechanic that is a part of a digital board game where you can customize the tile configurations before taking them into a game against another opponent (hence why the tiles need to “flip” mirror each other (not sure what the correct term I’m looking for is).

Right now the code is moving noticeably slower than I’d like, I realize I may not have the most efficient solution here but I’d like some help with ideas on how to improve it. I’ve never done a post like this on any site, so I’m sorry if this format for showing my code isn’t exactly correct. Below is my BoardTile script attached to each tile. Thank you in advance for any assistance or references!

//BoardTile script
 using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class BoardTile : MonoBehaviour
    {
        [SerializeField] private SpriteRenderer _tileRenderer;
        [SerializeField] Sprite[] _tileImageArray;
    
        public enum BoardTileType { 1, 2, 3, 4, 5, 6};
        public BoardTileType tileType;
    
        public bool checkedForChange = true;
        public bool mouseDownDisabled = true;
    
        // Start is called before the first frame update
        void Start()
        {
            tileType = BoardTileType.1;
        }
    
        // Update is called once per frame
    //changes the sprite to match the appropriate image
        void Update()
        {
            switch (tileType)
            {
                case BoardTileType.1:
                    _tileRenderer.sprite = _tileImageArray[0];
                    break;
                case BoardTileType.2:
                    _tileRenderer.sprite = _tileImageArray[1];
                    break;
                case BoardTileType.3:
                    _tileRenderer.sprite = _tileImageArray[2];
                    break;
                case BoardTileType.4:
                    _tileRenderer.sprite = _tileImageArray[3];
                    break;
                case BoardTileType.5:
                    _tileRenderer.sprite = _tileImageArray[4];
                    break;
                case BoardTileType.6:
                    _tileRenderer.sprite = _tileImageArray[5];
                    break;
                default:
                    break;
            }
        }
    
    //When the player clicks a tile changes it to the next tile in the enum order
        public void OnMouseDown()
        {
            if (mouseDownDisabled)
            {
                switch (tileType)
                {
                    case BoardTileType.1:
                        tileType = BoardTileType.2;
                        checkedForChange = false;
                        break;
                    case BoardTileType.2:
                        tileType = BoardTileType.3;
                        checkedForChange = false;
                        break;
                    case BoardTileType.3:
                        tileType = BoardTileType.4;
                        checkedForChange = false;
                        break;
                    case BoardTileType.4:
                        tileType = BoardTileType.5;
                        checkedForChange = false;
                        break;
                    case BoardTileType.5:
                        tileType = BoardTileType.6;
                        checkedForChange = false;
                        break;
                    case BoardTileType.6:
                        tileType = BoardTileType.1;
                        checkedForChange = false;
                        break;
                    default:
                        break;
                }
                mouseDownDisabled = false;
            }
        }
    
    //used to change the "opposite" tile from the BoardSetupController
    //example: if 0,0 changed from 1 to 2 then 63,63 changed from 1 to 2 and vice versa
        public void ChangeTileType()
        {
            switch (tileType)
            {
                case BoardTileType.1:
                    tileType = BoardTileType.2;
                    break;
                case BoardTileType.2:
                    tileType = BoardTileType.3;
                    break;
                case BoardTileType.3:
                    tileType = BoardTileType.4;
                    break;
                case BoardTileType.4:
                    tileType = BoardTileType.5;
                    break;
                case BoardTileType.5:
                    tileType = BoardTileType.6;
                    break;
                case BoardTileType.6:
                    tileType = BoardTileType.1;
                    break;
                default:
                    break;
            }
        }
    }

BoardSetupController Script

 //BoardSetupController Script
    using System.Collections;
    using System.Collections.Generic;
    using TMPro;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class BoardSetupController : MonoBehaviour
    {
        [SerializeField] private int _width, _height;
        [SerializeField] private Transform _camera;
        [SerializeField] private BoardSetupTile _boardSetupTilePrefab;
        [SerializeField] private TMP_Text tileOneCountText;
        [SerializeField] private TMP_Text tileTwoCountText;
        [SerializeField] private TMP_Text tileThreeCountText;
        [SerializeField] private TMP_Text tileFourCountText;
        [SerializeField] private TMP_Text tileFiveCountText;
        [SerializeField] private TMP_Text tileSixCountText;
    
        private List<BoardTile> tileList = new List<BoardTile>();
        private int xVal = 0;
        private bool gridCreated = false;
        int[] tileAmounts = new int[] { 0, 0, 0, 0, 0, 0 };
    
        // Start is called before the first frame update
        void Start()
        {
            GenerateGrid();
        }
    
        private void Update()
        {
            if (gridCreated)
            {
                checkGridChanges();
                    //change the text of the ui counters
                    updateUiCounter();
            }
        }
    
        void GenerateGrid()
        {
            float xPos = (float)-6.25;
            float yPos = (float)2.85;
    
            for (int x = 0; x < _width; x++)
            {
                for (int y = 0; y < _height; y++)
                {
                    var spawnedDefaultTile = Instantiate(_boardSetupTilePrefab, new Vector3((float)(xPos + (y*0.8)), (float)(yPos - (x*0.8))), Quaternion.identity);
                    spawnedDefaultTile.name = $"BoardTile {x},{y}";
                    tileList.Add(spawnedDefaultTile);
                }
            }
            gridCreated = true;
            updateUiCounter();
        }
    
        //this method is what updates the board to make sure opposites tile match each other
        void checkGridChanges()
        {
            if (xVal >= tileList.Count && gridCreated)
            {
                xVal = 0;
            }
            else if (xVal <= tileList.Count && gridCreated)
            {
                //if the tile at this poisiton has not been checked for change
                if (tileList[xVal].checkedForChange == false)
                {
                    //flip the tileList
                    tileList.Reverse();
                    //call ChangeTileType on the opposite tile
                    tileList[xVal].ChangeTileType();
                    //flip the list back to its original order
                    tileList.Reverse();
                    //tile has now been checked so set to true
                    tileList[xVal].checkedForChange = true;
                    //prevent race 
                    tileList[xVal].mouseDownDisabled = true;
                }
                xVal++;
            }
        }
    
        //there are ui counters that update to reflect the type of tile present on the board
        void updateUiCounter()
        {
            tileAmounts[0] = 0;
            tileAmounts[1] = 0;
            tileAmounts[2] = 0;
            tileAmounts[3] = 0;
            tileAmounts[4] = 0;
            tileAmounts[5] = 0;
           for(int i = 0; i < tileList.Count; i++)
            {
                var tileType = tileList*.tileType;*

switch (tileType)
{
case BoardTile.BoardTileType.1:
tileAmounts[0]++;
break;
case BoardTile.BoardTileType.2:
tileAmounts[1]++;
break;
case BoardTile.BoardTileType.3:
tileAmounts[2]++;
break;
case BoardTile.BoardTileType.4:
tileAmounts[3]++;
break;
case BoardTile.BoardTileType.5:
tileAmounts[4]++;
break;
case BoardTile.BoardTileType.6:
tileAmounts[5]++;
break;
default:
break;
}
}

//loop through the array of tileAmounts and display them
updateCounterText();
}

void updateCounterText()
{
for (int i = 0; i < tileAmounts.Length; i++)
{
if (tileAmounts < 10)
{
switch (i)
{
case 0:
tileOneCountText.text = "0{tileAmounts*}x";*_</em> <em>_*break;*_</em> <em>_*case 1:*_</em> <em><em>_tileTwoCountText.text = “0{tileAmounts*}x”;*
break;
case 2:
tileThreeCountText.text = "0{tileAmounts*}x";*_</em></em></em> <em><em><em>_*break;*_</em></em></em> <em><em><em>_*case 3:*_</em></em></em> <em><em><em><em>_tileFourCountText.text = “0{tileAmounts*}x”;*
break;
case 4:
tileFiveCountText.text = "0{tileAmounts*}x";*_</em></em></em></em></em> <em><em><em><em><em>_*break;*_</em></em></em></em></em> <em><em><em><em><em>_*case 5:*_</em></em></em></em></em> <em><em><em><em><em><em>_tileSixCountText.text = “0{tileAmounts*}x”;*
break;
default:
break;
}
}
else
{
switch (i)
{
case 0:
tileOneCountText.text = "{tileAmounts*}x";*_</em></em></em></em></em></em></em> <em><em><em><em><em><em><em>_*break;*_</em></em></em></em></em></em></em> <em><em><em><em><em><em><em>_*case 1:*_</em></em></em></em></em></em></em> <em><em><em><em><em><em><em><em>_tileTwoCountText.text = “{tileAmounts*}x”;*
break;
case 2:
tileThreeCountText.text = "{tileAmounts*}x";*_</em></em></em></em></em></em></em></em></em> <em><em><em><em><em><em><em><em><em>_*break;*_</em></em></em></em></em></em></em></em></em> <em><em><em><em><em><em><em><em><em>_*case 3:*_</em></em></em></em></em></em></em></em></em> <em><em><em><em><em><em><em><em><em><em>_tileFourCountText.text = “{tileAmounts*}x”;*
break;
case 4:
tileFiveCountText.text = "{tileAmounts*}x";*_</em></em></em></em></em></em></em></em></em></em></em> <em><em><em><em><em><em><em><em><em><em><em>_*break;*_</em></em></em></em></em></em></em></em></em></em></em> <em><em><em><em><em><em><em><em><em><em><em>_*case 5:*_</em></em></em></em></em></em></em></em></em></em></em> <em><em><em><em><em><em><em><em><em><em><em><em>_tileSixCountText.text = “{tileAmounts*}x”;*
break;
default:
break;
}
}
}
}
}

I am not sure what is suppose to be slow except the GenerateGridFunction and maybe the checkGridChanges(). I note that in the checkGridChanges use a really cleaver, but terribly inefficient way of doing what you are trying to do. (you wont notice if you have only 64x64 tiles, but in bigger board you will see the difference) You should be able to find the opposing tile in one operation. It should be something like (size of board) - (position of your tile you just clicked).


Also, your code is suffering from multiple issue in term of design.

  • It seems to me that you are not harvesting the full potential of event base programmation. (If you really want to have the control on your tile. a.k.a checking if the tile has been clicked). Notably, because of that, you do have strange way (error prone? definitely harder to understand/maintain) of controlling mirroring of your tile.
  • You have a “mouseDisable” variable that is use for race condition ? Unity is synchronous, you should not have any issue with race condition.
  • You are using a lot of switch case that could be easily converted in function (usage of modulo), polymorphism for each tile type (maybe) or dictionary/array for updateCounterText.
  • You use magical value for the positioning of your tile.
  • If your board is static (always the same size), you should serialize your tile (create them in the scene). This way, you will be able to use the hyper-optimize process of loading scene.
  • Line 133 to 183 should be a function. (It could a one liner with the usage of an array/dictionary and ternary operation)

Alright, I think I found the issue after analyzing your code. You are using a really particular way of mirroring your tile. Your application is not slow, it is because your updating 1 tile at a time. If you run at 60 fps, in worst case your going to wait more than 1min (4096 frames(tiles to update) / 60 frames per seconds).