using System; using UnityEngine; using UnityEngine.AI; public class Gatherer : MonoBehaviour { public event Action OnGatheredChanged; [SerializeField] private int _maxCarried = 20; private StateMachine _stateMachine; private int _gathered; public GatherableResource Target { get; set; } public StockPile StockPile { get; set; } private void Awake() { var navMeshAgent = GetComponent(); var animator = GetComponent(); var enemyDetector = gameObject.AddComponent(); var fleeParticleSystem = gameObject.GetComponentInChildren(); _stateMachine = new StateMachine(); var search = new SearchForResource(this); var moveToSelected = new MoveToSelectedResource(this, navMeshAgent, animator); var harvest = new HarvestResource(this, animator); var returnToStockpile = new ReturnToStockpile(this, navMeshAgent, animator); var placeResourcesInStockpile = new PlaceResourcesInStockpile(this); var flee = new Flee(this, navMeshAgent, enemyDetector, animator, fleeParticleSystem); At(search, moveToSelected, HasTarget()); At(moveToSelected, search, StuckForOverASecond()); At(moveToSelected, harvest, ReachedResource()); At(harvest, search, TargetIsDepletedAndICanCarryMore()); At(harvest, returnToStockpile, InventoryFull()); At(returnToStockpile, placeResourcesInStockpile, ReachedStockpile()); At(placeResourcesInStockpile, search, () => _gathered == 0); _stateMachine.AddAnyTransition(flee, () => enemyDetector.EnemyInRange); At(flee, search, () => enemyDetector.EnemyInRange == false); _stateMachine.SetState(search); void At(AIState to, AIState from, Func condition) => _stateMachine.AddTransition(to, from, condition); Func HasTarget() => () => Target != null; Func StuckForOverASecond() => () => moveToSelected.TimeStuck > 1f; Func ReachedResource() => () => Target != null && Vector3.Distance(transform.position, Target.transform.position) < 1f; Func TargetIsDepletedAndICanCarryMore() => () => (Target == null || Target.IsDepleted) && !InventoryFull().Invoke(); Func InventoryFull() => () => _gathered >= _maxCarried; Func ReachedStockpile() => () => StockPile != null && Vector3.Distance(transform.position, StockPile.transform.position) < 1f; } private void Update() { _stateMachine.Tick(); } public void TakeFromTarget() { if (Target.Take()) { _gathered++; OnGatheredChanged?.Invoke(_gathered); } } public bool Take() { if (_gathered <= 0) return false; _gathered--; OnGatheredChanged?.Invoke(_gathered); return true; } public void DropAllResources() { if (_gathered > 0) { FindObjectOfType().Drop(_gathered, transform.position); _gathered = 0; OnGatheredChanged?.Invoke(_gathered); } } }