Forum begins after the advertisement:


[Part 6] Charger is rapidly turning left/right and not chasing Player

Home Forums Video Game Tutorial Series Creating a Metroidvania in Unity [Part 6] Charger is rapidly turning left/right and not chasing Player

Viewing 5 posts - 1 through 5 (of 5 total)
  • Author
    Posts
  • #15062
    Wan Laeta
    Participant

    My charger is rapidly turning left/right and don’t move when not found Player.
    The charger still can detect Player but it doesn’t do anything except turn around and detect again.

    View post on imgur.com

    Here is my script:

    The Charger.cs:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class Charger : Enemy
    {
        [SerializeField] private float ledgeCheckX;
        [SerializeField] private float ledgeCheckY;
        [SerializeField] private float chargeSpeedMultiplier;
        [SerializeField] private float chargeDuration;
        [SerializeField] private float jumpForce;
        [SerializeField] private LayerMask whatIsGround;
    
        private Vector3 ledgeCheckStart;
        private Vector2 wallCheckDir;
    
        private void OnDrawGizmos()
        {
            Gizmos.color = Color.red;
            Gizmos.DrawRay(transform.position + ledgeCheckStart, wallCheckDir * (ledgeCheckX * 10));
        }
    
        float timer;
    
        protected override void Start()
        {
            base.Start();
            ChangeState(EnemyStates.Charger_Idle);
            rb.gravityScale = 12f;
        }
    
        protected override void UpdateEnemyStates()
        {
            if (health <= 0)
            {
                Death(0.05f);
            }
    
            Vector3 _ledgeCheckStart = transform.localScale.x > 0 ? new Vector3(ledgeCheckX, 0) : new Vector3(-ledgeCheckX, 0);
            Vector2 _wallCheckDir = transform.localScale.x > 0 ? transform.right : -transform.right;
    
            ledgeCheckStart = _ledgeCheckStart;
            wallCheckDir = _wallCheckDir;
    
            switch (GetCurrentEnemyState)
            {
                case EnemyStates.Charger_Idle:
    
                    if (!Physics2D.Raycast(transform.position + _ledgeCheckStart, Vector2.down, ledgeCheckY, whatIsGround) || Physics2D.Raycast(transform.position, _wallCheckDir, ledgeCheckX, whatIsGround))
                    {
                        print("Turn Around");
                        transform.localScale = new Vector2(transform.localScale.x * -1, transform.localScale.y);
                    }
    
                    RaycastHit2D _hit = Physics2D.Raycast(transform.position + _ledgeCheckStart, _wallCheckDir, ledgeCheckX * 10);
                    if (_hit.collider != null && _hit.collider.gameObject.CompareTag("Player"))
                    {
                        print("Found Player");
                        ChangeState(EnemyStates.Charger_Surprised);
                    }
    
                    if (transform.localScale.x > 0)
                    {
                        rb.velocity = new Vector2(speed, rb.velocity.y);
                    }
                    else
                    {
                        rb.velocity = new Vector2(-speed, rb.velocity.y);
                    }
                    break;
    
                case EnemyStates.Charger_Surprised:
                    rb.velocity = new Vector2(0, jumpForce);
                    ChangeState(EnemyStates.Charger_Charge);
                    break;
    
                case EnemyStates.Charger_Charge:
                    timer += Time.deltaTime;
                    if (timer < chargeDuration)
                    {
                        if (Physics2D.Raycast(transform.position, Vector2.down, ledgeCheckY, whatIsGround))
                        {
                            if (transform.localScale.x > 0)
                            {
                                rb.velocity = new Vector2(speed * chargeSpeedMultiplier, rb.velocity.y);
                            }
                            else
                            {
                                rb.velocity = new Vector2(-speed * chargeSpeedMultiplier, rb.velocity.y);
                            }
                        }
                        else
                        {
                            rb.velocity = new Vector2(0, rb.velocity.y);
                        }
                    }
                    else
                    {
                        timer = 0;
                        ChangeState(EnemyStates.Charger_Idle);
                    }
                    break;
            }
        }
    
        protected override void ChangeCurrentAnimation()
        {
            if (GetCurrentEnemyState == EnemyStates.Charger_Idle)
            {
                anim.speed = 1;
            }
    
            if (GetCurrentEnemyState == EnemyStates.Charger_Charge)
            {
                anim.speed = chargeSpeedMultiplier;
            }
        }
    }

    The Enemy.cs:

    using System.Collections;
    using System.Collections.Generic;
    using Unity.VisualScripting;
    using UnityEngine;
    
    public class Enemy : MonoBehaviour
    {
        [SerializeField] protected float health;
        [SerializeField] protected float recoilLength;
        [SerializeField] protected float recoilFactor;
        [SerializeField] protected bool isRecoiling = false;
    
        // [SerializeField] protected PlayerController player;
        [SerializeField] protected float speed;
    
        [SerializeField] protected float damage;
        [SerializeField] protected GameObject monsterBlood;
    
        protected float recoilTimer;
        protected Rigidbody2D rb;
        protected SpriteRenderer sr;
        protected Animator anim;
    
        protected enum EnemyStates
        {
            // Crawler
            Crawler_Idle,
            Crawler_Flip,
    
            // Bat
            Bat_Idle,
            Bat_Chase,
            Bat_Stunned,
            Bat_Death,
    
            // Charger
            Charger_Idle,
            Charger_Surprised,
            Charger_Charge,
        }
    
        protected EnemyStates currentEnemyState;
    
        protected virtual EnemyStates GetCurrentEnemyState
        {
            get { return currentEnemyState; }
            set
            {
                if (currentEnemyState != value)
                {
                    currentEnemyState = value;
    
                    ChangeCurrentAnimation();
                }
            }
        }
    
        // Start is called before the first frame update
        protected virtual void Start()
        {
            rb = GetComponent<Rigidbody2D>();
            sr = GetComponent<SpriteRenderer>();
            anim = GetComponent<Animator>();
        }
    
        // Update is called once per frame
        protected virtual void Update()
        {
            if (isRecoiling)
            {
                if (recoilTimer < recoilLength)
                {
                    recoilTimer += Time.deltaTime;
                }
                else
                {
                    isRecoiling = false;
                    recoilTimer = 0;
                }
            }
            else
            {
                UpdateEnemyStates();
            }
        }
    
        public virtual void EnemyGetsHit(float _damageDone, Vector2 _hitDirection, float _hitForce)
        {
            health -= _damageDone;
            if (!isRecoiling)
            {
                GameObject _monsterBlood = Instantiate(monsterBlood, transform.position, Quaternion.identity);
                Destroy(_monsterBlood, 5.5f);
                rb.velocity = _hitForce * recoilFactor * _hitDirection;
            }
            Debug.Log("Hit!");
        }
    
        protected void OnCollisionStay2D(Collision2D _other)
        {
            if (_other.gameObject.CompareTag("Player") && !PlayerController.Instance.pState.invincible && health > 0)
            {
                Attack();
                PlayerController.Instance.HitStopTime(0, 5, 0.5f);
            }
        }
    
        protected virtual void Death(float _destroyTime)
        {
            Destroy(gameObject, _destroyTime);
        }
    
        protected virtual void UpdateEnemyStates() { }
    
        protected virtual void ChangeCurrentAnimation() { }
    
        protected void ChangeState(EnemyStates _newState)
        {
            GetCurrentEnemyState = _newState;
        }
    
        protected virtual void Attack()
        {
            PlayerController.Instance.TakeDamage(damage);
        }
    }
    #15064
    Terence
    Keymaster

    My guess is that the enemy’s state is getting changed in a way that is not intended. Can you add the following line to your ChangeState() function, then show me your console output?

    protected void ChangeState(EnemyStates _newState)
    {
        Debug.Log(name + " changed state to " + _newState.ToString());
        GetCurrentEnemyState = _newState;
    }
    #15065
    Wan Laeta
    Participant

    I did as you said.

    View post on imgur.com

    #15067
    Joseph Tang
    Moderator

    So from the videos, we can determine that the Charger’s mechanics all work, it only seems that the Idle state’s function is being triggered multiple times.

    We can tell this by the fact that no other state in the Charger should have it change it’s direction than Idle, and from the first video with all the “Turn Around” logs.

    So, knowing that, either the if parameters are wrong and triggering it multiple times, or the raycast of the Charger is too big, triggering the state’s function without needing to be so close to the edge. I suggest you try the charger again, with a wider platform and maybe increase it’s height too, and see how it goes, before changing it’s Ledge Check values.

    #15068
    Wan Laeta
    Participant

    I tried changing the platform as you said but it doesn’t seem to work.

    But hey, it worked when I changed ledgeCheckY from 1 to 1.2!

    Thanks for your support!!

Viewing 5 posts - 1 through 5 (of 5 total)
  • You must be logged in to reply to this topic.

Go to Login Page →


Advertisement below: