- Home /
30 Objects all firing at exactly the same time and not randomly
I have 30 objects/enemies in my scene and they all fire at exactly the same time.
So I added a random delay into the firing script, hoping to make them fire at different times but they still 'all' fire at exactly the same time.
using UnityEngine;
using System.Collections;
public class InvaderShoot : MonoBehaviour
{
//private float delay = Random.Range(1.5f,3f);
private bool canFire = false;
public float attackDistance = 150;
public GameObject bolt;
public Transform boltSpawn01;
public float fireSpeed;
private float fireAgain; //set the time between shots
void Update()
{
RaycastHit hit;
Ray shootingRay = new Ray(transform.position, -Vector3.forward);
//Debug.DrawRay(transform.position, -Vector3.forward * attackDistance);
if(Physics.Raycast(shootingRay, out hit, attackDistance))
{
if(hit.collider.tag == "ShieldCube")
{
canFire = true;
StartCoroutine(InvaderFireWeapon());
}
if(hit.collider.tag == "Enemy")
{
canFire = false;
}
if(hit.collider.tag == "Player")
{
canFire = true;
StartCoroutine(InvaderFireWeapon());
}
}
else
{
canFire = true;
StartCoroutine(InvaderFireWeapon());
}
}
IEnumerator InvaderFireWeapon()
{
float delay = Random.Range(1.5f,3f);
yield return new WaitForSeconds(delay);
print("Waiting For " + delay);
if(canFire == true && Time.time > fireAgain)
{
fireAgain = Time.time + fireSpeed;
Instantiate(bolt, boltSpawn01.position, boltSpawn01.rotation);
}
}
}
I know all 30 are using the same script, but I don't understand how(or why) they are still all firing at the same time.
Need some help on this one please guys
???
just to confirm I understand- is this correct?
You are telling them all to fire at the same time (or at least, the in same update cycle). Then you want each to wait a random 1.5-3 seconds before it actually shoots.
If so, I don see where it going wrong.... Can you confirm that RandomRange and WaitForSeconds are working as expected? $$anonymous$$gest a print command both above an below the "yield wait" command, like: print("time now:" + Time.time.ToString() + " delay:"+delay.ToString());
Alternate Idea: I would have done this differently, and created a new variable called fireAtTime. Setting fireAtTime equal to Time.time + delay during FireWeapon. I would check this value against Time.time during Update(). If it has "expired" (fireAtTime>=Time.time), and canFire, then instantiate projectile. (similar to what you are doing with fireAgain)
P.S. gratz on 1$$anonymous$$+ karma!
Answer by DiegoSLTS · Mar 29, 2015 at 09:17 PM
You wrote that "they still 'all' fire at exactly the same time", those single quotes mean that only some fire at the same time and not literally all of them?
I'm not sure about the problem here, but one thing that looks suspicious is that you start the "InvaderFireWeapon" coroutine on every frame that the raycast returns false, doesn't it start the coroutine in a lot of consecutive frames for most of the enemies?
Now, inside the coroutine, you wait a random time, but they don't shoot after that random time, they only shoot if the current time is grater than "fireAgain", wich is the same value for every object that has that component.
So, your enemies start a lot of coroutines and in all of them they wait some time. Each coroutine continues after that wait, and some of them reach the "if" before the "fireAgain" time, so those coroutines don't produce a shot. At some point one coroutine reaches that if and Time.time is actually greater than fireAgain, but since there where so many coroutines runing, Time.time is probably really close to fireAgain. Now, that coroutine sets fireAgain to a new time in the future, so when the rest of the coroutines that where waiting continue, they all evaluate "Time.time > fireAgain" as false, and don't shoot. During añl this time a lot of coroutines where started, so at some point one coroutine finishes the wait when Time.time is again greater than fireAgain, but it's probably really close again, so the cycle repeats.
I'd suggest you control the shooting ONLY with coroutines, not from the Update. Instead of starting the coroutine on the Update, start the coroutine again at the end of the same coroutine, something like this:
IEnumerator InvaderFireWeapon()
{
// doing this you make sure that the enemy waits at least the "fireSpeed" time before shooting again
float delay = Random.Range(fireSpeed,fireSpeed + 1.5f);
yield return new WaitForSeconds(delay);
if(canFire == true)
{
fireAgain = Time.time + fireSpeed; //I think you can remove this line
Instantiate(bolt, boltSpawn01.position, boltSpawn01.rotation);
}
StartCoroutine(InvaderFireWeapon());
}
And start that coroutine for the first time in some method that's called only once.
Your answer
Follow this Question
Related Questions
shot delay in between bullets 1 Answer
Loading Screen and Lerp 3 Answers
How to delay a function (how to use WaitForSeconds() and yield) 1 Answer
Yielding for a changing amount of time? 2 Answers
WaitForSeconds() Is not working. 5 Answers