最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - Unity 2d enemy patrolling not working properly - Stack Overflow

programmeradmin1浏览0评论

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!

发布评论

评论列表(0)

  1. 暂无评论