Be the first to post for 'Lazy Enemy Bug'!

rpg_s04_lazy_enemy_bug

#1

If you’re reading this, there probably aren’t very many posts yet. But don’t worry, you can be the first! Either create a new post or just reply to this one to say ‘hi’.


#2

The problem with this bug fix is that it is defeating the idea of having a simple state machine, since we don’t use the ‘State’ enum anymore.
A state machine is not really necessary for such a simple behavior script, but now we have already broken something: having a weapon range larger than the chase change (typical for a ranged enemy) won’t work.

To fix that we can re-introduce a basic state machine with a switch statement. This makes a lot of repeated code,
but it is easier to avoid bugs:

//
// In EnemyAI.cs
//
        // State made public for visibility in inspector
        public enum State { idle, patrolling, attacking, chasing }
        public State state = State.idle;

        private void Update()
        {
            if (healthSystem.getIsAlive)
            {
                currentWeaponRange = weaponSystem.getCurrentWeaponConfig.getAttackRange;

                distanceToPlayer = Vector3.Distance(player.transform.position, transform.position);

                bool inWeaponRange = distanceToPlayer <= currentWeaponRange;
                bool inChaseRange = distanceToPlayer > currentWeaponRange && distanceToPlayer <= chaseRadius;
                bool outsideChaseRange = distanceToPlayer > chaseRadius;

                switch (state)
                {
                    case State.idle:
                        {
                            if (inWeaponRange)
                            {
                                StopAllCoroutines();
                                state = State.attacking;
                                weaponSystem.AttackTarget(player.gameObject);
                            }
                            if (outsideChaseRange)
                            {
                                StopAllCoroutines();
                                weaponSystem.StopAttacking();
                                StartCoroutine(Patrol());
                            }
                            if (inChaseRange)
                            {
                                StopAllCoroutines();
                                weaponSystem.StopAttacking();
                                StartCoroutine(ChasePlayer());
                            }
                            break;
                        }
                    case State.attacking:
                        {
                            if (inWeaponRange) { break; }
                            if (outsideChaseRange)
                            {
                                StopAllCoroutines();
                                weaponSystem.StopAttacking();
                                StartCoroutine(Patrol());
                            }
                            if (inChaseRange)
                            {
                                StopAllCoroutines();
                                weaponSystem.StopAttacking();
                                StartCoroutine(ChasePlayer());
                            }
                            break;
                        }
                    case State.patrolling:
                        {
                            if (inWeaponRange)
                            {
                                StopAllCoroutines();
                                state = State.attacking;
                                weaponSystem.AttackTarget(player.gameObject);
                            }
                            if (outsideChaseRange) { break; }
                            if (inChaseRange)
                            {
                                StopAllCoroutines();
                                weaponSystem.StopAttacking();
                                StartCoroutine(ChasePlayer());
                            }
                            break;
                        }
                    case State.chasing:
                        {
                            if (inWeaponRange)
                            {
                                StopAllCoroutines();
                                state = State.attacking;
                                weaponSystem.AttackTarget(player.gameObject);
                            }
                            if (outsideChaseRange)
                            {
                                StopAllCoroutines();
                                weaponSystem.StopAttacking();
                                StartCoroutine(Patrol());
                            }
                            if (inChaseRange) { break; }
                            break;
                        }
                }
            }
        }

And for more complex behaviors, I think I’ll consider using this: