Code Samples

Monster Defense Pooling System

For Monster Defense, we needed a pooling system made to support multiple Enum-organized sets of Game Objects with a minimal performance impact. This pooling setup allowed us to create sets of pooled objects in which the objects could easily be accessed and spawned by passing in the desired Enum ID. All pooled items were additionally given easy cleanup through either a single function call or a despawn timer given when pulled from the pool.

public class Pool
{
    private PoolItem _poolItem;
    private Queue<PoolItem> _pool;
    private GameObject _parentObject;

    public Transform GetParentTransform() => _parentObject.transform;

    public GameObject Spawn(Vector3 position, float lifetime = 0, bool setActive = true)
    {
        if (_pool.Count < 1)
        {
            AddToPool(1);
        }
        PoolItem objectToSpawn = _pool.Dequeue();
        objectToSpawn.transform.position = position;
        objectToSpawn.gameObject.SetActive(setActive);
        objectToSpawn.OnSpawn(this, lifetime);
        return objectToSpawn.gameObject;
    }

    public void Despawn(PoolItem poolItem)
    {
        poolItem.gameObject.SetActive(false);
        if(poolItem.transform.parent != _parentObject.transform)
        {
            poolItem.transform.SetParent(_parentObject.transform);
        }
        _pool.Enqueue(poolItem);
    }

    private void AddToPool(int amount)
    {
        for (int i = 0; i < amount; i++)
        {
            PoolItem poolItem = GameObject.Instantiate(_poolItem, Vector3.zero, Quaternion.Euler(0, 0, 0));
            poolItem.gameObject.SetActive(false);
            poolItem.transform.SetParent(_parentObject.transform);
            _pool.Enqueue(poolItem);
        }
    }

    public Pool(GameObject parentObject, PoolItem poolItem, int initialSpawnCount)
    {
        _pool = new Queue<PoolItem>();
        _parentObject = parentObject;
        _poolItem = poolItem;
        AddToPool(initialSpawnCount);
    }
}
public class PoolSet
{
    private Dictionary<int, Pool> _poolSet;
    private GameObject _parentObject;

        public GameObject Spawn(int enumID, Vector3 position, float lifetime = 0, bool setActive = true) 
        { 
            return _poolSet[enumID].Spawn(position, lifetime, setActive); 
        }

    public PoolSet(string poolSetName)
    {
        _poolSet = new Dictionary<int, Pool>();
        _parentObject = GameObject.Instantiate(new GameObject(), Vector3.zero, Quaternion.Euler(0, 0, 0));
        _parentObject.name = poolSetName;
    }

    public void AddPool(int enumID, PoolItem poolItem, int initialSpawnCount)
    {
        _poolSet.Add(enumID, new Pool(_parentObject, poolItem, initialSpawnCount));
    }

    public Pool GetPool(int enumID) => _poolSet[enumID];
}
public class PoolItem : MonoBehaviour
{
    private Pool _pool;

    public void OnSpawn(Pool pool, float lifetime = 0)
    {
        if(_pool == null)
        {
            _pool = pool;
        }
        if (lifetime > 0)
        {
            StartCoroutine(AutoDespawn(lifetime));
        }
    }

    public void Despawn()
    {
        StopAllCoroutines();
        _pool.Despawn(this);
    }

    private IEnumerator AutoDespawn(float lifetime)
    {
        yield return new WaitForSeconds(lifetime);
        Despawn();
    }
}

Board Spaces in The Royal Game of Ur

This code was used to simulate the states of a board space in a Unity recreation of the Royal Game of Ur. The board spaces serve as a guide to the pieces, and are made to both contain the proper pathway for the piece owner, as well as host the unique rules of the Rosette spaces and Supplanting opponent pieces.

public class BoardSpace : MonoBehaviour
{
    //Y coord offset
    private const float _pieceOffset = 3;

    [SerializeField] private bool _isRosette = false;

    private Vector3 _piecePosition;

    private BoardSpace _playerPathNext;
    private BoardSpace _opponentPathNext;
    private GamePiece _occupyingPiece;
    
    private int _spacesLeftInPath = 0;

public BoardSpace NextSpace(bool isPlayer) => isPlayer ? _playerPathNext : _opponentPathNext;
public Vector3 GetPosition() => _piecePosition;
public int SpacesLeftInPath => _spacesLeftInPath;
public bool IsRosette => _isRosette;
public GamePiece OccupyingPiece => _occupyingPiece;
private void Start() { _piecePosition = new Vector3(transform.position.x, transform.position.y + _pieceOffset, transform.position.z); } public bool CanOccupy(GamePiece piece) { if (_occupyingPiece == null ) return true; else if (_isRosette) return false; else if(_occupyingPiece._isPlayer == piece._isPlayer) return false; return true; } public bool TryOccupyingSpace(GamePiece piece) { if (CanOccupy(piece)) { if (_occupyingPiece != null) _occupyingPiece.Supplant(); _occupyingPiece = piece; return true; } return false; }

public void OnPieceLanding(GamePiece landingPiece) { _occupyingPiece = landingPiece; } public void OccupyingPieceMoved() => _occupyingPiece = null; public void InitializeSpace(BoardSpace playerNext, BoardSpace opponentNext) { _playerPathNext = playerNext; _opponentPathNext = opponentNext; }

public void SetNextInPath(BoardSpace space, bool isPlayerPath) { if (isPlayerPath) _playerPathNext = space; else _opponentPathNext = space; }

public void SetSpacesLeftInPath(int numSpaces) => _spacesLeftInPath = numSpaces; }