Setup World Class
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using EZObjectPools;
public class SetupWorld : MonoBehaviour
{
/// <summary>
/// This class takes 2 parameters and prepares a grid for the playing field. The 2 parameters are read from the "WorldManager" class. The "worldSize" parameter defines how many tiles the grid has, and the "cellSize" parameter defines how many square Unity units the tiles are in size.
/// Each tile is tracked in an array so it can be specifically referenced when the world needs to check if something is occupying the tile or not.
/// Additionally, the lines to create the grid are object pooled so they can be reused, instead of instantiated and then destroyed continuously.
/// </summary>
// OBJECT POOLS
public EZObjectPool gridLinePool;
public EZObjectPool gridCellPool;
[Header("Tile Prefab")]
public GameObject vacantPlanePrefab;
[Header("Tile Parent")]
public Transform vacantPlaneParent;
[HideInInspector]
public GameObject[] vacantPlaneArray;
int vacantPlaneArraySize = 0;
private void Awake()
{
SetupVacantPlaneArray();
}
private void Start()
{
BuildGrid();
}
void BuildGrid()
{
// X grid lines
for (int i = 0; i <= WorldManager.Instance.worldSize; i++)
{
Vector3 currentPlacement = new Vector3((i * WorldManager.Instance.cellSize) - 2, .01f, 0);
gridLinePool.TryGetNextObject(currentPlacement, Quaternion.Euler(90, 0, 0));
}
// Z grid lines
for (int i = 0; i <= WorldManager.Instance.worldSize; i++)
{
Vector3 currentPlacement = new Vector3(0, .01f, (i * WorldManager.Instance.cellSize) - 2);
gridLinePool.TryGetNextObject(currentPlacement, Quaternion.Euler(90, 90, 0));
}
// Iterate through the X row.
for (int i = 0; i < WorldManager.Instance.worldSize; i++)
{
int currentXRow = i * WorldManager.Instance.cellSize;
// A nested iteration that fills out the Z column of each row.
for (int j = 0; j < WorldManager.Instance.worldSize; j++)
{
Vector3 currentPlacement = new Vector3(currentXRow, .006f, (j * WorldManager.Instance.cellSize));
gridCellPool.TryGetNextObject(currentPlacement, Quaternion.identity);
}
}
}
// Builds the tile array that will be referenced when the grid is being built.
void SetupVacantPlaneArray()
{
vacantPlaneArraySize = WorldManager.Instance.worldSize * WorldManager.Instance.worldSize;
vacantPlaneArray = new GameObject[vacantPlaneArraySize];
for(int i = 0;i<vacantPlaneArray.Length;i++)
{
vacantPlaneArray[i] = Instantiate(vacantPlanePrefab, vacantPlaneParent);
}
}
// Places a tile from the tile array into it's designated position.
public void SetVacantPlane(Vector3 _position, int arrayValue, bool _enable)
{
GameObject vacantPlaneObject = vacantPlaneArray[arrayValue];
if (_enable)
{
vacantPlaneObject.SetActive(true);
vacantPlaneObject.transform.position = _position;
}
else
{
vacantPlaneObject.SetActive(false);
}
}
}
World Manager Class
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Has functions for building the world array and checking the status of array locations. Builds the world along positives axes starting at 0,0.
/// </summary>
public class WorldManager : MonoBehaviour
{
[Header("Class References")]
public SetupWorld setupWorld;
public SummonLand summonLand;
public int worldSize = 8; // the number of grid spaces in each direction
public int cellSize = 4; // the size of each grid space
public WorldData[] worldDataArray;
public WorldData[] storedWorldDataArray;
[Header("Start Settings")]
public Direction player1StartingPosition;
[Header("Object References")]
public GameObject objectPools;
[Header("Lists")]
List<Vector2> queuedLandVectorsPlayer1;
List<Vector2> queuedLandVectorsPlayer2;
#region singleton
private static WorldManager instance;
public static WorldManager Instance
{
get
{
if (instance == null)
{
instance = GameObject.FindObjectOfType<WorldManager>();
if (instance == null)
{
Debug.LogError("No WorldManager was found in this scene. Make sure you place one in the scene.");
return instance;
}
}
return instance;
}
}
void Awake()
{
if (instance == null)
{
instance = GameObject.FindObjectOfType<WorldManager>();
if (instance == null)
{
Debug.LogError("No WorldManager was found in this scene. Make sure you place one in the scene.");
return;
}
}
else
{
DestroyNonInstanceDuplicates();
}
}
public void OnApplicationQuit()
{
instance = null;
}
private bool DestroyNonInstanceDuplicates()
{
if (this != instance)
{
Destroy(gameObject);
return true;
}
return false;
}
#endregion
private void Start()
{
BuildWorldDataArray();
PlaceStartingLands(player1StartingPosition);
MarkVacantCells();
CopyWorldDataArray();
RefreshLandQueue();
}
/// <summary>
/// At the beginning of the casting phase, we copy the current world data array. When we switch to the play phase we roll back to the copied version of the world data array.
/// </summary>
public void CopyWorldDataArray()
{
storedWorldDataArray = new WorldData[worldSize * worldSize];
for (int i = 0; i < storedWorldDataArray.Length; i++)
{
storedWorldDataArray[i] = new WorldData(worldDataArray[i].x, worldDataArray[i].z, worldDataArray[i].cardIdentityNumber,worldDataArray[i].ownerPlayer);
}
}
public void RollbackWorldDataArray()
{
worldDataArray = storedWorldDataArray;
MarkVacantCells();
}
/// <summary>
/// Builds the world out in the direction of positive axes starting at 0,0.
/// </summary>
void BuildWorldDataArray()
{
int xValue = 0;
int zValue = 0;
worldDataArray = new WorldData[worldSize * worldSize];
for(int i = 0; i < worldDataArray.Length; i++)
{
worldDataArray[i] = new WorldData(xValue, zValue, -1,0);
zValue += 1;
if(zValue < worldSize)
{
}
else
{
zValue = 0;
xValue += 1;
}
}
}
public void UpdateWorldData(Vector3 _position, int _cardIdentityNumber, int _ownerPlayer)
{
int arrayValue = ArrayValue(_position);
worldDataArray[arrayValue].cardIdentityNumber = _cardIdentityNumber;
worldDataArray[arrayValue].ownerPlayer = _ownerPlayer;
MarkVacantCells();
}
/// <summary>
/// Returns true if it detects a land adjacent to the target position.
/// </summary>
/// <param name="_position"></param>
/// <returns></returns>
public bool CheckAdjacentLand(Vector3 _position, int _ownerPlayer)
{
int targetArrayValue = ArrayValue(_position);
Vector2 targetArrayVector = ArrayVector(_position);
Vector2[] adjacentArrayPositions = new Vector2[4];
// these are the z grid positions "above" and "below" the current spot
adjacentArrayPositions[0] = new Vector2(targetArrayVector.x, targetArrayVector.y - 1);
adjacentArrayPositions[1] = new Vector2(targetArrayVector.x, targetArrayVector.y + 1);
// these are the x grid positions to the "left" and "right", a column over
adjacentArrayPositions[2] = new Vector2(targetArrayVector.x - 1 ,targetArrayVector.y);
adjacentArrayPositions[3] = new Vector2(targetArrayVector.x + 1, targetArrayVector.y);
bool adjacentLand = false;
for(int i = 0; i< adjacentArrayPositions.Length; i++)
{
if(CheckIfArrayPositionIsInBounds(adjacentArrayPositions[i]))
{
int _arrayValue = ArrayValue(adjacentArrayPositions[i]);
if(worldDataArray[_arrayValue].cardIdentityNumber >= 0 && worldDataArray[_arrayValue].ownerPlayer == _ownerPlayer) // check that land exists and that it belongs to the player we're checking for
{
adjacentLand = true;
}
}
}
return adjacentLand;
}
/// <summary>
/// Returns true if the target position is empty.
/// </summary>
/// <param name="_position"></param>
/// <returns></returns>
public bool CheckTargetPosition(Vector3 _position)
{
bool targetPositionIsEmpty;
int targetArrayValue = ArrayValue(_position);
if (targetArrayValue < worldDataArray.Length)
{
if (worldDataArray[targetArrayValue].cardIdentityNumber >= 0)
{
targetPositionIsEmpty = false;
}
else
{
targetPositionIsEmpty = true;
}
}
else
{
targetPositionIsEmpty = false;
}
return targetPositionIsEmpty;
}
/// <summary>
/// Checks if the local array coordinates are within the world grid. Checks if either value is above world size or below 0.
/// </summary>
/// <param name="arraySpot"></param>
/// <returns></returns>
bool CheckIfArrayPositionIsInBounds(Vector2 arraySpot)
{
if(arraySpot.x > worldSize - 1)
{
return false;
}
if (arraySpot.x < 0)
{
return false;
}
if (arraySpot.y > worldSize - 1)
{
return false;
}
if (arraySpot.y < 0)
{
return false;
}
return true;
}
/// <summary>
/// Takes a vector3 world position and uses the x and z to find the arrayValue.
/// </summary>
/// <param name="_position"></param>
/// <returns></returns>
int ArrayValue(Vector3 _position)
{
int _arrayValue;
int xPosition = Mathf.RoundToInt(_position.x / cellSize);
int zPosition = Mathf.RoundToInt(_position.z / cellSize);
// the formula to know an array position is (_x * world size) + _z, for example, world spot (2,3) [x row 2, z column 3] in a world size 8, would be (2 * 8) + 3, so array spot 19.
return _arrayValue = (xPosition * worldSize) + zPosition;
}
/// <summary>
/// uses the array Vector coordinates to find the array value. This is in the local space of the grid adjusted for world and cell size
/// </summary>
/// <param name="_arrayVector"></param>
/// <returns></returns>
int ArrayValue(Vector2 _arrayVector)
{
int _arrayValue;
int xPosition = Mathf.RoundToInt(_arrayVector.x);
int zPosition = Mathf.RoundToInt(_arrayVector.y);
// the formula to know an array position is (_x * world size) + _z, for example, world spot (2,3) [x row 2, z column 3] in a world size 8, would be (2 * 8) + 3, so array spot 19.
return _arrayValue = (xPosition * worldSize) + zPosition;
}
/// <summary>
/// Gets the world array vector value from a Vector3 world position value.
/// </summary>
/// <param name="_position"></param>
/// <returns></returns>
Vector2 ArrayVector(Vector3 _position)
{
int xPosition = Mathf.RoundToInt(_position.x / cellSize);
int zPosition = Mathf.RoundToInt(_position.z / cellSize);
return new Vector2(xPosition, zPosition);
}
Vector3 GetWorldPositionOfArrayValue(int _arrayValue)
{
int _xValue = Mathf.FloorToInt(_arrayValue / worldSize);
int _zValue = _arrayValue - (_xValue * worldSize);
return new Vector3(_xValue * cellSize, 0, _zValue * cellSize);
}
Vector3 GetWorldPositionOfArrayVector(Vector2 _arrayVector)
{
int arrayValueFromVector = ArrayValue(_arrayVector);
return GetWorldPositionOfArrayValue(arrayValueFromVector);
}
void MarkVacantCells()
{
for(int i = 0;i<worldDataArray.Length;i++)
{
if(worldDataArray[i].cardIdentityNumber < 0)
{
Vector3 arrayValuePosition = GetWorldPositionOfArrayValue(i);
setupWorld.SetVacantPlane(arrayValuePosition,i,true);
}
else
{
setupWorld.SetVacantPlane(Vector3.zero, i, false);
}
}
}
void PlaceStartingLands(Direction _startingPlacement)
{
if (_startingPlacement == Direction.NorthWest)
{
// player 1 placement
Vector2[] startingTiles = new Vector2[4];
startingTiles[0] = new Vector2(0, worldSize - 1);
startingTiles[1] = new Vector2(1, worldSize - 1);
startingTiles[2] = new Vector2(0, worldSize - 2);
startingTiles[3] = new Vector2(1, worldSize - 2);
for(int i = 0; i< startingTiles.Length;i++)
{
summonLand.ForcePlaceLand(GetWorldPositionOfArrayVector(startingTiles[i]), 0,1);
}
// enemy placement player 2
startingTiles = new Vector2[4];
startingTiles[0] = new Vector2(worldSize - 1,0 );
startingTiles[1] = new Vector2(worldSize - 2, 0);
startingTiles[2] = new Vector2(worldSize - 1, 1);
startingTiles[3] = new Vector2(worldSize - 2, 1);
for (int i = 0; i < startingTiles.Length; i++)
{
summonLand.ForcePlaceLand(GetWorldPositionOfArrayVector(startingTiles[i]), 0,2);
}
}
}
/// <summary>
/// Clears the list that holds the coordinates for lands trying to be placed during the current queue number. Called by PlayManager each time the queue changes.
/// </summary>
public void RefreshLandQueue()
{
queuedLandVectorsPlayer1 = new List<Vector2>();
queuedLandVectorsPlayer2 = new List<Vector2>();
}
/// <summary>
/// Adds a land to be checked during the current queue number for conflicts. This does not actually perform the check.
/// </summary>
/// <param name="_position"></param>
public void AddLandToQueue(int _ownerPlayer,Vector3 _position)
{
if (_ownerPlayer == 1)
{
queuedLandVectorsPlayer1.Add(ArrayVector(_position));
}
if(_ownerPlayer == 2)
{
queuedLandVectorsPlayer2.Add(ArrayVector(_position));
}
}
/// <summary>
/// Returns true if there's a conflict. Checks if there are any placement conflicts between the land vectors that have been added to the queue.
/// </summary>
public bool CheckLandQueueForConflicts()
{
for(int i = 0; i <queuedLandVectorsPlayer1.Count;i++)
{
for(int h = 0;h<queuedLandVectorsPlayer2.Count;h++)
{
if(queuedLandVectorsPlayer1[i] == queuedLandVectorsPlayer2[h])
{
return true;
}
}
}
return false;
}
}
Like this:
Like Loading...