using UnityEngine; using UnityEngine.AI; using VOID.Generic.Objects.Abstract; using VOID.Generic.Objects.Unit.Actions.Exceptions; using VOID.Generic.Objects.Unit.Events; using VOID.Generic.Util; namespace VOID.Generic.Objects.Unit.Actions { public class MoveAction : AbstractAction { private readonly UnitObject _unit; private readonly Vector3 _targetPosition; private readonly AbstractObject _targetObject; private readonly float _untilInRange; public MoveAction(UnitObject unit, Vector3 targetPosition, float untilInRange = 0f) { _unit = unit; _targetPosition = targetPosition; _untilInRange = untilInRange; } public MoveAction(UnitObject unit, AbstractObject targetObject, float untilInRange = 0f) : this(unit, targetObject.transform.position, untilInRange + targetObject.basicData.radius) { _targetObject = targetObject; } public override bool IsInRange() { // Dont let player ordering move too far away var distanceBetween = Vector3.Distance(_unit.transform.position, _targetPosition); return distanceBetween < 100f; } public override bool CanBeStopped() { return !_unit.unitState.isTraversing; } protected override void OnEndIt() { _unit.unitEvents.onMoveEnd.RemoveListener(OnMoveEnd); } protected override void OnCancelIt() { _unit.unitEvents.onMoveEnd.RemoveListener(OnMoveEnd); _unit.unitNavAgent.Stop(); } public override void CanDoIt() { Check( _unit.unitData.canMove, UnitActionErrorType.ThisUnitCantMove); Check( state == ActionState.Ready, UnitActionErrorType.ActionStateIsNotReady); Check( !_unit.unitState.isCasting, UnitActionErrorType.ThisUnitIsCasting); if (_unit.basicState.turnManager) { Check( _unit.unitState.isSelfTurn, UnitActionErrorType.UnitSelfTurnNotActive); Check( _unit.unitData.currentResources.movePoints > 0.1f, UnitActionErrorType.UnitNotEnoughMovePoints); } Check( _unit.unitState.isControllable, UnitActionErrorType.UnitStateIsNotControllable); Check( IsInRange(), UnitActionErrorType.NotInRange); _unit.unitNavAgent.CalculatePathTo(_targetPosition, _untilInRange); Check( _unit.unitNavAgent.GetPath().status is not NavMeshPathStatus.PathInvalid, UnitActionErrorType.NoPathToTarget); } protected override void OnDoIt() { var isInRange = _targetObject ? RangeUtil.IsInRange(_unit, _targetObject, _untilInRange, false) : RangeUtil.IsInRange(_unit, _targetPosition, _untilInRange, false); if (isInRange) { EndIt(); return; } BeforePerform(); _unit.unitEvents.onMoveEnd.AddListener(OnMoveEnd); var moveStarted = _targetObject ? _unit.unitNavAgent.Move(_targetObject, _untilInRange) : _unit.unitNavAgent.Move(_targetPosition, _untilInRange); // Unit didn't move for some reason (usually path is impossible or already at path destination) if (!moveStarted) EndIt(); } private void OnMoveEnd(MoveEvent moveEvent) { AfterPerform(); EndIt(); } } }