admin管理员组

文章数量:1410737

so the main problem is that the Patrol() method is not getting called, its my fist time working with inheritance and I suppose theres something wrong with how Currentstate gets set. My idea was that I write the method in the base class, check the CurrentState in its update method and then just set CurrentState in my enemy - child - scripts but it doesnt seem to work. Can somebody help?

using Assets.Code.Enemy.Enemies;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices.WindowsRuntime;
using Unity.VisualScripting;
using UnityEngine;

public class EnemyBase : MonoBehaviour
{
    [Header("Base values")]
    private int _health = 0;

    private int _damage = 0;

    private int _speed = 0;

    private EnemyState _currentState;

    [Header("Movement elements")]

    protected bool playerInRange = false;

    [SerializeField] protected CapsuleCollider2D SpotRange; // the range the enemy will be able to see the player 

    [SerializeField] protected Transform PlayerTransform;

    [SerializeField] protected Transform EnemyFirstPosition, EnemySecondPosition;

    protected GameObject CurrentEnemy;

    virtual protected int Speed
    {
        get => _speed;
        set => _speed = value;
    }

    virtual protected EnemyState CurrentState
    {
        get => _currentState;
        set => _currentState = value;
    }

    virtual protected int Health
    {
        get => _health;
        set => _health = value;
    }

    virtual protected int Damage
    {
        get => _damage;
        set => _damage = value;
    }

    // Update is called once per frame
    void Update()
    {
        switch (CurrentState)
        {
            case EnemyState.Patrol:
                StartCoroutine(Patrol());
                break;

            case EnemyState.Chase:
                MoveTowardsPlayer();
                break;

            case EnemyState.Attack:
                Attack();
                break;

        }
    }


    public virtual void TakeDamage(int damageTotake)
    {
        Health -= damageTotake;
    }

    protected virtual void MoveTowardsPlayer()
    {

    }

    protected virtual void Attack() { } //Empty, will be set in each enemy class individually

    protected virtual IEnumerator Patrol()
    {
        Transform nextTargetPoint = EnemyFirstPosition;

        while (true)
        {
            if (nextTargetPoint != null)
            {
                Debug.Log("move enemy");
                CurrentEnemy.transform.position = Vector2.MoveTowards(
                    CurrentEnemy.transform.position,
                    nextTargetPoint.transform.position,
                    Speed * Time.deltaTime
                );

                if ((CurrentEnemy.transform.position - nextTargetPoint.transform.position).magnitude < 0.1f) //check if the distance between the enemy and the first target point is low, same as Vector.Distance()
                {
                    yield return new WaitForSeconds(1);

                    nextTargetPoint = (nextTargetPoint == EnemyFirstPosition) ? EnemySecondPosition : EnemyFirstPosition;
                }
            }
            else if (nextTargetPoint == null)
            {
                nextTargetPoint = EnemyFirstPosition.transform;
            }
        }
    }

    protected virtual void Rest()
    {

    }

    protected virtual void Die()
    {
        Destroy(this.gameObject);

    }
    protected virtual void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.CompareTag("Player"))
        {
            playerInRange = true;
        }
    }

    protected virtual void OnTriggerExit2D(Collider2D collision)
    {
        if (collision.CompareTag("Player"))
        {
            playerInRange = false;
        }
    }
}
using Assets.Code.Enemy.Enemies;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LunaticCultistBase : EnemyBase
{
    private Animator _enemyAnimator;
    private Rigidbody2D _enemyRigidbody;
    private SpriteRenderer _enemySpriteRenderer;
    

    // Start is called before the first frame update
    void Start()
    {
        _enemyAnimator = GetComponent<Animator>();
        _enemyRigidbody = GetComponent<Rigidbody2D>();
        _enemySpriteRenderer = GetComponent<SpriteRenderer>();

        base.Health = 20;
        base.Damage = 10;
        base.Speed = 10;
        base.CurrentEnemy = this.gameObject;

        base.CurrentState = EnemyState.Patrol;

        CurrentEnemy = this.gameObject;


    }

    // Update is called once per frame
    void Update()
    {
        if (base.Health <= 0)
            Die();

        if (playerInRange)
        {

            if (PlayerTransform.position.x < this.gameObject.transform.position.x)
            {
                _enemySpriteRenderer.flipX = true;
            }
            else
            {
                _enemySpriteRenderer.flipX = false;
            }
        }
    }

    //hit and damage logic
    public override void TakeDamage(int damageTotake)
    {
        _enemyRigidbody.bodyType = RigidbodyType2D.Static;
        base.TakeDamage(damageTotake);
        Invoke("SetAnimationAndBodyType", 0.1f);
    }


    private void SetAnimationAndBodyType()
    {
        _enemyAnimator.SetTrigger("Hit");
        _enemyRigidbody.bodyType = RigidbodyType2D.Dynamic;

    }

    //death logic
    protected override void Die()
    {
        _enemyAnimator.SetTrigger("Death");
        Invoke("InvokeDie", 1f);
    }

    private void InvokeDie()
    {
        base.Die();
    }   
}
public enum EnemyState
{
    Patrol,
    Chase,
    Attack
}

so the main problem is that the Patrol() method is not getting called, its my fist time working with inheritance and I suppose theres something wrong with how Currentstate gets set. My idea was that I write the method in the base class, check the CurrentState in its update method and then just set CurrentState in my enemy - child - scripts but it doesnt seem to work. Can somebody help?

using Assets.Code.Enemy.Enemies;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices.WindowsRuntime;
using Unity.VisualScripting;
using UnityEngine;

public class EnemyBase : MonoBehaviour
{
    [Header("Base values")]
    private int _health = 0;

    private int _damage = 0;

    private int _speed = 0;

    private EnemyState _currentState;

    [Header("Movement elements")]

    protected bool playerInRange = false;

    [SerializeField] protected CapsuleCollider2D SpotRange; // the range the enemy will be able to see the player 

    [SerializeField] protected Transform PlayerTransform;

    [SerializeField] protected Transform EnemyFirstPosition, EnemySecondPosition;

    protected GameObject CurrentEnemy;

    virtual protected int Speed
    {
        get => _speed;
        set => _speed = value;
    }

    virtual protected EnemyState CurrentState
    {
        get => _currentState;
        set => _currentState = value;
    }

    virtual protected int Health
    {
        get => _health;
        set => _health = value;
    }

    virtual protected int Damage
    {
        get => _damage;
        set => _damage = value;
    }

    // Update is called once per frame
    void Update()
    {
        switch (CurrentState)
        {
            case EnemyState.Patrol:
                StartCoroutine(Patrol());
                break;

            case EnemyState.Chase:
                MoveTowardsPlayer();
                break;

            case EnemyState.Attack:
                Attack();
                break;

        }
    }


    public virtual void TakeDamage(int damageTotake)
    {
        Health -= damageTotake;
    }

    protected virtual void MoveTowardsPlayer()
    {

    }

    protected virtual void Attack() { } //Empty, will be set in each enemy class individually

    protected virtual IEnumerator Patrol()
    {
        Transform nextTargetPoint = EnemyFirstPosition;

        while (true)
        {
            if (nextTargetPoint != null)
            {
                Debug.Log("move enemy");
                CurrentEnemy.transform.position = Vector2.MoveTowards(
                    CurrentEnemy.transform.position,
                    nextTargetPoint.transform.position,
                    Speed * Time.deltaTime
                );

                if ((CurrentEnemy.transform.position - nextTargetPoint.transform.position).magnitude < 0.1f) //check if the distance between the enemy and the first target point is low, same as Vector.Distance()
                {
                    yield return new WaitForSeconds(1);

                    nextTargetPoint = (nextTargetPoint == EnemyFirstPosition) ? EnemySecondPosition : EnemyFirstPosition;
                }
            }
            else if (nextTargetPoint == null)
            {
                nextTargetPoint = EnemyFirstPosition.transform;
            }
        }
    }

    protected virtual void Rest()
    {

    }

    protected virtual void Die()
    {
        Destroy(this.gameObject);

    }
    protected virtual void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.CompareTag("Player"))
        {
            playerInRange = true;
        }
    }

    protected virtual void OnTriggerExit2D(Collider2D collision)
    {
        if (collision.CompareTag("Player"))
        {
            playerInRange = false;
        }
    }
}
using Assets.Code.Enemy.Enemies;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LunaticCultistBase : EnemyBase
{
    private Animator _enemyAnimator;
    private Rigidbody2D _enemyRigidbody;
    private SpriteRenderer _enemySpriteRenderer;
    

    // Start is called before the first frame update
    void Start()
    {
        _enemyAnimator = GetComponent<Animator>();
        _enemyRigidbody = GetComponent<Rigidbody2D>();
        _enemySpriteRenderer = GetComponent<SpriteRenderer>();

        base.Health = 20;
        base.Damage = 10;
        base.Speed = 10;
        base.CurrentEnemy = this.gameObject;

        base.CurrentState = EnemyState.Patrol;

        CurrentEnemy = this.gameObject;


    }

    // Update is called once per frame
    void Update()
    {
        if (base.Health <= 0)
            Die();

        if (playerInRange)
        {

            if (PlayerTransform.position.x < this.gameObject.transform.position.x)
            {
                _enemySpriteRenderer.flipX = true;
            }
            else
            {
                _enemySpriteRenderer.flipX = false;
            }
        }
    }

    //hit and damage logic
    public override void TakeDamage(int damageTotake)
    {
        _enemyRigidbody.bodyType = RigidbodyType2D.Static;
        base.TakeDamage(damageTotake);
        Invoke("SetAnimationAndBodyType", 0.1f);
    }


    private void SetAnimationAndBodyType()
    {
        _enemyAnimator.SetTrigger("Hit");
        _enemyRigidbody.bodyType = RigidbodyType2D.Dynamic;

    }

    //death logic
    protected override void Die()
    {
        _enemyAnimator.SetTrigger("Death");
        Invoke("InvokeDie", 1f);
    }

    private void InvokeDie()
    {
        base.Die();
    }   
}
public enum EnemyState
{
    Patrol,
    Chase,
    Attack
}
Share Improve this question edited Mar 10 at 19:30 derHugo 91.3k9 gold badges91 silver badges135 bronze badges asked Mar 8 at 19:13 JULUXX JULUXJULUXX JULUX 1
Add a comment  | 

1 Answer 1

Reset to default 0

Your subtype LunaticCultistBase is hiding Update meaning it has it's own implementation and the Update of EnemyBase might not get called! That's because these Unity built-in event message methods are invoked by Unity's event loop system and not like "normal" methods. And that event system is probably going by the most specific type.

So to be sure you should rather make those Unity methods always protected virtual in base types so you can then safely overwrite/extend them in subtypes!

本文标签: cUnity 2d enemy patrolling not working properlyStack Overflow