Hello,
I tried getting an answer on this using the answers page but to no avail.
I am making a shooting script and I would like to limit the rate of fire using the WaitForSeconds method. I am using the script below but it wont work… It has about 1 sec delay between the shots and it does not matter what the “rateOfFire” float is set to, it is completely ignored.
Any idea what I am doing wrong?
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(GameObject))]
public class FireBullets : MonoBehaviour
{
public GameObject projectileType; //the prefab that should be spawned.
public float bulletSpeed = 30f;
public float reloadSpeed = 3f;
public float rateOfFire = 1f;
public int clipSize = 30;
private bool allowFire = true;
private int bulletsLeft;
void Awake ( )
{
bulletsLeft = clipSize;
}
void Update ( )
{
if (Input.GetMouseButton(0) && allowFire) //when left mousebutton is held.
{
Fire(); //fire projectile.
}
}
void Fire( )
{
//find the posotion where the projectile should spawn.
Transform spawn = transform.Find( "Spawn" );
//create projectile.
GameObject projectile = Instantiate( projectileType, spawn.position, spawn.rotation ) as GameObject;
//calculate force and apply it.
Vector2 vBarrelDir = new Vector2(spawn.transform.up.x,spawn.transform.up.y);
projectile.rigidbody2D.AddForce(vBarrelDir * 250f);
//start the delay
StartCoroutine(Wait(rateOfFire));
}
//do not allow any bullets to be created until the delay is over.
IEnumerator Wait(float time){
allowFire = false;
yield return new WaitForSeconds (time);
allowFire = true;
}
}
Don’t take this as an answer since I am not very good with this, but in CSharp, WaitForSeconds() doesn’t work so great, you canuse it in a IEnumerator void though. I just make another void, and invoke that void for a certain amount of seconds. It does well to, making it so you don’t interrupt other things, and more tidy.
WaitForSeconds (regardles of how well it works) is probably the wrong approach here. Coroutines are best used for things that need complex, precise scripted and timed actions. This is much more simple, so let’s use a simpler technique.
public float fireDelay = 1f;
private float lastFiredAt = -999f;
void Update() {
if (Input.GetMouseButton(0) && Time.time > lastFiredAt + fireDelay) {
lastFiredAt = Time.time;
Fire();
}
}
Compared to a script I’ve made a few weeks ago, only the StartCoroutine is called first instead of last. Here’s it:
(don’t mind the other messy stuff
)
public Transform areaParent;
public Transform[] ammo;
public float shootSpeed;
public float minShootSpeed;
public PlayerController pc;
public Transform shield;
private bool isShooting = false;
public void ShootNormalRocket()
{
if (pc.missiles > 0 && !isShooting)
{
StartCoroutine(Launch());
Transform normalRocketClone = Instantiate (ammo [0], transform.position + new Vector3(0, 0, 2), ammo[0].rotation) as Transform;
normalRocketClone.parent = areaParent;
normalRocketClone.position = transform.position;
if(shield.gameObject.activeInHierarchy)
Physics.IgnoreCollision(normalRocketClone.collider, shield.collider);
Physics.IgnoreCollision(normalRocketClone.collider, collider);
Vector3 force = rigidbody.velocity * shootSpeed;
if (force.z < minShootSpeed)
force.z = minShootSpeed;
normalRocketClone.rigidbody.velocity = force;
Destroy (normalRocketClone.gameObject, 5);
pc.missiles--;
pc.totalUsedMissiles++;
}
}
private IEnumerator Launch()
{
isShooting = true;
yield return new WaitForSeconds(0.2f);
isShooting = false;
}
Thanks for the quick replies!
Before trying with Coroutines I did try something like your suggestion SratManta, but after similar results I gave this a shot.
I have now updated with your suggestions but the same behavior occurs, and just to check I set the rateOfFire really high, but there is still about a sec delay only.
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(GameObject))]
public class FireBullets : MonoBehaviour
{
public GameObject projectileType; //the prefab that should be spawned.
public float bulletSpeed = 30f;
public float reloadSpeed = 3f;
public float rateOfFire = 5000f;
public int clipSize = 30;
private int bulletsLeft;
private float lastFiredAt = -999f;
void Awake ( )
{
bulletsLeft = clipSize;
}
void Update ( )
{
if (Input.GetMouseButton(0) && (Time.time > (lastFiredAt + rateOfFire))) //when left mousebutton is held.
{
lastFiredAt = Time.time;
Fire(); //fire projectile.
}
}
void Fire( )
{
//find the posotion where the projectile should spawn.
Transform spawn = transform.Find( "Spawn" );
//create projectile.
GameObject projectile = Instantiate( projectileType, spawn.position, spawn.rotation ) as GameObject;
//calculate force and apply it.
Vector2 vBarrelDir = new Vector2(spawn.transform.up.x,spawn.transform.up.y);
projectile.rigidbody2D.AddForce(vBarrelDir * 250f);
}
}
Something happens because if I don’t use anything but “Input.GetMouseButton(0)” in the if-stetement the bullets fly out at an insane rate.
Look at the script in the inspector. What does it say for rateOfFire? I bet it still says “1”.
When Unity first compiles a script with a public variable, the default value of that variable gets assigned to any instances of that script that exist. Future changes to the default value in the script will only be applied if A) you put the script on a new object, or B) you right-click “Reset” on the component in the inspector.
1 Like
Awesome StarManta! that was it.
I am familiar with general coding like java and C so I did not even think of the inspector, lesson learned!
Thanks again for the fast replies.