Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public class Behaviorizer : MonoBehaviour {
- public NPCController c;
- Coroutine rootCo, actionCo;
- // ---------------------------------------------------------------------
- // Conditions
- // ---------------------------------------------------------------------
- public bool OkGo => actionCo == null;
- public bool IsBusy => c.IsBusy;
- public bool HasOrders => c?.orders != Orders.None;
- public bool InCombat => c?.attackTargets.Count > 0;
- public bool AttackReady => IsCurrentTargetValid && c.CanHitTarget;
- public bool IsCurrentTargetValid => c.currentTarget && c.currentTarget != null && !c.currentTarget.IsDead;
- public bool AtDestination => ((Vector2)c.transform.position - c.destination).sqrMagnitude < 0.1f;
- public bool c.CanHitTargetTarget => true;
- // ---------------------------------------------------------------------
- // Commands
- // ---------------------------------------------------------------------
- public void Interrupt() { CancelAction(); }
- private void StartAct(IEnumerator co) {
- CancelAction();
- actionCo = StartCoroutine(co);
- }
- private void CancelAction() {
- if (actionCo != null) { StopCoroutine(actionCo); actionCo = null; }
- }
- private IEnumerator RunUntil(Func<bool> done) {
- yield return new WaitUntil(done);
- actionCo = null;
- }
- private IEnumerator RunWhile(Func<bool> cond, Action bodyPerFrame) {
- while (cond()) { bodyPerFrame(); yield return null; }
- }
- private void ReturnToRoot() => actionCo = null;
- // ---------------------------------------------------------------------
- // The Machine
- // ---------------------------------------------------------------------
- public void Go(NPCController c) {
- this.c = c;
- if (rootCo != null) StopCoroutine(rootCo);
- rootCo = StartCoroutine(RunRoot());
- }
- private IEnumerator RunRoot() { //selectorizor
- while (OkGo) {
- _ = true switch {
- _ when IsBusy => StartCoroutine(DoNothing()),
- _ when InCombat => StartCoroutine(DoCombat()),
- _ => StartCoroutine(DoNonCombat()),
- };
- yield return new WaitUntil(() => OkGo);
- }
- }
- // ---------------------------------------------------------------------
- // Branches
- // ---------------------------------------------------------------------
- private IEnumerator DoNothing() {
- StartAct(StopMoving());
- yield return RunUntil(() => !c.IsBusy);
- }
- private IEnumerator DoCombat() {
- while (InCombat) {
- if (HasOrders) {
- yield return DoOrders();
- continue;
- }
- if (AttackReady) {
- StartAct(Attack(c));
- yield return RunUntil(() => !c.isAttacking || !IsCurrentTargetValid || !CanHitTarget);
- //if (!IsCurrentTargetValid) SelectClosestTarget(); // local helper below
- continue;
- }
- if (IsCurrentTargetValid && !CanHitTarget) {
- StartAct(MoveToTarget(c));
- yield return new WaitUntil(() => c.CanHitTargetTarget || !IsCurrentTargetValid || HasOrders || IsBusy);
- continue;
- }
- if (!IsCurrentTargetValid) {
- //SelectClosestTarget();
- if (!IsCurrentTargetValid) break;
- }
- yield return null;
- }
- ReturnToRoot();
- }
- private IEnumerator DoOrders() {
- while (HasOrders && !IsBusy) {
- switch (c.orders) {
- case Orders.GoTo:
- StartAct(MoveToDestination(c));
- yield return new WaitUntil(() => AtDestination || !HasOrders || IsBusy);
- break;
- case Orders.Follow:
- StartAct(Follow(c));
- // follow is continuous; bail when priorities change
- yield return new WaitUntil(() => !HasOrders || InCombat || IsBusy);
- break;
- case Orders.Chase:
- StartAct(MoveToTarget(c));
- yield return new WaitUntil(() => c.CanHitTargetTarget || !HasOrders || !IsCurrentTargetValid || IsBusy);
- break;
- }
- }
- ReturnToRoot();
- }
- private IEnumerator DoNonCombat() {
- if (c.data is CivilianData) {
- //wander forever until something higher-priority changes
- yield return RunWhile(() => !IsBusy && !InCombat && !HasOrders, () => WanderDistrict(c));
- } else if (c.data is CrewmanData) {
- yield return RunWhile(() => !IsBusy && !InCombat && !HasOrders, () => WanderWorld(c));
- } else { //leader
- //move to next control point; when done, loop back to root
- //MoveToNearestControlPoint();
- WanderWorld(c);
- yield return RunUntil(() => AtDestination || InCombat || HasOrders || IsBusy);
- }
- ReturnToRoot();
- }
- // ---------------------------------------------------------------------
- // Actions
- // ---------------------------------------------------------------------
- private IEnumerator StopMoving() { c.rb.velocity = Vector2.zero; c.animate.AnimateUpdate(Vector2.zero, 0); yield return null; }
- public IEnumerator Stop(NPCController c) {
- // Hold still while busy OR until velocity truly zero
- while (c.IsBusy || c.rb.velocity.sqrMagnitude > 0.0001f) {
- c.rb.velocity = Vector2.zero;
- c.animate.AnimateUpdate(Vector2.zero, 0f);
- yield return null;
- }
- }
- public IEnumerator TurnOnCollider(NPCController c) {
- if (c.physicsCollider != null) c.physicsCollider.enabled = true;
- yield break;
- }
- public IEnumerator PurgeDeadTargets(NPCController c) {
- c.attackTargets.RemoveWhere(x => x == null || !x || x.IsDead);
- yield break;
- }
- public IEnumerator ValidateTarget(NPCController c) {
- //purge first
- c.attackTargets.RemoveWhere(x => x == null || !x || x.IsDead);
- //select closest (no LINQ)
- CommonController best = null;
- float bestDis = float.MaxValue;
- var pos = (Vector2)c.transform.position;
- foreach (var t in c.attackTargets) {
- if (!t || t.IsDead) continue;
- float dis = ((Vector2)t.transform.position - pos).sqrMagnitude;
- if (dis < bestDis) { bestDis = dis; best = t; }
- }
- c.currentTarget = best;
- yield break;
- }
- public IEnumerator MoveToDestination(NPCController c) {
- //move until we arrive or higher priority interrupts
- while (!c.IsBusy) {
- Vector2 diff = c.destination - (Vector2)c.transform.position;
- if (diff.sqrMagnitude < 0.02f) break;
- Vector2 dir = diff.normalized;
- c.rb.velocity = dir * c.moveSpeed;
- c.animate.AnimateUpdate(dir, c.rb.velocity.magnitude);
- yield return null;
- }
- c.rb.velocity = Vector2.zero;
- c.animate.AnimateUpdate(Vector2.zero, 0f);
- }
Advertisement
Add Comment
Please, Sign In to add comment