c# - Unity 2d Enemy patrol - Stack Overflow

So, basically I want the enemy to be moving dynamical between the targetpoints, right now the enemy is

So, basically I want the enemy to be moving dynamical between the targetpoints, right now the enemy is like teleporting between them. I already tried multiple other methods because I thought that this is the problem, well its not. I put the logic for this in a base class and the method is getting called correctly so I will leave that part out of here.Somebody can help? Thanks :>

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

   private int _damage = 0;

   private float _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 float Speed
   {
       get => _speed;
       set => _speed = value;
   }

   private bool _isPatrolling;

   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
   protected virtual void Update()
   {
       switch (CurrentState)
       {
           case EnemyState.Patrol:
               if (_isPatrolling)
               {
                   return;
               }
               else
               {
                   _isPatrolling = true;
                   StartCoroutine(Patrol());

               }
               break;

           case EnemyState.Chase:
               MoveTowardsPlayer();
               break;

           case EnemyState.Attack:
               Attack();
               break;

       }

       if (CurrentState != EnemyState.Patrol)
           _isPatrolling = false;

   }


   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.Lerp(
                   CurrentEnemy.transform.position,
                   nextTargetPoint.transform.position,
                     Speed

               ); 

               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;
           }
       }
   } ```

So, basically I want the enemy to be moving dynamical between the targetpoints, right now the enemy is like teleporting between them. I already tried multiple other methods because I thought that this is the problem, well its not. I put the logic for this in a base class and the method is getting called correctly so I will leave that part out of here.Somebody can help? Thanks :>

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

   private int _damage = 0;

   private float _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 float Speed
   {
       get => _speed;
       set => _speed = value;
   }

   private bool _isPatrolling;

   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
   protected virtual void Update()
   {
       switch (CurrentState)
       {
           case EnemyState.Patrol:
               if (_isPatrolling)
               {
                   return;
               }
               else
               {
                   _isPatrolling = true;
                   StartCoroutine(Patrol());

               }
               break;

           case EnemyState.Chase:
               MoveTowardsPlayer();
               break;

           case EnemyState.Attack:
               Attack();
               break;

       }

       if (CurrentState != EnemyState.Patrol)
           _isPatrolling = false;

   }


   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.Lerp(
                   CurrentEnemy.transform.position,
                   nextTargetPoint.transform.position,
                     Speed

               ); 

               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;
           }
       }
   } ```
Share Improve this question asked Mar 23 at 8:43 JULUXX JULUXJULUXX JULUX 1 2
  • like i said, ive already done that and it gave me the same result as with Lerp() – JULUXX JULUX Commented Mar 23 at 16:05
  • You only said "I already tried multiple other methods", how am I suppose to know what multiple other methods are? – shingo Commented Mar 24 at 4:52
Add a comment  | 

2 Answers 2

Reset to default 0
CurrentEnemy.transform.position = Vector2.Lerp(
                   CurrentEnemy.transform.position,
                   nextTargetPoint.transform.position,
                     Speed

               )

Lerp's third parameter is a normalized time value, if it's >= 1, it will arrive at the target point. You normally pass a time value in here, for example: timeToArrival = distance / speed, so you will calculate this time to arrival at the beginning of the code that assign the target point, then the value to pass in Lerp will be timePassed / timeToArrival, with the timePassed increased by Time.deltaTime per frame.

You can either do that or switch to use Update() entirely, ditch the Coroutine and use Vector2.MoveTowards instead.

using while (true) is dangerous, if somehow your coroutine does not run a yield return ..., the game will crash due to infinite loop. And mixing Coroutine with Update() bring a lot of headache, it's better to use only Update() here for the core logic of your enemy.

Try this:

protected virtual void Update()
    {
        switch (CurrentState)
        {
            case EnemyState.Patrol:
                Patrol();
                break;

            case EnemyState.Chase:
                MoveTowardsPlayer();
                break;

            case EnemyState.Attack:
                Attack();
                break;
        }
    }

protected virtual void Patrol()
    {
        if (_nextTargetPoint == null) return;

        CurrentEnemy.transform.position = Vector2.MoveTowards(
            CurrentEnemy.transform.position,
            _nextTargetPoint.position,
            Speed * Time.deltaTime
        );

        if (Vector2.Distance(CurrentEnemy.transform.position, _nextTargetPoint.position) < 0.1f)
        {
            _nextTargetPoint = (_nextTargetPoint == EnemyFirstPosition) ? EnemySecondPosition : EnemyFirstPosition;
        }
    }

The reason your enemy is teleporting or not moving smoothly is due to this line inside your Patrol() coroutine:

CurrentEnemy.transform.position = Vector2.Lerp(
    CurrentEnemy.transform.position,
    nextTargetPoint.transform.position,
    Speed
);

The issue is with how you're using Lerp. The third parameter (Speed) is not time-based, so it's likely causing the enemy to jump/teleport or barely move.

I recommend that you use Time.deltaTime to make movement frame-based.

Please refer to the updated Patrol() method:

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

    while (true)
    {
        while ((CurrentEnemy.transform.position - nextTargetPoint.position).magnitude > 0.1f)
        {
            CurrentEnemy.transform.position = Vector2.MoveTowards(
                CurrentEnemy.transform.position,
                nextTargetPoint.position,
                Speed * Time.deltaTime
            );
            yield return null;
        }

        // Wait a second before switching to the next patrol point
        yield return new WaitForSeconds(1f);
        nextTargetPoint = (nextTargetPoint == EnemyFirstPosition) ? EnemySecondPosition : EnemyFirstPosition;
    }
}

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744292837a4567115.html

相关推荐

  • c# - Unity 2d Enemy patrol - Stack Overflow

    So, basically I want the enemy to be moving dynamical between the targetpoints, right now the enemy is

    7天前
    70

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信