¿Cómo podemos controlar el movimiento de las piezas en el tablero?
Para mejorar nuestro proyecto de juego, es esencial asegurarnos de que las piezas solo se muevan a espacios permitidos, es decir, a posiciones adyacentes y compatibles. Esto ayudará a mantener la lógica del juego y prevenir movimientos ilógicos que puedan romper las reglas establecidas. Para lograr esto, primero debemos entender lo que significa un "espacio permitido" tanto en el eje horizontal como en el vertical.
¿Cuál es la lógica detrás de los espacios permitidos?
La idea de "espacios permitidos" radica en moverse una sola unidad hacia un lado en el mismo eje o en cambiar una sola unidad de coordenadas, manteniendo constante la otra. Aquí profundizamos en cómo funciona:
Eje Horizontal:
Las piezas deben compartir la misma coordenada en Y.
La diferencia en la coordenada X debería ser exactamente 1.
Eje Vertical:
Las piezas deben compartir la misma coordenada en X.
La diferencia en la coordenada Y debería ser exactamente 1.
En suma, estos criterios aseguran que las piezas solo se muevan a espacios directamente adyacentes, ya sea horizontal o verticalmente.
¿Cómo implementamos esto en código?
Para poner en práctica esta lógica, crearemos una función que verifique si dos espacios están suficientemente cerca como para permitir un movimiento:
publicboolisClosedTo(Tile start,Tile end){// Verificación en el eje Xif(Math.Abs(start.x - end.x)==1&& start.y == end.y){returntrue;}// Verificación en el eje Yif(Math.Abs(start.y - end.y)==1&& start.x == end.x){returntrue;}// Si no cumple ninguna condición, retorno falsoreturnfalse;}
Este fragmento de código introduce una función isClosedTo que evalúa si dos espacios (representados por Tile) son adyacentes. Utilizamos la función Math.Abs para calcular la diferencia absoluta entre las coordenadas y luego validamos las condiciones mencionadas anteriormente.
¿Cómo integramos la función en nuestro juego?
Una vez creada la función isClosedTo, es crucial integrarla con el resto de la lógica que maneja los movimientos del juego. Así, verificaremos que las piezas no solo tengan puntos de inicio y fin válidos, sino que también estén adecuadamente cerca.
publicvoidTileUp(Tile startTile,Tile endTile){if(startTile !=null&& endTile !=null&&isClosedTo(startTile, endTile)){// Código para mover las piezas}}
Al añadir este chequeo adicional, aseguramos que el movimiento solo se realice cuando los espacios son adyacentes. El resultado es una experiencia de juego más precisa y acorde a las reglas establecidas.
Ahora, ve a Unity y comprueba el funcionamiento. Reinicia y observa cómo las piezas se mueven únicamente a espacios vecinos, reforzando así la lógica y jugabilidad deseadas. ¡Todo un avance para nuestra mecánica del juego!
Assets\Scripts\Board.cs(132,18): error CS0103:The name 'Math' does not exist in the current context
deben importar el módulo de System al principio del script:
using System;
using System;using System.Collections;using System.Collections.Generic;using System.Linq;using UnityEngine;public class Board : MonoBehaviour
{ public int width; public int height; public GameObject tileObject; public float cameraSizeOffset; public float cameraVerticalOffset; public GameObject[] availablePieces; Tile[,] Tiles; Piece[,] Pieces; Tile startTile; Tile endTile; bool swappingPieces = false;// Start is called before the first frame updatevoidStart(){ Tiles = new Tile[width, height]; Pieces = new Piece[width, height];SetupBoard();PositionCamera();SetupPieces();} private voidSetupPieces(){for(int x =0; x < width; x++){for(int y =0; y < height; y++){ var selectedPiece = availablePieces[UnityEngine.Random.Range(0, availablePieces.Length)]; var o =Instantiate(selectedPiece, new Vector3(x, y,-5), Quaternion.identity); o.transform.parent = transform; Pieces[x, y]= o.GetComponent<Piece>(); Pieces[x, y].Setup(x, y, this);}}} private voidPositionCamera(){float newPosX =(float)width /2f;float newPosY =(float)height /2f; Camera.main.transform.position = new Vector3(newPosX -0.5f, newPosY -0.5f+ cameraVerticalOffset,-10f);float horizontal = width +1;float vertical =(height /2)+1; Camera.main.orthographicSize = horizontal > vertical ? horizontal + cameraSizeOffset : vertical + cameraSizeOffset;} private voidSetupBoard(){for(int x =0; x < width; x++){for(int y =0; y < height; y++){ var o =Instantiate(tileObject, new Vector3(x, y,-5), Quaternion.identity); o.transform.parent = transform; Tiles[x, y]= o.GetComponent<Tile>(); Tiles[x, y]?.Setup(x, y, this);// Removed duplicate call}}} public voidTileDown(Tile tile_){ startTile = tile_;} public voidTileOver(Tile tile_){ endTile = tile_;} public voidTileUp(Tile tile_){if(startTile != null && endTile != null &&IsCloseTo(startTile, endTile)&&!swappingPieces){ swappingPieces = true;StartCoroutine(SwapTiles());} startTile = null; endTile = null;} IEnumerator SwapTiles(){ var startPiece = Pieces[startTile.x, startTile.y]; var endPiece = Pieces[endTile.x, endTile.y];if(startPiece == null || endPiece == null){ swappingPieces = false; yield break;} startPiece.Move(endTile.x, endTile.y); endPiece.Move(startTile.x, startTile.y); Pieces[startTile.x, startTile.y]= endPiece; Pieces[endTile.x, endTile.y]= startPiece; yield return new WaitForSeconds(0.3f); bool foundMatch = false; var startMatches =GetMatchByPiece(startTile.x, startTile.y,3); var endMatches =GetMatchByPiece(endTile.x, endTile.y,3); startMatches?.ForEach(piece =>{ foundMatch = true; Pieces[piece.x, piece.y]= null;Destroy(piece.gameObject);}); endMatches?.ForEach(piece =>{ foundMatch = true; Pieces[piece.x, piece.y]= null;Destroy(piece.gameObject);});if(!foundMatch){// Swap back if no matches found startPiece.Move(startTile.x, startTile.y); endPiece.Move(endTile.x, endTile.y); Pieces[startTile.x, startTile.y]= startPiece; Pieces[endTile.x, endTile.y]= endPiece;} startTile = null; endTile = null; swappingPieces = false; yield return null;} public bool IsCloseTo(Tile start, Tile end){return(Math.Abs(start.x - end.x)==1&& start.y == end.y)||(Math.Abs(start.y - end.y)==1&& start.x == end.x);} public List<Piece>GetMatchByDirection(int xpos,int ypos, Vector2 direction,int minPieces =3){ List<Piece> matches = new List<Piece>(); Piece startPiece = Pieces[xpos, ypos]; matches.Add(startPiece);int nextX;int nextY;int maxVal = width > height ? width : height;for(int i =1; i < maxVal; i++){ nextX = xpos +((int)direction.x * i); nextY = ypos +((int)direction.y * i);if(nextX >=0&& nextX < width && nextY >=0&& nextY < height){ var nextPiece = Pieces[nextX, nextY];if(nextPiece != null && nextPiece.pieceType == startPiece.pieceType){ matches.Add(nextPiece);}else{break;}}}return matches.Count >= minPieces ? matches : null;} public List<Piece>GetMatchByPiece(int xpos,int ypos,int minPieces =3){ var upMatches =GetMatchByDirection(xpos, ypos, new Vector2(0,1),2); var downMatches =GetMatchByDirection(xpos, ypos, new Vector2(0,-1),2); var rightMatches =GetMatchByDirection(xpos, ypos, new Vector2(1,0),2); var leftMatches =GetMatchByDirection(xpos, ypos, new Vector2(-1,0),2); upMatches = upMatches ?? new List<Piece>(); downMatches = downMatches ?? new List<Piece>(); rightMatches = rightMatches ?? new List<Piece>(); leftMatches = leftMatches ?? new List<Piece>(); var verticalMatches = upMatches.Union(downMatches).ToList(); var horizontalMatches = leftMatches.Union(rightMatches).ToList(); var foundMatches = new List<Piece>();if(verticalMatches.Count >= minPieces){ foundMatches = foundMatches.Union(verticalMatches).ToList();}if(horizontalMatches.Count >= minPieces){ foundMatches = foundMatches.Union(horizontalMatches).ToList();}return foundMatches;}}```using System;using System.Collections;using System.Collections.Generic;using System.Linq;using UnityEngine;public class Board : MonoBehaviour{ public int width; public int height; public GameObject tileObject; public float cameraSizeOffset; public float cameraVerticalOffset; public GameObject\[] availablePieces; Tile\[,] Tiles; Piece\[,] Pieces; Tile startTile; Tile endTile; bool swappingPieces = false;// Start is called before the first frame update void Start() { Tiles = new Tile\[width, height]; Pieces = new Piece\[width, height]; SetupBoard(); PositionCamera(); SetupPieces(); } private voidSetupPieces(){for(int x =0; x < width; x++){for(int y =0; y < height; y++){ var selectedPiece = availablePieces\[UnityEngine.Random.Range(0, availablePieces.Length)]; var o =Instantiate(selectedPiece, new Vector3(x, y,-5), Quaternion.identity); o.transform.parent = transform; Pieces\[x, y]= o.GetComponent\<Piece>(); Pieces\[x, y].Setup(x, y, this);}}} private voidPositionCamera(){float newPosX =(float)width /2f;float newPosY =(float)height /2f; Camera.main.transform.position = new Vector3(newPosX -0.5f, newPosY -0.5f+ cameraVerticalOffset,-10f);float horizontal = width +1;float vertical =(height /2)+1; Camera.main.orthographicSize = horizontal > vertical ? horizontal + cameraSizeOffset : vertical + cameraSizeOffset;} private voidSetupBoard(){for(int x =0; x < width; x++){for(int y =0; y < height; y++){ var o =Instantiate(tileObject, new Vector3(x, y,-5), Quaternion.identity); o.transform.parent = transform; Tiles\[x, y]= o.GetComponent\<Tile>(); Tiles\[x, y]?.Setup(x, y, this);// Removed duplicate call } } } public voidTileDown(Tile tile\_){ startTile = tile\_;} public voidTileOver(Tile tile\_){ endTile = tile\_;} public voidTileUp(Tile tile\_){if(startTile != null && endTile != null &&IsCloseTo(startTile, endTile)&&!swappingPieces){ swappingPieces = true;StartCoroutine(SwapTiles());} startTile = null; endTile = null;} IEnumerator SwapTiles(){ var startPiece = Pieces\[startTile.x, startTile.y]; var endPiece = Pieces\[endTile.x, endTile.y];if(startPiece == null || endPiece == null){ swappingPieces = false; yield break;} startPiece.Move(endTile.x, endTile.y); endPiece.Move(startTile.x, startTile.y); Pieces\[startTile.x, startTile.y]= endPiece; Pieces\[endTile.x, endTile.y]= startPiece; yield return new WaitForSeconds(0.3f); bool foundMatch = false; var startMatches =GetMatchByPiece(startTile.x, startTile.y,3); var endMatches =GetMatchByPiece(endTile.x, endTile.y,3); startMatches?.ForEach(piece =>{ foundMatch = true; Pieces\[piece.x, piece.y]= null;Destroy(piece.gameObject);}); endMatches?.ForEach(piece =>{ foundMatch = true; Pieces\[piece.x, piece.y]= null;Destroy(piece.gameObject);});if(!foundMatch){// Swap back if no matches found startPiece.Move(startTile.x, startTile.y); endPiece.Move(endTile.x, endTile.y); Pieces\[startTile.x, startTile.y] = startPiece; Pieces\[endTile.x, endTile.y] = endPiece; } startTile = null; endTile = null; swappingPieces = false; yield return null;} public bool IsCloseTo(Tile start, Tile end){return(Math.Abs(start.x - end.x)==1&& start.y == end.y)||(Math.Abs(start.y - end.y)==1&& start.x == end.x);} public List\<Piece>GetMatchByDirection(int xpos,int ypos, Vector2 direction,int minPieces =3){ List\<Piece> matches = new List\<Piece>(); Piece startPiece = Pieces\[xpos, ypos]; matches.Add(startPiece);int nextX;int nextY;int maxVal = width > height ? width : height;for(int i =1; i < maxVal; i++){ nextX = xpos +((int)direction.x \* i); nextY = ypos +((int)direction.y \* i);if(nextX >=0&& nextX < width && nextY >=0&& nextY < height){ var nextPiece = Pieces\[nextX, nextY];if(nextPiece != null && nextPiece.pieceType == startPiece.pieceType){ matches.Add(nextPiece);}else{break;}}}return matches.Count >= minPieces ? matches : null;} public List\<Piece>GetMatchByPiece(int xpos,int ypos,int minPieces =3){ var upMatches =GetMatchByDirection(xpos, ypos, new Vector2(0,1),2); var downMatches =GetMatchByDirection(xpos, ypos, new Vector2(0,-1),2); var rightMatches =GetMatchByDirection(xpos, ypos, new Vector2(1,0),2); var leftMatches =GetMatchByDirection(xpos, ypos, new Vector2(-1,0),2); upMatches = upMatches ?? new List\<Piece>(); downMatches = downMatches ?? new List\<Piece>(); rightMatches = rightMatches ?? new List\<Piece>(); leftMatches = leftMatches ?? new List\<Piece>(); var verticalMatches = upMatches.Union(downMatches).ToList(); var horizontalMatches = leftMatches.Union(rightMatches).ToList(); var foundMatches = new List\<Piece>();if(verticalMatches.Count >= minPieces){ foundMatches = foundMatches.Union(verticalMatches).ToList();}if(horizontalMatches.Count >= minPieces){ foundMatches = foundMatches.Union(horizontalMatches).ToList();}return foundMatches;}}
Tengo la costumbre de intentar siempre escribir el código necesario para resolvr el problema antes que el profe lo haga, y lo termine haciendo de una manera ligeramente diferente 🙂