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
2 Answers
Reset to default 0CurrentEnemy.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
评论列表(0条)