Reputation: 27
I set up a simple enemy in my unity 2D platformer game but it should move towards the player after a little bit of time but that doesn't happen. I post the code below; the problem is that "transform.position = Vector2.MoveTowards(transform.position, playerPosition, JumpAttackSpeed * Time.deltaTime);" doesn't work and I don't why. I were expecting the enemy to move after he jumps and take the current position of the player but that doesn't happen. That's my code hope it helps.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyScript : MonoBehaviour
{
public Rigidbody2D rb;
public GameObject player;
private Vector3 playerPosition;
public float NormalSpeed;
private float distance;
private bool canAttack = true;
public float AttackRange;
public float JumpAttackRange;
public float JumpForce;
public float JumpAttackPreTime;
public float JumpAttackTime;
public float JumpAttackSpeed;
public float AttackCooldawnTime;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
distance = Vector2.Distance(transform.position, player.transform.position);
if (transform.position != playerPosition && !canAttack)
{
transform.position = Vector2.MoveTowards(transform.position, playerPosition, JumpAttackSpeed * Time.deltaTime);
}
else
{
StartCoroutine(AttackCooldawn());
}
if (distance < AttackRange || canAttack)
{
StartCoroutine(Attack());
}
}
private IEnumerator Attack()
{
if (distance < JumpAttackRange)
{
canAttack = false;
rb.velocity = new Vector2(rb.velocity.x, JumpForce);
yield return new WaitForSeconds(JumpAttackPreTime);
rb.velocity = new Vector2(0, 0);
var normalGravity = rb.gravityScale;
rb.gravityScale = 0;
playerPosition = player.transform.position;
yield return new WaitForSeconds(JumpAttackTime);
rb.gravityScale = 1f;
}
}
private IEnumerator AttackCooldawn()
{
yield return new WaitForSeconds(AttackCooldawnTime);
canAttack = true;
}
}
Upvotes: 2
Views: 144
Reputation: 765
The issue is the way you use coroutines which are asynchronous. When your "AttackCooldawn()" coroutine executes because it is async your "Update()" method it will continue to be executed so when it comes to your last "if statement" most probably your "canAttack" boolean it will be false because your previous coroutine is gonna wait a few seconds before setting the "canAttack" variable to true. You need a better approach for that.
Try to keep truck of the cooldown with a timer like this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyScript : MonoBehaviour
{
public Rigidbody2D rb;
public GameObject player;
private Vector3 playerPosition;
public float NormalSpeed;
private float distance;
private bool canAttack = true;
public float AttackRange;
public float JumpAttackRange;
public float JumpForce;
public float JumpAttackPreTime;
public float JumpAttackTime;
public float JumpAttackSpeed;
public float AttackCooldawnTime;
public float maximumCooldownTime;
private float currentCooldownTimer = 0f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
distance = Vector2.Distance(transform.position, player.transform.position);
if (transform.position != playerPosition)
{
transform.position = Vector2.MoveTowards(transform.position, playerPosition, JumpAttackSpeed * Time.deltaTime);
}
if (distance < AttackRange && currentCooldownTimer > maximumCooldownTime)
{
StartCoroutine(Attack());
}
currentCooldownTimer += Time.deltaTime;
}
private IEnumerator Attack()
{
if (distance < JumpAttackRange)
{
canAttack = false;
rb.velocity = new Vector2(rb.velocity.x, JumpForce);
yield return new WaitForSeconds(JumpAttackPreTime);
rb.velocity = new Vector2(0, 0);
var normalGravity = rb.gravityScale;
rb.gravityScale = 0;
playerPosition = player.transform.position;
yield return new WaitForSeconds(JumpAttackTime);
rb.gravityScale = 1f;
}
currentCooldownTimer = 0f;
}
}
Simple set your maximumCooldownTime
through Unity's editor
Upvotes: 2