Search Unity

Help with a match-3 game

Discussion in 'Scripting' started by Khyinn, Mar 1, 2017.

  1. Khyinn

    Khyinn

    Joined:
    Feb 28, 2017
    Posts:
    5
    Hi,

    First, i'm new to Unity and C# scripting so i try to learn with a match-3 game.

    My game runs fine but i try to add some features :

    1) Shuffle my grid when no more matches can be found;
    2) Add the possibility to store possible matches so we can highlight one of them after some time;
    3) Fill the grid even if there are ROCK blocks on top of the Grid;
    4) Add the possibility to collect ingredients.

    Currently, my game has these features :
    - 6 different colors;
    - Vertical and horizontal "Bombs";
    - Clear color "Bomb";
    - Obstacles (called ICE in my game);
    - Unbreakable ROCK blocks (need to modify the FillStep() function to add support to these blocks);
    - Score based, obstacles based and time based levels.

    Here is my grid class (i think it's possible to fix 1), 2) and 3) just with this but 4) will need to show other scripts (like Level class) so it will be implemented later if someone accept to help ^^)

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. public class Grid : MonoBehaviour {
    7.  
    8.     public enum PieceType
    9.     {
    10.         EMPTY,
    11.         NORMAL,
    12.         ICE,
    13.         ROW_CLEAR,
    14.         COLUMN_CLEAR,
    15.         RAINBOW,
    16.         NONE,
    17.         ROCK,
    18.         COUNT,
    19.     };
    20.  
    21.     [System.Serializable]
    22.     public struct PiecePrefab
    23.     {
    24.         public PieceType type;
    25.         public GameObject prefab;
    26.     };
    27.  
    28.     [System.Serializable]
    29.     public struct PiecePosition
    30.     {
    31.         public PieceType type;
    32.         public int x;
    33.         public int y;
    34.     };
    35.  
    36.     // Grid size
    37.     public int xDim;
    38.     public int yDim;
    39.     // Time to fill/refill the grid
    40.     public float fillTime;
    41.  
    42.     // Used to call the level class
    43.     public Level level;
    44.  
    45.     // Array of piece types that can be defined in the inspector
    46.     public PiecePrefab[] piecePrefabs;
    47.     // GameObject to set a background for our pieces
    48.     public GameObject backgroundPrefab;
    49.  
    50.     // Used to set our initial pieces in the inspector, for each level
    51.     public PiecePosition[] initialPieces;
    52.  
    53.     // Dictionary for attaching a piece to its prefab
    54.     private Dictionary<PieceType, GameObject> piecePrefabDict;
    55.  
    56.     // 2D array to contain all our pieces
    57.     private GamePiece[,] pieces;
    58.  
    59.     // Used to move pieces in diag (for filling a grid with obstacles)
    60.     private bool inverse = false;
    61.  
    62.     // Used to know wich pieces will be swapped
    63.     private GamePiece pressedPiece;
    64.     private GamePiece enteredPiece;
    65.  
    66.     // Set the game over. Doesn't mean that the player loose
    67.     private bool gameOver = false;
    68.  
    69.     // Use this for initialization
    70.     void Awake () {
    71.         piecePrefabDict = new Dictionary<PieceType, GameObject> ();
    72.  
    73.         // First we need to check if we have keys in our dictionary. If not, add them
    74.         for (int i = 0; i < piecePrefabs.Length; i++) {
    75.             if (!piecePrefabDict.ContainsKey (piecePrefabs [i].type)) {
    76.                 piecePrefabDict.Add (piecePrefabs [i].type, piecePrefabs [i].prefab);
    77.             }
    78.         }
    79.  
    80.         // Instantiate the background for all our pieces on the grid
    81.         for (int x = 0; x < xDim; x++) {
    82.             for (int y = 0; y < yDim; y++) {
    83.                 GameObject background = (GameObject)Instantiate (backgroundPrefab, GetWorldPosition(x, y), Quaternion.identity);
    84.                 background.transform.parent = transform;
    85.             }
    86.         }
    87.  
    88.         // Now we need to add our initial and empty pieces on the grid
    89.         pieces = new GamePiece[xDim, yDim];
    90.  
    91.         for (int i = 0; i < initialPieces.Length; i++) {
    92.             if (initialPieces [i].x >= 0 && initialPieces [i].x < xDim
    93.                 && initialPieces [i].y >= 0 && initialPieces [i].y < yDim) {
    94.                 SpawnNewPiece (initialPieces [i].x, initialPieces [i].y, initialPieces [i].type);
    95.             }
    96.         }
    97.  
    98.         for (int x = 0; x < xDim; x++) {
    99.             for (int y = 0; y < yDim; y++) {
    100.                 if (pieces [x, y] == null) {
    101.                     SpawnNewPiece (x, y, PieceType.EMPTY);
    102.                 }
    103.             }
    104.         }
    105.  
    106.         // Now the grid is filled with empty pieces, we need to replace them by our non-empty pieces with animation
    107.         StartCoroutine(Fill ());
    108.     }
    109.  
    110.     // Update is called once per frame
    111.     void Update () {
    112.  
    113.     }
    114.  
    115.     // Fill the grid
    116.     public IEnumerator Fill()
    117.     {
    118.         bool needsRefill = true;
    119.  
    120.         while (needsRefill) {
    121.             yield return new WaitForSeconds (fillTime);
    122.  
    123.             while (FillStep ()) {
    124.                 inverse = !inverse;
    125.                 yield return new WaitForSeconds (fillTime);
    126.             }
    127.  
    128.             needsRefill = ClearAllValidMatches ();
    129.         }
    130.         CheckAllPossibleMatches ();
    131.     }
    132.  
    133.     // Move a piece to fill the grid
    134.     // Todo : add a check for ROCK Pieces so that they'll be ignored when filling the grid as they can't be destroyed and can be on top of the grid
    135.     public bool FillStep()
    136.     {
    137.         bool movedPiece = false;
    138.  
    139.         for (int y = yDim-2; y >= 0; y--)
    140.         {
    141.             for (int loopX = 0; loopX < xDim; loopX++)
    142.             {
    143.                 int x = loopX;
    144.  
    145.                 if (inverse) {
    146.                     x = xDim - 1 - loopX;
    147.                 }
    148.  
    149.                 GamePiece piece = pieces [x, y];
    150.  
    151.                 if (piece.IsMovable ())
    152.                 {
    153.                     GamePiece pieceBelow = pieces [x, y + 1];
    154.  
    155.                     if (pieceBelow.Type == PieceType.EMPTY) {
    156.                         Destroy (pieceBelow.gameObject);
    157.                         piece.MovableComponent.Move (x, y + 1, fillTime);
    158.                         pieces [x, y + 1] = piece;
    159.                         SpawnNewPiece (x, y, PieceType.EMPTY);
    160.                         movedPiece = true;
    161.                     } else {
    162.                         for (int diag = -1; diag <= 1; diag++)
    163.                         {
    164.                             if (diag != 0)
    165.                             {
    166.                                 int diagX = x + diag;
    167.  
    168.                                 if (inverse)
    169.                                 {
    170.                                     diagX = x - diag;
    171.                                 }
    172.  
    173.                                 if (diagX >= 0 && diagX < xDim)
    174.                                 {
    175.                                     GamePiece diagonalPiece = pieces [diagX, y + 1];
    176.  
    177.                                     if (diagonalPiece.Type == PieceType.EMPTY)
    178.                                     {
    179.                                         bool hasPieceAbove = true;
    180.  
    181.                                         for (int aboveY = y; aboveY >= 0; aboveY--)
    182.                                         {
    183.                                             GamePiece pieceAbove = pieces [diagX, aboveY];
    184.  
    185.                                             if (pieceAbove.IsMovable ())
    186.                                             {
    187.                                                 break;
    188.                                             }
    189.                                             else if(!pieceAbove.IsMovable() && pieceAbove.Type != PieceType.EMPTY)
    190.                                             {
    191.                                                 hasPieceAbove = false;
    192.                                                 break;
    193.                                             }
    194.                                         }
    195.  
    196.                                         if (!hasPieceAbove)
    197.                                         {
    198.                                             Destroy (diagonalPiece.gameObject);
    199.                                             piece.MovableComponent.Move (diagX, y + 1, fillTime);
    200.                                             pieces [diagX, y + 1] = piece;
    201.                                             SpawnNewPiece (x, y, PieceType.EMPTY);
    202.                                             movedPiece = true;
    203.                                             break;
    204.                                         }
    205.                                     }
    206.                                 }
    207.                             }
    208.                         }
    209.                     }
    210.                 }
    211.             }
    212.         }
    213.  
    214.         for (int x = 0; x < xDim; x++)
    215.         {
    216.             GamePiece pieceBelow = pieces [x, 0];
    217.  
    218.             if (pieceBelow.Type == PieceType.EMPTY)
    219.             {
    220.                 Destroy (pieceBelow.gameObject);
    221.                 GameObject newPiece = (GameObject)Instantiate(piecePrefabDict[PieceType.NORMAL], GetWorldPosition(x, -1), Quaternion.identity);
    222.                 newPiece.transform.parent = transform;
    223.  
    224.                 pieces [x, 0] = newPiece.GetComponent<GamePiece> ();
    225.                 pieces [x, 0].Init (x, -1, this, PieceType.NORMAL);
    226.                 pieces [x, 0].MovableComponent.Move (x, 0, fillTime);
    227.                 pieces [x, 0].ColorComponent.SetColor ((ColorPiece.ColorType)Random.Range (0, pieces [x, 0].ColorComponent.NumColors));
    228.                 movedPiece = true;
    229.             }
    230.         }
    231.  
    232.         return movedPiece;
    233.     }
    234.  
    235.     // Used to get the offset of our pieces
    236.     public Vector2 GetWorldPosition(int x, int y)
    237.     {
    238.         return new Vector2 (transform.position.x - xDim / 2.0f + x,
    239.             transform.position.y + yDim / 2.0f - y);
    240.     }
    241.  
    242.     // Spawn a new piece
    243.     public GamePiece SpawnNewPiece(int x, int y, PieceType type)
    244.     {
    245.         GameObject newPiece = (GameObject)Instantiate (piecePrefabDict [type], GetWorldPosition (x, y), Quaternion.identity);
    246.         newPiece.transform.parent = transform;
    247.  
    248.         pieces [x, y] = newPiece.GetComponent<GamePiece> ();
    249.         pieces [x, y].Init (x, y, this, type);
    250.  
    251.         return pieces [x, y];
    252.     }
    253.  
    254.     // Used to know if piece1 is adjacent to piece2
    255.     public bool IsAdjacent(GamePiece piece1, GamePiece piece2)
    256.     {
    257.         return (piece1.X == piece2.X && (int)Mathf.Abs (piece1.Y - piece2.Y) == 1)
    258.             || (piece1.Y == piece2.Y && (int)Mathf.Abs (piece1.X - piece2.X) == 1);
    259.     }
    260.  
    261.     // Swap pieces if they are adjacent
    262.     public void SwapPieces(GamePiece piece1, GamePiece piece2)
    263.     {
    264.         // If the game is over, just disabled this function
    265.         if (gameOver) {
    266.             return;
    267.         }
    268.  
    269.         // Swap only if they are movable
    270.         if (piece1.IsMovable () && piece2.IsMovable ()) {
    271.             pieces [piece1.X, piece1.Y] = piece2;
    272.             pieces [piece2.X, piece2.Y] = piece1;
    273.  
    274.             if (GetMatch (piece1, piece2.X, piece2.Y) != null || GetMatch (piece2, piece1.X, piece1.Y) != null
    275.                 || piece1.Type == PieceType.RAINBOW || piece2.Type == PieceType.RAINBOW) {
    276.  
    277.                 int piece1X = piece1.X;
    278.                 int piece1Y = piece1.Y;
    279.  
    280.                 // Make some animation while swaping
    281.                 piece1.MovableComponent.Move (piece2.X, piece2.Y, fillTime);
    282.                 piece2.MovableComponent.Move (piece1X, piece1Y, fillTime);
    283.  
    284.                 // Clear the Rainbow piece manually before clearing matches
    285.                 if (piece1.Type == PieceType.RAINBOW && piece1.IsClearable () && piece2.IsColored ()) {
    286.                     ClearColorPiece clearColor = piece1.GetComponent<ClearColorPiece> ();
    287.  
    288.                     if (clearColor) {
    289.                         clearColor.Color = piece2.ColorComponent.Color;
    290.                     }
    291.  
    292.                     ClearPiece (piece1.X, piece1.Y);
    293.                 }
    294.  
    295.                 if (piece2.Type == PieceType.RAINBOW && piece2.IsClearable () && piece1.IsColored ()) {
    296.                     ClearColorPiece clearColor = piece2.GetComponent<ClearColorPiece> ();
    297.  
    298.                     if (clearColor) {
    299.                         clearColor.Color = piece1.ColorComponent.Color;
    300.                     }
    301.  
    302.                     ClearPiece (piece2.X, piece2.Y);
    303.                 }
    304.  
    305.                 // Now we need to clear all pieces from this match
    306.                 ClearAllValidMatches ();
    307.  
    308.                 if (piece1.Type == PieceType.ROW_CLEAR || piece1.Type == PieceType.COLUMN_CLEAR) {
    309.                     ClearPiece (piece1.X, piece1.Y);
    310.                 }
    311.  
    312.                 if (piece2.Type == PieceType.ROW_CLEAR || piece2.Type == PieceType.COLUMN_CLEAR) {
    313.                     ClearPiece (piece2.X, piece2.Y);
    314.                 }
    315.  
    316.                 pressedPiece = null;
    317.                 enteredPiece = null;
    318.  
    319.                 // And finally refilling the board
    320.                 StartCoroutine (Fill ());
    321.  
    322.                 // Declares a player move
    323.                 level.OnMove();
    324.             } else {
    325.                 // No match, return pieces to their own positions
    326.                 pieces [piece1.X, piece1.Y] = piece1;
    327.                 pieces [piece2.X, piece2.Y] = piece2;
    328.             }
    329.         }
    330.     }
    331.  
    332.     // Assign piece when piece is pressed
    333.     public void PressPiece(GamePiece piece)
    334.     {
    335.         pressedPiece = piece;
    336.     }
    337.  
    338.     // Assign piece when piece is entered
    339.     public void EnterPiece(GamePiece piece)
    340.     {
    341.         enteredPiece = piece;
    342.     }
    343.  
    344.     // Swap pieces when piece is released
    345.     public void ReleasePiece()
    346.     {
    347.         if (IsAdjacent (pressedPiece, enteredPiece)) {
    348.             SwapPieces (pressedPiece, enteredPiece);
    349.         }
    350.     }
    351.  
    352.     // Used to know if pieces can match
    353.     public List<GamePiece> GetMatch(GamePiece piece, int newX, int newY)
    354.     {
    355.         if (piece.IsColored ()) {
    356.             ColorPiece.ColorType color = piece.ColorComponent.Color;
    357.             List<GamePiece> horizontalPieces = new List<GamePiece> ();
    358.             List<GamePiece> verticalPieces = new List<GamePiece> ();
    359.             List<GamePiece> matchingPieces = new List<GamePiece> ();
    360.  
    361.             // First check horizontal
    362.             horizontalPieces.Add(piece);
    363.  
    364.             for (int dir = 0; dir <= 1; dir++) {
    365.                 for (int xOffset = 1; xOffset < xDim; xOffset++) {
    366.                     int x;
    367.  
    368.                     if (dir == 0) { // Left
    369.                         x = newX - xOffset;
    370.                     } else { // Right
    371.                         x = newX + xOffset;
    372.                     }
    373.  
    374.                     if (x < 0 || x >= xDim) {
    375.                         break;
    376.                     }
    377.  
    378.                     if (pieces [x, newY].IsColored () && pieces [x, newY].ColorComponent.Color == color) {
    379.                         horizontalPieces.Add (pieces [x, newY]);
    380.                     } else {
    381.                         break;
    382.                     }
    383.                 }
    384.             }
    385.  
    386.             if (horizontalPieces.Count >= 3) {
    387.                 for (int i = 0; i < horizontalPieces.Count; i++) {
    388.                     matchingPieces.Add (horizontalPieces [i]);
    389.                 }
    390.             }
    391.  
    392.             // Traverse vertically if we found a match (for L and T shapes)
    393.             if (horizontalPieces.Count >= 3) {
    394.                 for (int i = 0; i < horizontalPieces.Count; i++) {
    395.                     for (int dir = 0; dir <= 1; dir++) {
    396.                         for (int yOffset = 1; yOffset < yDim; yOffset++) {
    397.                             int y;
    398.  
    399.                             if (dir == 0) { // Up
    400.                                 y = newY - yOffset;
    401.                             } else { // Down
    402.                                 y = newY + yOffset;
    403.                             }
    404.  
    405.                             if (y < 0 || y >= yDim) {
    406.                                 break;
    407.                             }
    408.  
    409.                             if (pieces [horizontalPieces [i].X, y].IsColored () && pieces [horizontalPieces [i].X, y].ColorComponent.Color == color) {
    410.                                 verticalPieces.Add (pieces [horizontalPieces [i].X, y]);
    411.                             } else {
    412.                                 break;
    413.                             }
    414.                         }
    415.                     }
    416.  
    417.                     if (verticalPieces.Count < 2) {
    418.                         verticalPieces.Clear ();
    419.                     } else {
    420.                         for (int j = 0; j < verticalPieces.Count; j++) {
    421.                             matchingPieces.Add (verticalPieces [j]);
    422.                         }
    423.  
    424.                         break;
    425.                     }
    426.                 }
    427.             }
    428.  
    429.             if (matchingPieces.Count >= 3) {
    430.                 return matchingPieces;
    431.             }
    432.  
    433.             // Didn't find anything going horizontally first,
    434.             // so now check vertically
    435.             horizontalPieces.Clear();
    436.             verticalPieces.Clear ();
    437.             verticalPieces.Add(piece);
    438.  
    439.             for (int dir = 0; dir <= 1; dir++) {
    440.                 for (int yOffset = 1; yOffset < yDim; yOffset++) {
    441.                     int y;
    442.  
    443.                     if (dir == 0) { // Up
    444.                         y = newY - yOffset;
    445.                     } else { // Down
    446.                         y = newY + yOffset;
    447.                     }
    448.  
    449.                     if (y < 0 || y >= yDim) {
    450.                         break;
    451.                     }
    452.  
    453.                     if (pieces [newX, y].IsColored () && pieces [newX, y].ColorComponent.Color == color) {
    454.                         verticalPieces.Add (pieces [newX, y]);
    455.                     } else {
    456.                         break;
    457.                     }
    458.                 }
    459.             }
    460.  
    461.             if (verticalPieces.Count >= 3) {
    462.                 for (int i = 0; i < verticalPieces.Count; i++) {
    463.                     matchingPieces.Add (verticalPieces [i]);
    464.                 }
    465.             }
    466.  
    467.             // Traverse horizontally if we found a match (for L and T shapes)
    468.             if (verticalPieces.Count >= 3) {
    469.                 for (int i = 0; i < verticalPieces.Count; i++) {
    470.                     for (int dir = 0; dir <= 1; dir++) {
    471.                         for (int xOffset = 1; xOffset < xDim; xOffset++) {
    472.                             int x;
    473.  
    474.                             if (dir == 0) { // Left
    475.                                 x = newX - xOffset;
    476.                             } else { // Right
    477.                                 x = newX + xOffset;
    478.                             }
    479.  
    480.                             if (x < 0 || x >= xDim) {
    481.                                 break;
    482.                             }
    483.  
    484.                             if (pieces [x, verticalPieces[i].Y].IsColored () && pieces [x, verticalPieces[i].Y].ColorComponent.Color == color) {
    485.                                 horizontalPieces.Add (pieces [x, verticalPieces[i].Y]);
    486.                             } else {
    487.                                 break;
    488.                             }
    489.                         }
    490.                     }
    491.  
    492.                     if (horizontalPieces.Count < 2) {
    493.                         horizontalPieces.Clear ();
    494.                     } else {
    495.                         for (int j = 0; j < horizontalPieces.Count; j++) {
    496.                             matchingPieces.Add (horizontalPieces [j]);
    497.                         }
    498.  
    499.                         break;
    500.                     }
    501.                 }
    502.             }
    503.  
    504.             if (matchingPieces.Count >= 3) {
    505.                 return matchingPieces;
    506.             }
    507.         }
    508.  
    509.         return null;
    510.     }
    511.  
    512.     // Clear all matches for one player move
    513.     public bool ClearAllValidMatches()
    514.     {
    515.         bool needsRefill = false;
    516.  
    517.         for (int y = 0; y < yDim; y++) {
    518.             for (int x = 0; x < xDim; x++) {
    519.                 if (pieces [x, y].IsClearable ()) {
    520.                     List<GamePiece> match = GetMatch (pieces [x, y], x, y);
    521.  
    522.                     if (match != null) {
    523.                         // Start Special piece spawning
    524.                         PieceType specialPieceType = PieceType.COUNT;
    525.                         GamePiece randomPiece = match [Random.Range (0, match.Count)];
    526.                         int specialPieceX = randomPiece.X;
    527.                         int specialPieceY = randomPiece.Y;
    528.  
    529.                         if (match.Count == 4) {
    530.                             if (pressedPiece == null || enteredPiece == null) {
    531.                                 specialPieceType = (PieceType)Random.Range ((int)PieceType.ROW_CLEAR, (int)PieceType.COLUMN_CLEAR);
    532.                             } else if (pressedPiece.Y == enteredPiece.Y) {
    533.                                 specialPieceType = PieceType.ROW_CLEAR;
    534.                             } else {
    535.                                 specialPieceType = PieceType.COLUMN_CLEAR;
    536.                             }
    537.                         } else if (match.Count >= 5) {
    538.                             specialPieceType = PieceType.RAINBOW;
    539.                         }
    540.                         // End Special piece spawning
    541.  
    542.                         for (int i = 0; i < match.Count; i++) {
    543.                             if (ClearPiece (match [i].X, match [i].Y)) {
    544.                                 needsRefill = true;
    545.  
    546.                                 if (match [i] == pressedPiece || match [i] == enteredPiece) {
    547.                                     specialPieceX = match [i].X;
    548.                                     specialPieceY = match [i].Y;
    549.                                 }
    550.                             }
    551.                         }
    552.  
    553.                         // Spawn the special piece
    554.                         if (specialPieceType != PieceType.COUNT) {
    555.                             Destroy (pieces [specialPieceX, specialPieceY]);
    556.                             GamePiece newPiece = SpawnNewPiece (specialPieceX, specialPieceY, specialPieceType);
    557.  
    558.                             if ((specialPieceType == PieceType.ROW_CLEAR || specialPieceType == PieceType.COLUMN_CLEAR)
    559.                                 && newPiece.IsColored () && match [0].IsColored ()) {
    560.                                 newPiece.ColorComponent.SetColor(match[0].ColorComponent.Color);
    561.                             } else if (specialPieceType == PieceType.RAINBOW && newPiece.IsColored ()) {
    562.                                 newPiece.ColorComponent.SetColor (ColorPiece.ColorType.ANY);
    563.                             }
    564.                         }
    565.                     }
    566.                 }
    567.             }
    568.         }
    569.  
    570.         return needsRefill;
    571.     }
    572.  
    573.     // Clear a piece and respawn an empty piece
    574.     public bool ClearPiece(int x, int y)
    575.     {
    576.         if (pieces [x, y].IsClearable () && !pieces [x, y].ClearableComponent.IsBeingCleared) {
    577.             pieces [x, y].ClearableComponent.Clear ();
    578.             SpawnNewPiece (x, y, PieceType.EMPTY);
    579.  
    580.             ClearObstacles (x, y);
    581.  
    582.             return true;
    583.         }
    584.  
    585.         return false;
    586.     }
    587.  
    588.     // Used to clear Ice pieces
    589.     public void ClearObstacles(int x, int y)
    590.     {
    591.         for (int adjacentX = x - 1; adjacentX <= x + 1; adjacentX++) {
    592.             if (adjacentX != x && adjacentX >= 0 && adjacentX < xDim) {
    593.                 if (pieces [adjacentX, y].Type == PieceType.ICE && pieces [adjacentX, y].IsClearable ()) {
    594.                     pieces [adjacentX, y].ClearableComponent.Clear ();
    595.                     SpawnNewPiece (adjacentX, y, PieceType.EMPTY);
    596.                 }
    597.             }
    598.         }
    599.  
    600.         for (int adjacentY = y - 1; adjacentY <= y + 1; adjacentY++) {
    601.             if (adjacentY != y && adjacentY >= 0 && adjacentY < yDim) {
    602.                 if (pieces [x, adjacentY].Type == PieceType.ICE && pieces [x, adjacentY].IsClearable ()) {
    603.                     pieces [x, adjacentY].ClearableComponent.Clear ();
    604.                     SpawnNewPiece (x, adjacentY, PieceType.EMPTY);
    605.                 }
    606.             }
    607.         }
    608.     }
    609.  
    610.     // Clear entire row
    611.     public void ClearRow(int row)
    612.     {
    613.         for (int x = 0; x < xDim; x++) {
    614.             ClearPiece (x, row);
    615.         }
    616.     }
    617.  
    618.     // Clear entire column
    619.     public void ClearColumn(int column)
    620.     {
    621.         for (int y = 0; y < yDim; y++) {
    622.             ClearPiece (column, y);
    623.         }
    624.     }
    625.  
    626.     // Clear all pieces with the same color
    627.     public void ClearColor(ColorPiece.ColorType color)
    628.     {
    629.         for (int x = 0; x < xDim; x++) {
    630.             for (int y = 0; y < yDim; y++) {
    631.                 if (pieces [x, y].IsColored () && (pieces [x, y].ColorComponent.Color == color
    632.                     || color == ColorPiece.ColorType.ANY)) {
    633.                     ClearPiece (x, y);
    634.                 }
    635.             }
    636.         }
    637.     }
    638.  
    639.     // Set the game over so the current level ends
    640.     public void GameOver()
    641.     {
    642.         gameOver = true;
    643.     }
    644.  
    645.     // Returns a list of pieces on the grid with the given type parameter
    646.     public List<GamePiece> GetPiecesOfType(PieceType type)
    647.     {
    648.         List<GamePiece> piecesOfType = new List<GamePiece> ();
    649.  
    650.         for (int x = 0; x < xDim; x++) {
    651.             for (int y = 0; y < yDim; y++) {
    652.                 if (pieces [x, y].Type == type) {
    653.                     piecesOfType.Add (pieces [x, y]);
    654.                 }
    655.             }
    656.         }
    657.  
    658.         return piecesOfType;
    659.     }
    660.  
    661.     // Used to know if two pieces have the same color
    662.     public bool IsSameColor(int x, int y, int color)
    663.     {
    664.         if (pieces [x, y].IsColored ()) {
    665.             return (int)pieces [x, y].ColorComponent.Color == color;
    666.         } else {
    667.             return false;
    668.         }
    669.     }
    670.  
    671.     // Used to check all possible matches on the grid
    672.     public void CheckAllPossibleMatches()
    673.     {
    674.         // If the game is over, just disabled this function
    675.         if (gameOver) {
    676.             return;
    677.         }
    678.  
    679.         // Vertical check
    680.         for (int x = 0; x < xDim; x++)
    681.         {
    682.             int secondToLastType = -1;
    683.             int lastType = -2;
    684.             int currentType = -3;
    685.  
    686.             for (int y = 0; y < yDim; y++)
    687.             {
    688.                 // Only if piece is colored and clearable
    689.                 if (pieces [x, y].IsClearable () && pieces [x, y].IsColored ())
    690.                 {
    691.                     currentType = (int)pieces [x, y].ColorComponent.Color;
    692.                     if (lastType == currentType) {
    693.                         if ((y > 2 && y < yDim - 3) && (x > 1 && x < xDim)) {
    694.                             /*
    695.                             * & * *
    696.                             * * * *
    697.                             * & * *
    698.                             * & * *
    699.                             */
    700.                             if (IsSameColor (x, y - 3, currentType))
    701.                                 return;
    702.                             /*
    703.                             * * * *
    704.                             * * & *
    705.                             * & * *
    706.                             * & * *
    707.                             */
    708.                             if (IsSameColor (x + 1, y - 2, currentType))
    709.                                 return;
    710.                             /*
    711.                             * * * *
    712.                             & * * *
    713.                             * & * *
    714.                             * & * *
    715.                             */
    716.                             if (IsSameColor (x - 1, y - 2, currentType))
    717.                                 return;
    718.                             /*
    719.                             * & * *
    720.                             * & * *
    721.                             * * * *
    722.                             * & * *
    723.                             */
    724.                             if (IsSameColor (x, y + 2, currentType))
    725.                                 return;
    726.                             /*
    727.                             * & * *
    728.                             * & * *
    729.                             * * & *
    730.                             * * * *
    731.                             */
    732.                             if (IsSameColor (x + 1, y + 1, currentType))
    733.                                 return;
    734.                             /*
    735.                             * & * *
    736.                             * & * *
    737.                             & * * *
    738.                             * * * *
    739.                             */
    740.                             if (IsSameColor (x - 1, y + 1, currentType))
    741.                                 return;
    742.                         }
    743.                     } else if (secondToLastType == currentType) {
    744.                         if (y > 1 && (x > 0 && x < xDim - 1)) {
    745.                             /*
    746.                             * & * *
    747.                             * * & *
    748.                             * & * *
    749.                             * * * *
    750.                             */
    751.                             if (IsSameColor (x + 1, y - 1, currentType))
    752.                                 return;
    753.                             Debug.Log ("VCheck8 " + (x - 1) + "," + (y - 1));
    754.                             /*
    755.                             * & * *
    756.                             & * * *
    757.                             * & * *
    758.                             * * * *
    759.                             */
    760.                             if (IsSameColor (x - 1, y - 1, currentType))
    761.                                 return;
    762.                         }
    763.                     }
    764.                     secondToLastType = lastType;
    765.                     lastType = currentType;
    766.                 }
    767.             }
    768.         }
    769.  
    770.         // Horizontal check
    771.         for (int y = 0; y < yDim; y++)
    772.         {
    773.             int secondToLastType = -1;
    774.             int lastType = -2;
    775.             int currentType = -3;
    776.  
    777.             for (int x = 0; x < xDim; x++)
    778.             {
    779.                 // Only if piece is colored and clearable
    780.                 if (pieces [x, y].IsClearable () && pieces [x, y].IsColored ())
    781.                 {
    782.                     currentType = (int)pieces [x, y].ColorComponent.Color;
    783.                     if (lastType == currentType) {
    784.                         if ((x > 2 && x < xDim - 3) && (y > 1 && y < yDim)) {
    785.                             /*
    786.                             * & * & & *
    787.                             */
    788.                             if (IsSameColor (x - 3, y, currentType))
    789.                                 return;
    790.                             /*
    791.                             * * * & & *
    792.                             * * & * * *
    793.                             */
    794.                             if (IsSameColor (x - 2, y + 1, currentType))
    795.                                 return;
    796.                             /*
    797.                             * * & * * *
    798.                             * * * & & *
    799.                             */
    800.                             if (IsSameColor (x - 2, y - 1, currentType))
    801.                                 return;
    802.                             /*
    803.                             * & & * & *
    804.                             */
    805.                             if (IsSameColor (x + 2, y, currentType))
    806.                                 return;
    807.                             /*
    808.                             * & & * * *
    809.                             * * * & *
    810.                             */
    811.                             if (IsSameColor (x + 1, y + 1, currentType))
    812.                                 return;
    813.                             /*
    814.                             * * * & * *
    815.                             * & & * * *
    816.                             */
    817.                             if (IsSameColor (x + 1, y - 1, currentType))
    818.                                 return;
    819.                         }
    820.                     } else if (secondToLastType == currentType) {
    821.                         if (x > 1 && (y > 0 && y < yDim - 1)) {
    822.                             /*
    823.                             * & * & * *
    824.                             * * & * * *
    825.                             */
    826.                             if (IsSameColor (x - 1, y + 1, currentType))
    827.                                 return;
    828.                             /*
    829.                             * * & * * *
    830.                             * & * & * *
    831.                             */
    832.                             if (IsSameColor (x - 1, y - 1, currentType))
    833.                                 return;
    834.                         }
    835.                     }
    836.                     secondToLastType = lastType;
    837.                     lastType = currentType;
    838.                 }
    839.             }
    840.         }
    841.  
    842.         // No matches? Shuffle!
    843.         Shuffle();
    844.     }
    845.  
    846.     // Shuffle the grid
    847.     public void Shuffle()
    848.     {
    849.         Debug.Log ("No More Matches, shuffle the grid");
    850.         for (int x = 0; x < xDim; x++) {
    851.             for (int y = 0; y < yDim; y++) {
    852.                 // We only need to shuffle movable pieces
    853.                 if (pieces [x, y].IsMovable ()) {
    854.                     pieces [x, y].ColorComponent.SetColor((ColorPiece.ColorType)Random.Range(0, 5));
    855.                 }
    856.                 if (ClearAllValidMatches ())
    857.                     StartCoroutine (Fill ());
    858.             }
    859.         }
    860.     }
    861. }
    862.  

    1) I think there is a problem with my CheckAllPossibleMatches() function. It works most of the time but sometimes shuffle even if we have one possible match on the grid.
    And sometimes, the game crash with an error :
    For my current test, i have set the grid to be 9x9 so x and y are in the [0,8] range. That's why i've made some checks to avoid such problems but it seems i've failed.

    2) Currently, we can't save possible matches in an array to choose one to highlight if the player don't move.

    3) Currently, if we add some ROCK blocks on top of the grid, it can't be filled. Is there a way to bypass ROCK blocks ?

    4) Later, we have enough problems to solve right now ^^
     
    Last edited: Mar 1, 2017
  2. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    So your pieces are all just solid blocks of color ? I noticed you mention somewhere in the code checking for L-shapes and T-shapes? Is this just a game where I have 3 colored blocks in a row, horizontally or vertically and If i do destroy them + all adjacent blocks of a the same color (say I had a cross?). What if I make a 3 in a row that had 2 of the same color directly below it:
    GRG
    RBR
    RR

    Then swapping the middle It turns into this:
    GBG
    RRR
    RR

    would all 5 blow up?
     
  3. Khyinn

    Khyinn

    Joined:
    Feb 28, 2017
    Posts:
    5
    First thanks for your reply. No, here are the matches :

    Horizontal matches :



    Vertical matches :



    And 2 more diagonal matches :

    EDIT : Grid class edited to fix some minor bugs. But not the one i've asked for help :'(
     
    Last edited: Mar 1, 2017
  4. Khyinn

    Khyinn

    Joined:
    Feb 28, 2017
    Posts:
    5
    I've edited the Grid class and added match patterns so it's now well commented.

    EDIT : adding more comments but editing the OP failed so...

    For vertical check :

    Code (CSharp):
    1.  
    2.             /*
    3.             * First loop : currentType will take the value of Piece [x,0] color
    4.             * We don't make a match test here. At the end of this first loop, we'll pass the currentType value to lastType
    5.             * Second loop : currentType will take the value of Piece [x,1] color
    6.             * We can now check if lastType == currentType and make some matching tests but we can't test the duag patterns as we don't have secondLastType set right now
    7.             * At the end of this loop, we'll set secondLastType with lastType value and continue to set lastType value to currentType
    8.             * Third loop : currentType will take the value of Piece [x,2] color
    9.             * We can now check if lastType == currentType and make all matching tests as secondLastType is set
    10.             */
    11.  
    For horizontal check :

    Code (CSharp):
    1.             /*
    2.              * First loop : currentType will take the value of Piece [0,y] color
    3.              * We don't make a match test here. At the end of this first loop, we'll pass the currentType value to lastType
    4.              * Second loop : currentType will take the value of Piece [1,y] color
    5.              * We can now check if lastType == currentType and make some matching tests but we can't test the duag patterns as we don't have secondLastType set right now
    6.              * At the end of this loop, we'll set secondLastType with lastType value and continue to set lastType value to currentType
    7.              * Third loop : currentType will take the value of Piece [2,y] color
    8.              * We can now check if lastType == currentType and make all matching tests as secondLastType is set
    9.              */
     
    Last edited: Mar 1, 2017
  5. ADNCG

    ADNCG

    Joined:
    Jun 9, 2014
    Posts:
    994
    Without going through your code, here's how I'd do it. No disrespect meant, feel free to use it or not :)

    I assume all of your blocks are holding some kind of grid position value and an ID value that represents their colour or whatever.

    Say you have 3x3 matrix using 0, 1, 2 to represents row/columns. (Left to right, bottom to top)

    Top row has blue, blue, red
    Mid row has whatever, whatever, blue

    The user tries to swap (2, 2) with (2, 1) to create a blue match on the top row.

    Create a function that takes an ID parameter along with a position. Run it twice, once for each swapped blocks.
    In our case, we would feed it the blue identifier with the position (2, 2), since we're trying to swap the blue and red of the last column, and then we would feed it the red identifier with the position (1, 2).

    Assuming you are only going for matches that are in a straight line, the functions should run 2 scans, 1 horizontal and 1 vertical.

    I threw this together real quick, it's untested. I'm leaving home but I'll check back tonight in case you decide to use it and you encounter issues.

    Code (CSharp):
    1. void FindMatches (int ID, Vector2 gridPos) {
    2.  
    3.         //List that holds the confirmed matches
    4.         List <Vector2> matches = new List<Vector2> ();
    5.  
    6.         //temporary list to hold the potential horizontal matches
    7.         List <Vector2> tempHoriz = new List<Vector2> ();
    8.  
    9.         //flags to know when to stop iterating in a direction
    10.         //In this case, 0 represents left, 1 represents right
    11.         bool[] dirFlag = new bool[2];
    12.         dirFlag [0] = false;
    13.         dirFlag [1] = false;
    14.  
    15.         for (int i = 0; i < whateveryourgridsizeis; i++) {
    16.  
    17.             //Create offsets to scan based on the iterator
    18.             Vector2[] offSet = new Vector2[2];
    19.             offSet [0] = gridPos + new Vector2 (-i, 0);
    20.             offSet [1] = gridPos + new Vector2 (i, 0);
    21.  
    22.             for (int j = 0; j < 2; j++) {
    23.                 //if the flag isnt true, you can keep iterating in that direction
    24.                 if (!dirFlag [j] == false) {
    25.                     //Assuming you have a dictionary that goes a bit like (position, blockclassinstance)
    26.                     //Get the block instance from it, whatever your setup is
    27.                     BlockClass temp = GetBlock (offSet[j]);
    28.                     //nullcheck since depending on where your initial grid position is, you will definitely iterate outside of boundaries and get nulls
    29.                     if (temp != null) {
    30.                         //Access its identifier(however you set it up) and compare it with the parameter fed to the function to see if they match
    31.                         if (temp.ID == ID) {
    32.                             //You have a match, add it to the horizontal temporary list
    33.                             tempHoriz.Add (offSet[j]);
    34.                         }
    35.                         else {
    36.                             //The block doesn't match, you want to stop iterating that way
    37.                             dirFlag[j] = true;
    38.                         }
    39.                     }
    40.                     else {
    41.                         dirFlag[j] = true;
    42.                     }
    43.                 }
    44.             }
    45.             //If both flags are true, no point in running the function anymore
    46.             if (dirFlag [0] && dirFlag [1]) {
    47.                 break;
    48.             }
    49.         }
    50.         //Now check to see if your temporary horizontal list has at least 3 values
    51.         if (tempHoriz.Count >= 3) {
    52.             //You have a match, add them to the matches list
    53.         }
    54.  
    55.         //Repeat everything but vertically
    56.         //If your vertical list is a match as well, you can throw them all in the same list, most likely you have some kind of T shaped match
    57.     }
     
  6. Khyinn

    Khyinn

    Joined:
    Feb 28, 2017
    Posts:
    5
    Thanks This is exactly what i've done in my grid class (see the getMatch function). I don't have problem making matches, i've already written all the code needed to do that. I only need to check if there are still one or more matches on the grid and store them in an array.

    Edit : oh ! Looks like this is what your code do... l'll try to modify if to suit my code.

    Please, look through my code.

    If someone wants all the project code, i can send a zip file with all the scripts i'm using.

    And sorry for my bad english...