Skip to content

Instantly share code, notes, and snippets.

@Cruxial0
Created November 10, 2023 10:24
Show Gist options
  • Save Cruxial0/114499f5b825a1dbda90cc209d3ac21e to your computer and use it in GitHub Desktop.
Save Cruxial0/114499f5b825a1dbda90cc209d3ac21e to your computer and use it in GitHub Desktop.
Workstation system
public class ResourceNode : Workstation
{
[SerializeField] private ResourceType resourceType;
[SerializeField] private float collectInterval = 30f;
[SerializeField] private int supply = 300;
private int _currSupply = 300;
protected override void Start() {
_currSupply = supply;
base.Start();
}
private void Update() {
foreach (var unit in PresentUnits) {
IncrementUnitTimer(unit);
if (_unitTimers[unit] < collectInterval) continue;
ResetUnitTimer(unit);
// Define a delta value based on the unit's scavenger level
var change = unit.Levels.Scavenger.Level + 1;
_currSupply -= change;
// Add resources and unit experience
ResourceManager.Instance.AllocateResources(resourceType, change);
unit.SetExp(workType, Random.Range(0, 3));
if (_currSupply <= 0) {
RemoveUnits();
MessageReciever.Instance.Message(MessageType.ResourceDepleted, $"{resourceType} Node was depleted");
Destroy(gameObject);
}
}
}
}
[RequireComponent(typeof(ContextMenuItem))]
public class Workstation : MonoBehaviour
{
/// <summary>
/// Max amount of workers on this workstation
/// </summary>
[Range(0, 10)] [SerializeField] protected int maxWorkers;
/// <summary>
/// The radius around the building where the units will attatch to
/// </summary>
[Range(0, 30)] [SerializeField] protected float workerAttachmentRadius = 2f;
/// <summary>
/// The profession related to this workstation
/// </summary>
[SerializeField] protected Profession workType;
/// <summary>
/// How units behave at this workstation *(currently not implemented)*
/// </summary>
[SerializeField] protected WorkstationUnitBehaviour unitBehaviour = WorkstationUnitBehaviour.None;
protected Dictionary<Unit, float> _unitTimers = new();
private float _adjacencyTimer = 1f;
private float _currTimeout;
private ContextMenuItem _contextMenuItem;
protected virtual void Start() {
_contextMenuItem = GetComponent<ContextMenuItem>();
}
/// <summary>
/// A list of users assigned to this workstation
/// </summary>
protected List<Unit> Units = new();
/// <summary>
/// Units that are working at this workstation
/// </summary>
protected List<Unit> PresentUnits = new();
/// <summary>
/// Adds a unit to this workstation
/// </summary>
public virtual void AddUnit(Unit unit) {
if(Units.Count >= maxWorkers) return;
unit.SetWorkstation(this);
Units.Add(unit);
_unitTimers.TryAdd(unit, 0f);
unit.Killed += HandleUnitDeath;
}
/// <summary>
/// Tries to add a unit to this workstation. Returns false if there is no more space in the workstation.
/// </summary>
public virtual bool TryAddUnit(Unit unit) {
if (Units.Count >= maxWorkers) return false;
AddUnit(unit);
return true;
}
/// <summary>
/// Removes all units from this workstation
/// </summary>
public void RemoveUnits() {
foreach (var unit in Units) {
RemoveUnit(unit, true);
}
Units.Clear();
}
/// <summary>
/// Removes a unit from this workstation
/// </summary>
public virtual void RemoveUnit(Unit unit, bool skipRemove = false) {
if(!skipRemove) Units.Remove(unit);
unit.SetWorkstation(null);
unit.StopWork();
if (_unitTimers.ContainsKey(unit)) _unitTimers.Remove(unit);
unit.Killed -= HandleUnitDeath;
}
/// <summary>
/// Calls a specific unit to this workstation
/// </summary>
public virtual void CallUnit(Unit unit) {
unit.MoveTo(transform.position + GetRandomPositionInCircle());
unit.StartWork();
}
/// <summary>
/// Calls all assigned units to this workstation
/// </summary>
public virtual void CallAssignedUnits() {
foreach (var unit in Units) {
unit.MoveTo(transform.position + GetRandomPositionInCircle());
}
}
public virtual void FixedUpdate() {
_currTimeout += Time.fixedDeltaTime;
if(_currTimeout < _adjacencyTimer) return;
PresentUnits = Units.Where(x =>
Vector3.Distance(x.transform.position, this.transform.position) < workerAttachmentRadius + 1f).ToList();
_contextMenuItem.workers = PresentUnits;
}
/// <summary>
/// Increments the work timer for the specified unit based on Time.deltaTime or Time.fixedDeltaTime
/// </summary>
protected virtual void IncrementUnitTimer(Unit unit, bool useFixedDeltaTime = false) {
if (_unitTimers.ContainsKey(unit))
_unitTimers[unit] += useFixedDeltaTime ? Time.fixedDeltaTime : Time.deltaTime;
else _unitTimers.Add(unit, 0f);
}
/// <summary>
/// Resets the unit's timer to 0
/// </summary>
protected virtual void ResetUnitTimer(Unit unit) {
if (_unitTimers.ContainsKey(unit)) _unitTimers[unit] = 0f;
}
private Vector3 GetRandomPositionInCircle() {
float angle = Random.Range(0, 360) * Mathf.PI * 2f / workerAttachmentRadius;
return new Vector3(Mathf.Cos(angle) * workerAttachmentRadius, 0, Mathf.Sin(angle) * workerAttachmentRadius);
}
/// <summary>
/// Makes sure units are removed upon death
/// </summary>
private void HandleUnitDeath(object sender, Unit e) {
Units.Remove(e);
if (PresentUnits.Contains(e)) PresentUnits.Remove(e);
if (_unitTimers.ContainsKey(e)) _unitTimers.Remove(e);
}
#if UNITY_EDITOR
/// <summary>
/// Creates a visual representation in the unity editor of where the units will stand
/// </summary>
private void OnDrawGizmosSelected() {
Handles.color = Color.cyan;
Handles.DrawWireDisc(transform.localPosition, Vector3.up, workerAttachmentRadius);
}
#endif
}
public enum WorkstationUnitBehaviour
{
None,
Disappear,
WorkAnimation
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment