// Mueve un bloque en el tablero, devolviendo el otro bloque que ahora pasa a ocupar el lugar de este // Si no se puede realizar el movimiento, da fallo public MovableBlock Move(MovableBlock block, float delay) { if (block == null) { throw new ArgumentNullException(nameof(block)); } if (!CanMove(block)) { throw new InvalidOperationException("The required movement is not possible"); } Debug.Log(ToString() + " moves " + block.ToString() + "."); // Intercambio de valores entre las dos posiciones de la matriz de bloques? MovableBlock otherBlock = manager.Move(block); // Ya ha cambiado el puzle, y mi posición lógica (y la del hueco -otherBlock-)... faltan las posiciones físicas en la escena y ubicaciones en la matriz de bloques de ambos // Cambio la ubicación en la matriz del bloque auxiliar para que sea la correcta blocks[otherBlock.position.GetRow(), otherBlock.position.GetColumn()] = otherBlock; // Cambio la ubicación en la matriz del bloque resultante para que sea la correcta blocks[block.position.GetRow(), block.position.GetColumn()] = block; // Los meto en la lista para que se muevan cuando corresponda... blocksInMotion.Enqueue(block); blocksInMotion.Enqueue(otherBlock); // Debería meter el delay o marcar de alguna manera si el movimiento es de humano o máquina return(otherBlock); }
// Mueve un bloque, según las normas que diga el gestor public MovableBlock Move(MovableBlock block) { if (block == null) { throw new ArgumentNullException(nameof(block)); } if (!CanMove(block)) { throw new InvalidOperationException("The required movement is not possible"); } Position originPosition = block.position; Debug.Log(ToString() + " moves " + block.ToString() + "."); var targetPosition = puzzle.MoveByDefault(block.position); // Si hemos tenido éxito ha cambiado la matrix lógica del puzle... pero no ha cambiado la posición (lógica), ni la mía ni la del hueco. Toca hacerlo ahora block.position = targetPosition; MovableBlock targetBlock = board.GetBlock(targetPosition); targetBlock.position = originPosition; UpdateInfo(); return(targetBlock); }
// Devuelve cierto si un bloque se puede mover, si se lo permite el gestor public bool CanMove(MovableBlock block) { if (block == null) { throw new ArgumentNullException(nameof(block)); } return(puzzle.CanMoveByDefault(block.position)); }
// Devuelve si se puede mover un bloque en el tablero public bool CanMove(MovableBlock block) { if (block == null) { throw new ArgumentNullException(nameof(block)); } return(manager.CanMove(block)); }
// Intercambia la posición física en la escena con otro bloque public void ExchangeTransform(MovableBlock block) { if (block == null) { throw new ArgumentNullException(nameof(block)); } // Se usa una variable auxiliar para hacer el intercambio Vector3 auxTransformPosition = block.transform.position; block.transform.position = transform.position; transform.position = auxTransformPosition; }
// Corrutina para pausar entre movimientos y poder verlos IEnumerator BlockInMotion(float delay) { blockInMotion = true; // Animar tal vez las dos piezas... yield return(new WaitForSeconds(delay)); MovableBlock block = blocksInMotion.Dequeue(); MovableBlock otherBlock = blocksInMotion.Dequeue(); // Ya ha cambiando el puzle, la posición lógica y ubicación en la matriz de bloques de ambos bloques // Sólo queda intercambiar la parte visual, la posición física de ambos en la escena block.ExchangeTransform(otherBlock); blockInMotion = false; }
// Genera todos los bloques de la matriz // No se utiliza GetLowerBound ni GetUpperBound porque sabemos que son matrices que siempre empiezan en cero y acaban en positivo private void GenerateBlocks(SlidingPuzzle puzzle) { if (puzzle == null) { throw new ArgumentNullException(nameof(puzzle)); } var rows = blocks.GetLength(0); var columns = blocks.GetLength(1); for (var r = 0u; r < rows; r++) { for (var c = 0u; c < columns; c++) { MovableBlock block = blocks[r, c]; if (block == null) { // Crea un ejemplar del prefab de bloque en la posición correcta según su posición en la matriz (podrían hacerse hijos del tablero) // Se asume un tablero en (0f, 0f, 0f) aunque debería tomarse la posición real del tablero como referencia block = Instantiate(blockPrefab, new Vector3(-((blocks.GetLength(1) / 2.0f) * POSITION_FACTOR_C - (POSITION_FACTOR_C / 2.0f)) + c * POSITION_FACTOR_C, 0, (blocks.GetLength(0) / 2.0f) * POSITION_FACTOR_R - (POSITION_FACTOR_R / 2.0f) - r * POSITION_FACTOR_R), Quaternion.identity); // En Y, que es la separación del board, estoy poniendo 0 pero la referencia la debería dar el Board blocks[r, c] = block; } // Estuviera o no ya creado el bloque, se inicializa y reposiciona Position position = new Position(r, c); block.position = position; uint value = puzzle.GetValue(position); // El texto que se pone en el bloque es el valor +1, salvo si es el último valor, que no se mandará texto para que sea un bloque no visible if (value == 0) { block.Initialize(this, null); } else { block.Initialize(this, value.ToString()); } Debug.Log(ToString() + "generated " + block.ToString() + "."); } } }
// Notifica el intento de movimiento al tablero de bloques (si lo hay), cuando se recibe un clic completo de ratón (apretar y soltar) // Podría reaccionarse con un sonido si el intento falla, aunque ahora no se hace nada // La he puesto pública para que se puedan simular pulsaciones sobre un bloque desde el gestor public bool OnMouseUpAsButton() { if (board == null) { throw new InvalidOperationException("This object has not been initialized"); } Debug.Log("Trying to move " + ToString() + "..."); if (board.CanMove(this)) { board.UserInteraction(); // Aviso de que lo he tocado para que se pongan los contadores a cero (por si contenían algo) MovableBlock block = board.Move(this, BlockBoard.USER_DELAY); Debug.Log(ToString() + " was moved."); return(true); } Debug.Log(ToString() + " cannot be moved."); return(false); }