- Home /
Scrabble In Tetris Help Needed
Hey guys. I'm trying to make a game where Scrabble tiles fall down like Tetris tiles and when you make a word, it disappears like Tetris. I managed to make it with single letters but i cant figure out how to connect the letters together.
void RegisterTile()
{
gameLogic.grid[Mathf.FloorToInt(gameObject.transform.position.x), Mathf.FloorToInt(gameObject.transform.position.y)] = gameObject.transform;
TryWord();
}
bool CheckValid()
{
if(gameObject.transform.position.x > GameLogic.width ||
gameObject.transform.position.x < 0 ||
gameObject.transform.position.y < 0)
{
return false;
}
if (gameObject.transform.position.y < GameLogic.heigth && gameLogic.grid[Mathf.FloorToInt(gameObject.transform.position.x), Mathf.FloorToInt(gameObject.transform.position.y)] != null)
{
return false;
}
return true;
}
// Update is called once per frame
void Update()
{
if(CheckValid())
{
check = true;
}
if (!fingerDown && Input.GetMouseButtonDown(0))
{
startPos = Input.mousePosition;
fingerDown = true;
}
if (movable)
{
timer += 1 * Time.deltaTime;
if (Input.GetKey(KeyCode.DownArrow) && timer > GameLogicNew.quickDropTime || fingerDown && timer > GameLogic.quickDropTime && Input.mousePosition.y < startPos.y - pixelDistToDetect)
{
gameObject.transform.position -= new Vector3(0, 2, 0);
timer = 0;
if (!CheckValid())
{
movable = false;
gameObject.transform.position += new Vector3(0, 2, 0);
RegisterTile();
gameLogic.SpawnTile();
}
}
else if (timer > GameLogicNew.dropTime)
{
gameObject.transform.position -= new Vector3(0, 2, 0);
timer = 0;
if (!CheckValid())
{
movable = false;
gameObject.transform.position += new Vector3(0, 2, 0);
RegisterTile();
gameLogic.SpawnTile();
}
}
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
gameObject.transform.position -= new Vector3(2, 0, 0);
if (!CheckValid())
{
gameObject.transform.position += new Vector3(2, 0, 0);
}
}
else if (Input.GetKeyDown(KeyCode.RightArrow))
{
gameObject.transform.position += new Vector3(2, 0, 0);
if (!CheckValid())
{
gameObject.transform.position -= new Vector3(2, 0, 0);
}
}
if (fingerDown)
{
if (Input.mousePosition.x >= startPos.x + pixelDistToDetect)
{
gameObject.transform.position += new Vector3(2, 0, 0);
startPos = Input.mousePosition;
if (!CheckValid())
{
gameObject.transform.position -= new Vector3(2, 0, 0);
}
}
if (Input.mousePosition.x <= startPos.x - pixelDistToDetect)
{
gameObject.transform.position -= new Vector3(2, 0, 0);
startPos = Input.mousePosition;
if (!CheckValid())
{
gameObject.transform.position += new Vector3(2, 0, 0);
}
}
}
}
if (fingerDown && Input.GetMouseButtonUp(0))
{
fingerDown = false;
}
}
public void TryWord()
{
WordManager.currentWord += letterName.GetComponent<TMP_Text>().text;
Debug.Log(letterName.GetComponent<TMP_Text>().text);
}
it looks like this right now. When a letter hits the bottom, i can see it in the console but when multiple ones hit, i see them all together no matter where they are. I cant find a way to seperate them or show them in order (From left to right / from up to down). I couldnt find any tutorials on how to make a Scrabble game so i ask for your help. Thank you in advance.
Answer by rh_galaxy · Jan 09 at 07:37 PM
I'd go about it this way:
Every time a block hits the bottom and sticks (the grid has changed), check for words on every block in the grid, Right and Down as far as it goes. But you need to have your wordlist indexed so that it does not become too expensive to check for words... GetComponent can certainly not be used as much.
Thats the problem mate. I dont know how to. I tried a few methods but they didnt worked. So i need the help. I cant make a tile recognize it's neighbour tiles. So it takes all of them.
Answer by Eno-Khaon · Jan 10 at 04:05 AM
Well, if it's based around Scrabble squares and Tetris-style blocks falling into place, then once a tile has settled in place, the new state of your playfield should be a fixed/known state.
Right now, your block positioning appears to be based purely on physical positions in Unity. You should probably move away from that approach and use a pre-specified grid for placement, then reflect those positions back to your placement scheme instead.
With this in mind, you would have a fixed size for your playfield at any given time. Let's say it's 8x8 (to keep this example a bit smaller):
--------
--------
--------
--M--A--
--I--D-X
B-G--R-W
FDG-OECM
ZLE-TERQ
In this situation, you can easily store the current state of all the existing blocks in a 2-dimensional array, either as a char array or (preferably) a "Tile" array.
Each tile should contain information about the char associated with it, where that data is copied to the Text component. It's much faster than reading strings from Text components themselves, and the playfield should be storing "Tile" information at all times.
Going back to my example above, the bottom row contains LE TER, where no complete word has been formed yet, but adding the letter 'T' in the middle would complete a new word.
Your playfield can simultaneously keep track of tiles that have changed. After all, the playfield wouldn't be constantly shifting and changing; if a change is manually made, then you can limit your completed-word search to only use letters adjacent to ones that have been updated.
This means two things:
First: When a new letter is placed, check all tiles in its row and column (and diagonally, if applicable) for new words formed. If it's feasible to do so without strings, it would almost definitely be the "faster" solution, but a string still works well enough once you're limiting your search area.
// Example definition of playfield
Tile[,] playfield = new Tile[playfieldWidth, playfieldHeight];
// These are the array coordinates where the new Tile landed
int placedTileX;
int placedTileY;
// Markers to check word bounds
int firstCharX = placedTileX;
int lastCharX = placedTileX;
int firstCharY = placedTileY;
int lastCharY = placedTileY;
string wordCheckX = string.Empty;
string wordCheckY = string.Empty;
// Check backwards for the first letter in the word
for(int x = placedTileX - 1; x >= 0; x--)
{
if(playfield[x, placedTileY] == null)
{
break;
}
else
{
firstCharX = x;
}
}
// Check forwards for the last letter in the word
for(int x = placedTileX + 1; x < playfieldWidth; x++)
{
if(playfield[x, placedTileY] == null)
{
break;
}
else
{
lastCharX = x;
}
}
// Repeat the same basic principle for Y-axis
// ...
// Add char to your string to compare with dictionary
for(int x = firstCharX; x <= lastCharX; x++)
{
wordCheckX += playfield[x, placedTileY].letter;
}
// Again, repeat for Y-axis
// Compare with dictionary (or ignore if below minimum letter count)
// After processing is complete...
for(int y = playfieldHeight - 1; y >= 0; y--)
{
for(int x = playfieldWidth - 1; x >= 0; x--)
{
playfield[x, y].modified = false;
}
}
Second: If you form a word, then by Tetris rules, the involved Tiles will disappear. All tiles above the formed word are moved down to the nearest available height. Then, this is why I mention marking all modified tiles... You'll need to perform the same check as above for the entire range of tiles modified (not one-by-one, but as a group) to check every new row and column they are now adjacent to. On that note, it means my example would need to be changed to accommodate min/max X and Y axis ranges needing to be searched. That makes things a bit more involved, so it's probably better to start simpler, then add more complex logic for searching for all words contained in arbitrary spaces simultaneously.
This is my code for the grid of the playing field:
public static float dropTime = 0.9f;
public static float quickDropTime = 0.05f;
public static int width = 11, heigth = 17;
public GameObject tile;
public Transform tileSpawn;
public Transform[,] grid = new Transform[width, heigth];
// Start is called before the first frame update
void Start()
{
SpawnTile();
}
// Update is called once per frame
void Update()
{
}
public void SpawnTile()
{
Instantiate(tile, tileSpawn.position, Quaternion.identity);
}
it's just like you said. I use the tiles as single Tetris blocks and destroy them (at least trying to) when they form a word.

When i drop a letter, i'm trying to make it recognize the neighbour letters. I'll try your method
Probably one of the better changes to make would involve changing your "grid" from Transform data into a "Tile" class attached to each falling block. Because a GameObject will *always* have Transform data associated with it, MonoBehaviour scripts can always easily reference both of those. So your best bet for performance is to put your most relevant data into your grid array (i.e. a class that knows the letter on its tile).
I'm trying to make it work first. :D Before worrying about the performance. But scratch that. Can you teach me how to do that? Or turn me to the right direction to learn it? That would be awesome.
Your answer