jairogarcíarincón

El tablero

Para la generación del tablero de juego crearemos dos nuevos scripts (dentro de Assets > Scripts) llamados BoardManager y GameManager.

Además, crearemos un Empty Object al que llamaremos Game Manager y le asociaremos los dos scripts anteriores.

El código de los scripts es:


using UnityEngine;
using System;
using System.Collections.Generic; //Nos permite utilizar listas
using Random = UnityEngine.Random; //Para usar Random de manera sencilla


public class BoardManager : MonoBehaviour {

//Permite mostrar una clase con sus propiedades en el Inspector.
[Serializable]
public class Count
{
public int minimum; //Valor mínimo de la clase Count.
public int maximum; //Valor máximo de la clase Count.


//Constructor
public Count(int min, int max)
{
minimum = min;
maximum = max;
}
}

public int columns = 8; //Número de columnas del tablero.
public int rows = 8; //Número de filas del tablero.
public Count wallCount = new Count(5, 9); //Límites inferior y superior de muros aleatorios por tablero.
public Count foodCount = new Count(1, 5); //Límites inferior y superior de comida por tablero.
public GameObject exit; //Prefab parta la salida.
public GameObject[] floorTiles; //Array de prefabs de suelo.
public GameObject[] wallTiles; //Array de prefabs de muros.
public GameObject[] foodTiles; //Array de prefabs de comida.
public GameObject[] enemyTiles; //Array de prefabs de enemigos.
public GameObject[] outerWallTiles; //Array de prefabs de muros exteriores.

private Transform boardHolder; //Referencia de la transform del tablero.
private List gridPositions = new List(); //Lista de posibles ubicaciones de los tiles.

//Limpia la lista de posiciones y la prepara para generar un nuevo tablero
void InitialiseList()
{
//Limpia la lista de posiciones
gridPositions.Clear();

//Recorre el eje x (columnas)
for (int x = 1; x < columns - 1; x++)
{
//En cada columna, recorre el eje y (filas)
for (int y = 1; y < rows - 1; y++)
{
//En cada celda, añade un nuevo vector 3 con la coordenadas x e y de esa posición
gridPositions.Add(new Vector3(x, y, 0f));
}
}
}


//Configura los muros exteriores y el suelo del tablero
void BoardSetup()
{
//Instancio el tablero y el contenedor del tablero a su trasnform
boardHolder = new GameObject("Board").transform;

//Recorro el eje x (desde -1 para rellenar la esquina) con suelo o muros exteriores
for (int x = -1; x < columns + 1; x++)
{
//Recorro el eje y (desde -1 para rellenar la esquina) con suelo o muros exteriores
for (int y = -1; y < rows + 1; y++)
{
//Elijo un tile random del array de suelo y lo preparo para instanciar
GameObject toInstantiate = floorTiles[Random.Range(0, floorTiles.Length)];

//Si es un límite, instancio un muro exterior aleatorio
if (x == -1 || x == columns || y == -1 || y == rows)
toInstantiate = outerWallTiles[Random.Range(0, outerWallTiles.Length)];

//Instancio el objeto escogido en la posición escogida como GameObject
GameObject instance = Instantiate(toInstantiate, new Vector3(x, y, 0f), Quaternion.identity) as GameObject;

//Asigno al contenedor del tablero como padre del objeto instanciado
instance.transform.SetParent(boardHolder);
}
}
}


//Devuelve una posición aleeatoria de nuestra lista de posibles ubicaciones.
Vector3 RandomPosition()
{
//Entero aleatorio entre 0 y el total de items de la lista
int randomIndex = Random.Range(0, gridPositions.Count);

//Vector3 en la posición obtenida
Vector3 randomPosition = gridPositions[randomIndex];

//Elimino la posición obtenida para no volverla a usar en el tablero
gridPositions.RemoveAt(randomIndex);

//Devuelvo el vector3 creado.
return randomPosition;
}


//Acepta un array de objetos para elegir entre un mínimo y un máximo de objetos para crear
void LayoutObjectAtRandom(GameObject[] tileArray, int minimum, int maximum)
{
//Número aleatorio de objetos a instanciar entre el máximo y el mínimo
int objectCount = Random.Range(minimum, maximum + 1);

//Instancio objetos hasta el máximo obtenido
for (int i = 0; i < objectCount; i++)
{
//Obtengo unVector3 en una posición con nuestra función RandomPosition
Vector3 randomPosition = RandomPosition();

//Escojo un tile aleatorio del array de opciones
GameObject tileChoice = tileArray[Random.Range(0, tileArray.Length)];

//Instancio el tile escogido en la posición escogida (sin cambios en la rotación)
Instantiate(tileChoice, randomPosition, Quaternion.identity);
}
}


//Inicio el nivel usando las funciones anteriores
public void SetupScene(int level)
{
//Muros exteriores y suelo.
BoardSetup();

//Reseteo lista de posiciones.
InitialiseList();

//Instancio un número aleatorio de muros basado en el mínimo y el máximo en posiciones aleatorias
LayoutObjectAtRandom(wallTiles, wallCount.minimum, wallCount.maximum);

//Instancio un número aleatorio de comidas basado en el mínimo y el máximo en posiciones aleatorias
LayoutObjectAtRandom(foodTiles, foodCount.minimum, foodCount.maximum);

//Determino el número de enemigos basado en el número de nivel con progresión logarítmica
//A partir del nivel 3 aparecen enemigos
int enemyCount = (int)Mathf.Log(level, 2f);

//Instancio un número aleatorio de enemigos basado en el mínimo y el máximo en posiciones aleatorias
LayoutObjectAtRandom(enemyTiles, enemyCount, enemyCount);

//Instancio el tile de salida en la esquina superior derecha del tablero
Instantiate(exit, new Vector3(columns - 1, rows - 1, 0f), Quaternion.identity);
}
}



using UnityEngine;

public class GameManager : MonoBehaviour
{

public static GameManager instance = null; //Instancia al GameManager para poder acceder desde otro script
private BoardManager boardScript; //Renerencia a BoardManager para configurar el nivel.
private int level = 3; //Número de nivel, expresado en el juego como "Día 1".

//Awake es llamado antes de Start()
void Awake()
{
//Si no existe instancia al GameManager
if (instance == null){

//La igualo a la actual
instance = this;

}

//Si ya existe y no es esta:
else if (instance != this){

//La destruyo para que solo haya una.
Destroy(gameObject);

}

//Le digo que no la destruya durante todo el juego
DontDestroyOnLoad(gameObject);

//Inicializo el componente BoardManager
boardScript = GetComponent<BoardManager>();

//Inicio el juego
InitGame();
}

//Inicio el juego
void InitGame()
{
//Llamo a la función SetupScene con el nivel actual
boardScript.SetupScene(level);

}

}


Y lo siguiente que debemos hacer es asociar todas las variables correspondientes de los scripts de Game Manager con nuestros Prefabs (puedes usar el candado del Inspector window para seleccionar varios sin perder el foco del Game Manager):



Antes de generar el nivel, ajusta la PositionXYZ de la Main Camera a 3.5, 3.5, -10 y el Background a negro.

El resultado debería ser similar a este:



Una vez probado que el nivel se crea, arrastra el objeto Game Manager a la carpeta de Prefabs, bórralo de la Hierarchy window.

Para finalizar, crea un nuevo script llamado Loader que se encargará de lanzar nuestro juego y asóciaselo a la Main Camera:


using UnityEngine;

public class Loader : MonoBehaviour
{
public GameObject gameManager; //Prefab Game Manager a instanciar.


void Awake()
{
//Si no hay un script GameManager asignado o está vacío
if (GameManager.instance == null){

//Lo instancio
Instantiate(gameManager);

}

}

}


No olvides asociar la variable Game Manager con el prefab Game Manager.


Publicado el 09 de Diciembre de 2022