NOTE: Since making this post, things have moved on where I now think my code is OK but doesn’t work with newer versions of Unity. The code works in a Unity 2017 version
Hi all, I’m trying to make a Match-3 game with c# and Unity. I’ve been learning this engine for a few years on and off, but still sometimes make very silly mistakes so this really could be anything that causes my issue here (sorry lol!)
The problem started when I tried to make a method in the GameBoard class(theres only that class and a Tile class really). The method took two parameters both of Tile type and tried to swap them. I have deleted/lost this version of the code the other day as it just kept ‘hanging’ in Unity as soon as i clicked the second tile.
Then I did the method taking just VectorInt’s for the index of both tiles. I tried swapping using just the two indexes but this resulted in the two tiles being on top of eachother.
So I finally have this method which takes the Indexes, creates a temp Tile of one of them and then swaps them. I’ve been confused for a few days trying many things, so what I did was hard code Input Key Q to first set tile [0,0] to be the “CurrentSelectedTileIndex” and then if that index is not null, then another Q press will act as clicking tile [1,0].
That’s where it gets wierd! if I click Q in game (SLOWLY) it works great, the two tiles swap places. If I click at more than a rate of about 1 press per second, the game hangs again. Furthermore, if I mouse-click the actual tiles (as per the real input for the game i originally coded) this again hangs Unity as soon as the second tile is clicked.
I tried posting questions online with very limited scope as people don’t like me posting whole game and yelling “Fix this please!!!” , but to be honest… I’m a at a loss and almost ready to give up :[
So i guess I could quietly whisper "…Fix this please… kind fellows "
Thanks for any help. Here are both classes, which is the full game code:
//required in 2017 as Vector2Int was not found .. wasn't used in the 2019 attempts
public class Vector2Int
{
public int x;
public int y;
public Vector2Int(int x, int y)
{
this.x = x;
this.y = y;
}
}
public class GlobalAssets : MonoBehaviour
{
public static GlobalAssets instance;
public Sprite[] sprites;
public Tile tilePrefab;
private void Awake()
{
if (instance == null)
instance = this;
else
Destroy(this);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Tile : MonoBehaviour
{
[HideInInspector] public SpriteRenderer sr;
[HideInInspector] public enum TileType { A, B, C, D, E, F, G };
[HideInInspector] public TileType tileType;
[HideInInspector] public int TYPE_COUNT = 7;
[HideInInspector] public Vector2Int coords;
public void InitTile(TileType type, int x, int y)
{
tileType = type;
GiveNewGridCoords(new Vector2Int(x, y));
sr = GetComponent<SpriteRenderer>();
sr.sprite = GlobalAssets.instance.sprites[(int)tileType];
}
public void MakeEmpty()
{
Debug.Log("Clearing tile...");
sr.sprite = null;
}
public List<Tile> FindMatches(Vector2 castDirection)
{
List<Tile> matches = new List<Tile>();
RaycastHit2D hit = Physics2D.Raycast(transform.position + new Vector3(castDirection.x, castDirection.y, 0), castDirection);
while (hit.collider != null && hit.collider.GetComponent<SpriteRenderer>().sprite == sr.sprite)
{
matches.Add(hit.collider.GetComponent<Tile>());
hit = Physics2D.Raycast(hit.transform.position + new Vector3(castDirection.x, castDirection.y, 0), castDirection);
}
hit = Physics2D.Raycast(transform.position - new Vector3(castDirection.x, castDirection.y, 0), -castDirection);
while (hit.collider != null && hit.collider.GetComponent<SpriteRenderer>().sprite == sr.sprite)
{
matches.Add(hit.collider.GetComponent<Tile>());
hit = Physics2D.Raycast(hit.transform.position - new Vector3(castDirection.x, castDirection.y, 0), -castDirection);
}
matches.Add(this);
return matches;
}
public void GiveNewGridCoords(Vector2Int coords)
{
this.coords = coords;
RepositionUsingGridCoords(coords);
}
void RepositionUsingGridCoords(Vector2Int coords)
{
transform.position = new Vector2(coords.x * GameBoard.tileSize, coords.y * GameBoard.tileSize);
}
private void OnMouseDown()
{
Debug.Log("MOUSE CLICKED ON TILE" + transform.position.x + "," + transform.position.y);
GameBoard.instance.TileClicked(this);
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameBoard : MonoBehaviour
{
public static GameBoard instance;
const int GRID_WIDTH = 9;
const int GRID_HEIGHT = 9;
public static int tileSize = 1;
Tile[,] tiles = new Tile[GRID_WIDTH, GRID_HEIGHT];
System.Random rand;
Vector2Int currentlySelectedTileCoords = new Vector2Int(-1,-1);
Vector2Int UNSELECTION_COORDS = new Vector2Int(-1, -1);
private void Awake()
{
if (instance == null)
instance = this;
else
Destroy(this);
}
private void Start()
{
CreateNewBoard();
}
void CreateNewBoard()
{
rand = new System.Random();
for (int y = 0; y < tiles.GetLength(1); y++)
{
for (int x = 0; x < tiles.GetLength(0); x++)
{
Tile tile = Instantiate(GlobalAssets.instance.tilePrefab);
tile.InitTile((Tile.TileType)rand.Next(tile.TYPE_COUNT), x, y);
tiles[x, y] = tile;
}
}
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Q))
{
if (currentlySelectedTileCoords == UNSELECTION_COORDS)
TileClicked(tiles[0, 0]);
else
TileClicked(tiles[1, 0]);
}
if (currentlySelectedTileCoords != UNSELECTION_COORDS)
{
return;
}
CheckForMatches();
MakeBlocksFall();
}
public void CheckForMatches()
{
for (int y = 0; y < tiles.GetLength(1); y++)
{
for (int x = 0; x < tiles.GetLength(0); x++)
{
List<Tile> matchedTilesX = tiles[x,y].FindMatches(Vector2.right);
if (matchedTilesX.Count >= 3)
{
foreach (Tile t in matchedTilesX)
{
t.MakeEmpty();
}
}
List<Tile> matchedTilesY = tiles[x,y].FindMatches(Vector2.up);
if (matchedTilesY.Count >= 3)
{
foreach (Tile t in matchedTilesY)
{
t.MakeEmpty();
}
}
}
}
}
void MakeBlocksFall()
{
for (int y = 1; y < tiles.GetLength(1); y++)
{
for (int x = 0; x < tiles.GetLength(0); x++)
{
if (y == tiles.GetLength(1) - 1 && tiles[x, y].sr.sprite == null)
{
Tile tile = Instantiate(GlobalAssets.instance.tilePrefab);
tile.InitTile((Tile.TileType)rand.Next(tile.TYPE_COUNT), x, y);
tiles[x, y] = tile;
}
if (tiles[x,y-1].sr.sprite == null)
{
tiles[x, y - 1].sr.sprite = tiles[x, y].sr.sprite;
tiles[x, y].MakeEmpty();
}
}
}
}
public void TileClicked(Tile tile)
{
Debug.Log("Selected TILE INDEX: " + currentlySelectedTileCoords);
Debug.Log("TileClicked!");
if (currentlySelectedTileCoords == UNSELECTION_COORDS)
{
currentlySelectedTileCoords = tile.coords;
Debug.Log("selceted tile was null. it is now: " + currentlySelectedTileCoords);
}
else
{
if (tile.coords != currentlySelectedTileCoords)
{
SwapTilePositions(currentlySelectedTileCoords, tile.coords);
currentlySelectedTileCoords = UNSELECTION_COORDS;
}
else
{
Debug.Log("Re-clicked the same tile. Now selectedTile is made null");
currentlySelectedTileCoords = UNSELECTION_COORDS;
}
}
}
public void SwapTilePositions(Vector2Int selectedTileIndex, Vector2Int otherTileIndex)
{
if (selectedTileIndex.x < 0 || selectedTileIndex.y < 0)
return;
if (selectedTileIndex.x == otherTileIndex.x + 1 || selectedTileIndex.x == otherTileIndex.x - 1
|| selectedTileIndex.y == otherTileIndex.y + 1 || selectedTileIndex.y == otherTileIndex.y - 1)
{
Vector2Int a = selectedTileIndex;
Vector2Int b = otherTileIndex;
Debug.Log("ax and ay = " + a.x + a.y);
Debug.Log("tile = " + tiles[a.x, a.y]);
Tile tempTile = tiles[a.x, a.y];
tiles[a.x, a.y] = tiles[b.x, b.y];
tiles[b.x, b.y] = tempTile;
tiles[a.x, a.y].GiveNewGridCoords(a);
tiles[b.x, b.y].GiveNewGridCoords(b);
}
else
{
Debug.Log("Tile not adjecent, cannot swap tiles");
}
}
}