using System; using UnityEngine; // TODO: maybe instead of inheritance I could use behaviours // So the Unit will still be a thing, and that's what the CameraController interfaces with // But then commands will be sent to any attached behaviour (worker, marine, etc). // and that behaviour can do whatever it needs. // Now that I think about it more, maybe more granular behaviours (move, mine, build, attack, etc). public class Worker : Unit { private enum WorkerState { None, Building, Mining, Moving } public Building barracksGo; public float mineDuration; public int mineralHarvestAmount; private WorkerState _currentState; private Building _constructionBuilding; private Minerals _minerals; private Vector2 _mineralPatch; private Vector2 _commandCenter; private int _currentMineralsHeld; private float _mineStartTime; protected override void Start() { base.Start(); _currentState = WorkerState.None; } private void Update() { // TODO: maybe a function pointer instead of this switch? switch (_currentState) { case WorkerState.None: // Literally do nothing. break; case WorkerState.Building: BuildBarracks(); break; case WorkerState.Mining: MineMinerals(); break; case WorkerState.Moving: MovementRoutine(); break; default: throw new ArgumentOutOfRangeException(); } } private void MineMinerals() { _currentState = WorkerState.Mining; if (_currentMineralsHeld <= 0) { if ((Vector2) _transform.position != _mineralPatch) { MoveTo(_mineralPatch); _doThingAfterMove = () => { _mineStartTime = Time.time; MineMinerals(); }; } else { // TODO: wait to mine minerals; if (Time.time >= _mineStartTime + mineDuration) { var amount = mineralHarvestAmount; if (_minerals.amount < amount) { amount = _minerals.amount; } _minerals.amount -= amount; _currentMineralsHeld = amount; } } } else { if ((Vector2) _transform.position != _commandCenter) { MoveTo(_commandCenter); _doThingAfterMove = MineMinerals; } else { Team.Minerals += _currentMineralsHeld; _currentMineralsHeld = 0; } } } private void BuildBarracks() { // Since we are in the Building state, just assume we have a construction building. if (_constructionBuilding.isUnderConstruction) { _constructionBuilding.UpdateBuildProgress(Time.deltaTime); } else { // change state _currentState = WorkerState.None; } } private void InstantiateBarracks() { if (barracksGo.buildingCost > Team.Minerals) { Debug.LogWarning("You've not enough minerals!"); return; } Team.Minerals -= barracksGo.buildingCost; _constructionBuilding = Instantiate(barracksGo, _transform.position + new Vector3(0.5f, 0, 0), _transform.rotation); Team.AllBuildings.Add(_constructionBuilding); _currentState = WorkerState.Building; _doThingAfterMove = null; } protected override void CancelCurrentTask() { _currentState = WorkerState.None; _doThingAfterMove = null; // Might be able to just set the building to null all the time? if (_currentState == WorkerState.Building) { _constructionBuilding = null; } } public override void MoveTo(Vector3 position) { base.MoveTo(position); _currentState = WorkerState.Moving; } // Called when the user selects the build barracks command. public void BuildBarracks(Vector3 position) { MoveTo(position); _doThingAfterMove = InstantiateBarracks; } // Called when the user right clicks on an unfinished building. public void ConstructBuilding(Building building, Vector3 position) { MoveTo(position); _constructionBuilding = building; _doThingAfterMove = () => _currentState = WorkerState.Building; } public void StartMining(Minerals patch, Vector2 patchLocation, Vector2 commandCenterLocation) { _mineralPatch = patchLocation; _commandCenter = commandCenterLocation; _minerals = patch; _currentState = WorkerState.Mining; } }