proto_rts/Assets/Scripts/Worker.cs

177 lines
5.0 KiB
C#

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;
}
}