- Home /
How to freeze enemy movement when Hurt/enemy Damage?
Hello. i am a newbie and have a simple question. I have a hurt animation on the enemy that is triggered when the player shoots it. Suppose the enemy is chasing the player and the player shoots it while chasing him, the hurt animation is triggered. However, i would like to freeze the enemy movement(freeze the chase) when the hurt animation is triggered. This might be a simple fix, but i cant seem to get it done.
Here is the code that is responsible for the enemy movement
public class NewEnemyScript : MonoBehaviour
{
//use holster master as the player target
[SerializeField] private Transform playerTarget;
[SerializeField] private float attackRange;
[SerializeField] private float alertRange;
[SerializeField] private float moveSpeed;
[SerializeField] private Animator anim;
void Update()
{
if(Vector3.Distance(playerTarget.position,this.transform.position)<alertRange)
{
Vector3 direction = playerTarget.position - this.transform.position;
direction.y = 0;
this.transform.rotation = Quaternion.Slerp(this.transform.rotation, Quaternion.LookRotation(direction), 0.1f);
anim.SetBool("isIdle", false);
if(direction.magnitude>attackRange)
{
this.transform.Translate(0, 0, moveSpeed);
anim.SetBool("isRunning", true);
anim.SetBool("isAttack", false);
}
else
{
anim.SetBool("isAttack", true);
anim.SetBool("isRunning", false);
}
}
else
{
anim.SetBool("isIdle", true);
anim.SetBool("isAttack", false);
anim.SetBool("isRunning", false);
}
}
i have an other script named health that is attached to the enemy and the hurt animation is triggered here when the bullet is collided with the enemy along with a deduction in health
public class NewHealth : MonoBehaviour
{
[SerializeField] private float enemyHealth = 100f;
[SerializeField] private Animator animator;
private bool isDead = false;
[SerializeField] private float deductHealth = 10f;
void Update()
{
if (!isDead)
{
if (enemyHealth <= 0)
{
enemyDead();
}
}
}
public void DeductHealth()
{
if (!isDead)
{
enemyHealth -= deductHealth;
animator.SetTrigger("Hurt");
}
}
void enemyDead()
{
Destroy(gameObject, 5);
animator.SetBool("isDead", true);
isDead = true;
}
private void OnTriggerEnter(Collider other)
{
if(other.gameObject.tag=="Bullet")
{
DeductHealth();
Destroy(other.gameObject);
Debug.Log("Hurt");
}
}
Here is the animator window
any help would be greatly appreciated. Thank you for your time.
Answer by b1gry4n · Jul 14, 2021 at 06:20 PM
It looks like youre using root motion and mecanim to drive the zombies movement? Depending on what your hurt animation is actually animating is determining the zombies movement speed. if you want the zombie to pause longer in the hurt state your animation should actually include that pause.
if youre trying to get the zombie to pause after every hurt but dont have the means to modify/add a new hurt animation you could insert a new animation to follow up the hurt animation and then transition from that new animation to the other states. you could try putting another "Zombie Idle" animation into your mecanim state machine and name it something like "pause". have "Hurt1" transition only to that state then reconnect the new "pause" state to zombie idle. The transition from pause -> idle should have "Has Exit Time" checked and you would set the "Exit Time" setting to however long you want that pause to play.
https://i.imgur.com/DV6GOCW.png
If this is not what you meant and I misunderstood then maybe youre looking to stop the zombie from rotating? In order to do this you need to know when the zombie is actually hurt. I added some things to your code and commented my additions, maybe it will help.
NewEnemyScript:
public class NewEnemyScript : MonoBehaviour
{
//use holster master as the player target
[SerializeField] private Transform playerTarget;
[SerializeField] private float attackRange;
[SerializeField] private float alertRange;
[SerializeField] private float moveSpeed;
[SerializeField] private Animator anim;
//need a reference to the health script to determine if the zombie is dead or hurt
[SerializeField] private NewHealth health;
void Update()
{
//if we are hurt or dead just return and dont run the code below
if (health.IsHurt || health.IsDead) { return; }
if (Vector3.Distance(playerTarget.position, this.transform.position) < alertRange)
{
Vector3 direction = playerTarget.position - this.transform.position;
direction.y = 0;
this.transform.rotation = Quaternion.Slerp(this.transform.rotation, Quaternion.LookRotation(direction), 0.1f);
anim.SetBool("isIdle", false);
if (direction.magnitude > attackRange)
{
this.transform.Translate(0, 0, moveSpeed);
anim.SetBool("isRunning", true);
anim.SetBool("isAttack", false);
}
else
{
anim.SetBool("isAttack", true);
anim.SetBool("isRunning", false);
}
}
else
{
anim.SetBool("isIdle", true);
anim.SetBool("isAttack", false);
anim.SetBool("isRunning", false);
}
}
}
NewHealth:
public class NewHealth : MonoBehaviour
{
[SerializeField] private float enemyHealth = 100f;
[SerializeField] private Animator animator;
[SerializeField] private float deductHealth = 10f;
//the time that the zombie will pause after being hurt (will not rotate during this time)
[SerializeField] private float hurtPauseTime = 1f;
private bool _isHurt = false;
private bool _isDead = false;
//cached reference to the coroutine so we can start/stop it whenever we want
Coroutine hurtRoutine;
//public bool used by "newenemyscript" to determine if we are dead
public bool IsDead
{
get
{
return _isDead;
}
}
//public bool used by "newenemyscript" to determine if we are hurt
public bool IsHurt
{
get
{
return _isHurt;
}
}
void Update()
{
if (!_isDead)
{
if (enemyHealth <= 0)
{
enemyDead();
}
}
}
public void DeductHealth()
{
if (!_isDead)
{
enemyHealth -= deductHealth;
animator.SetTrigger("Hurt");
//if we are already hurt lets stop the coroutine so that multiple coroutines arent running
if (_isHurt)
{
StopCoroutine(hurtRoutine);
}
//start the coroutine and store a reference to it so that we can stop it whenever we want
hurtRoutine = StartCoroutine(HurtWait(hurtPauseTime));
}
}
void enemyDead()
{
Destroy(gameObject, 5);
animator.SetBool("isDead", true);
_isDead = true;
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Bullet")
{
DeductHealth();
Destroy(other.gameObject);
Debug.Log("Hurt");
}
}
//enable isHurt, pause for "waitTime" in seconds, disable isHurt
IEnumerator HurtWait(float waitTime)
{
_isHurt = true;
yield return new WaitForSeconds(waitTime);
_isHurt = false;
}
}