- Home /
One enemy triggers all the enemies
When player get close to an enemy and the enemy starts attacking the player, all the enemies throughout the map start their attacking animation. Player's health get deducted and go to negatives. Player never dies but keeps getting hit by enemies that are not even close to him. Here are the two scripts used on enemies.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ZombieFollow : MonoBehaviour {
public GameObject player;
public float targetDistance;
public float allowedRange = 10;
public GameObject enemy;
public float enemySpeed;
public static int attackTrigger;
public RaycastHit shot;
public int isAttacking;
public GameObject screenFlash;
public AudioSource hurt01;
public AudioSource hurt02;
public AudioSource hurt03;
public int painSound;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void FixedUpdate () {
transform.LookAt (player.transform);
if (Physics.Raycast (transform.position, transform.TransformDirection (Vector3.forward), out shot)) {
targetDistance = shot.distance;
if (targetDistance < allowedRange) {
enemySpeed = 0.6f;
if (attackTrigger == 0) {
enemy.GetComponent<Animation> ().Play ("Walking");
GetComponent<Rigidbody>().AddForce(transform.forward * enemySpeed * Time.deltaTime);
}
} else {
enemySpeed = 0;
enemy.GetComponent<Animation> ().Play ("Idle");
}
}
if (attackTrigger == 1) {
if (isAttacking == 0) {
StartCoroutine(EnemyDamage());
}
enemySpeed = 0;
enemy.GetComponent<Animation>().Play("Attacking");
}
}
void OnTriggerEnter() {
attackTrigger = 1;
}
void OnTriggerExit() {
attackTrigger = 0;
}
IEnumerator EnemyDamage() {
isAttacking = 1;
painSound = Random.Range (1, 4);
yield return new WaitForSeconds (0.9f);
screenFlash.SetActive (true);
GlobalHealth.playerHealth -= 10;
if (painSound == 1) {
hurt01.Play ();
}
if (painSound == 2) {
hurt02.Play ();
}
if (painSound == 3) {
hurt03.Play ();
}
yield return new WaitForSeconds (0.05f);
screenFlash.SetActive (false);
yield return new WaitForSeconds (1);
isAttacking = 0;
}
}
Second one which is responsible for enemy death
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyScript : MonoBehaviour {
public int enemyHealth = 10;
public GameObject zombie;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (enemyHealth <= 0) {
this.GetComponent<ZombieFollow>().enabled = false;
zombie.GetComponent<Animation>().Play("Dying");
StartCoroutine(EndZombie());
}
}
void DeductPoints(int damageAmount) {
enemyHealth -= damageAmount;
}
IEnumerator EndZombie() {
yield return new WaitForSeconds(3);
Destroy(gameObject);
}
}
Have you tried moving this part:
if (attackTrigger == 1) { if (isAttacking == 0) { StartCoroutine(EnemyDamage()); } enemySpeed = 0; enemy.GetComponent().Play("Attacking"); }
Into the raycast?
Answer by Iarus · Nov 04, 2018 at 06:15 PM
I have no idea how Physics.Raycast () and transform.TransformDirection() really work, but I was not expecting to see Vector3.foward, but maybe transform.foward instead. Again, I don't know how it works, just look at the documentation.
Also make sure the targetDistance has a value that makes sense for each enemy. Debug.Log(gameobject.Name +" "+ targetDistance), pause the game and calculate the distance yourself. Maybe you are not calculating the right distance...
Look at Nocktion suggestion.
I noticed that attackTrigger is static. This means that ALL object instances of the ZombieFollow class wil share the same value. This is a big part of the bug.
Irrelevant to the current problem, but please don't use GetComponent inside update , it'll work, but it'll kill your performance. Do that in Start() and store the components in member variables.
Variable being static was a mistake. I fixed it but it didn't fix the issue. As you said, I checked if the distances are making sense for each enemy. They weren't. Therefore, I changed the zombiefollow script to the following. Now distances of each zombie make sense. However, problem is still there. Even though you are not even near an enemy, you keep getting hit and die eventually. I observed that, right when the game starts, all the enemies throughout the map, starts sliding towards the player. Even the enemies that are so far away. They are not walking.. Just sliding towards the player with "Idle" animation.
public class ZombieFollow : $$anonymous$$onoBehaviour {
public GameObject player;
public float targetDistance;
public float allowedRange = 10f;
public GameObject enemy;
public float enemySpeed;
public int attackTrigger;
public RaycastHit shot;
public int isAttacking;
public GameObject screenFlash;
public AudioSource hurt01;
public AudioSource hurt02;
public AudioSource hurt03;
public int painSound;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void FixedUpdate () {
transform.LookAt (player.transform);
targetDistance = Vector3.Distance(enemy.transform.position, player.transform.position);
if (targetDistance < allowedRange) {
enemySpeed = 0.6f;
if (attackTrigger == 0) {
enemy.GetComponent<Animation> ().Play ("Walking");
GetComponent<Rigidbody>().AddForce(transform.forward * enemySpeed * Time.deltaTime);
}
} else {
enemySpeed = 0;
enemy.GetComponent<Animation> ().Play ("Idle");
}
if (attackTrigger == 1) {
if (isAttacking == 0) {
StartCoroutine(EnemyDamage());
}
enemySpeed = 0;
enemy.GetComponent<Animation>().Play("Attacking");
}
}
void OnTriggerEnter() {
attackTrigger = 1;
}
void OnTriggerExit() {
attackTrigger = 0;
}
IEnumerator EnemyDamage() {
isAttacking = 1;
painSound = Random.Range (1, 4);
yield return new WaitForSeconds (0.9f);
screenFlash.SetActive (true);
GlobalHealth.playerHealth -= 10;
if (painSound == 1) {
hurt01.Play ();
}
if (painSound == 2) {
hurt02.Play ();
}
if (painSound == 3) {
hurt03.Play ();
}
yield return new WaitForSeconds (0.05f);
screenFlash.SetActive (false);
yield return new WaitForSeconds (1);
isAttacking = 0;
}
}
When zombies are sliding toward the player playing the idle animation. Are they really playing the whole animation or are always stuck at the first frame ? I'm not sure how the animation work, does animation.Play("Idle") every frame reset the animation, or are subsequent call with the same animation name ignored so it can play normally?
Initially I thought that you were starting the coroutine every frames, but you are guarding it with isAttacking...
I did not know that OnTriggerEnter and OnTriggerExit could exist without any parameters, but you can also create them with a parameter of type Collider. Check the documentation. That parameter is the other object that touched the zombie. Validate what it is before you go into attack mode. You can check if it has the "player" tag or the player controller component. I think your zombies are overly sensitive and are being triggered by the ground or some other objects.
I would suggest that you delete or deactivate all zombies except one, make sure it works correctly with just one, test with 2, then add the others
Validating the player tag in both OnTriggerEnter and OnTriggerExit actually fixed the issue where player got hit from out of nowhere.. However, still that sliding thing happens. Whole Idle animation plays repeatedly while this sliding happens. For example, if I'm beyond the range that an enemy can detect me, it will slowly slide (with the idle animation) towards me until it get into the range and then start walking towards me.
Answer by engfkaplan · Nov 11, 2018 at 01:34 PM
All enemies start attack because you use static variable.
public static int attackTrigger;
static variables store same value for all object. So when you set attackTrigger = 1 for one object , other objects script's attackTrigger field change
Right now it is that, player get hits out of nowhere, even though no enemy is near him.. Far away enemies don't do attack animations cos I changed the variable you mentioned to just public int..