- Home /
Bullet Spawn depends on frame rate.
Hello
I'm making a Bullet Hell Game. But I have trouble making the spawners Framerate Independent.
If I Pause and Frame Advance The spawners spawn more, But In Realtime it spawns less.
A clear Indicator that It depends on frame rate.
I Tried Time.deltaTime But that doesn't work.
Here's the Code Snippet In charge of the spawning:
// Fire Bullets
if (fireNumber >= rateOfFire)
{
SpawnBullet();
fireNumber = 0;
bulletCount++;
}
else
fireNumber += Time.deltaTime;
My guess is that if the amount Time.deltaTime is bigger than the spawn rate it skips over them.
I can't just spawn more bullets if Time.deltaTime is bigger than the spawn rate because they would just be on top of each other.
This is a big problem for the game and I would appreciate any answers.
Edit: Full Script. Warning Messy and unreadable:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletSpawn : MonoBehaviour
{
//Spawn Controls
public GameObject spawnObject;
public float rateOfFire;
public float bulletSpeed = 0.1f;
public bool randomBulletSpeed;
public bool aimAwayFromBoss = false;
public Sprite Colour;
public float offset = 0;
public bool patterned = false;
public int everyBullet = 10;
public float waitTime = 100;
public float speedAdd = 0f;
public float curveTimeAdd = 0f;
public int rotationOffset = 0;
public bool spawningSpawns = false;
public AudioClip clip = null;
public bool lazer = false;
public float lazerTime = 1;
public float lazerWait = 1;
public Animation playedAnimation;
public moveObj_Aim aimer;
public moveObj_RandomRotation randomRotation;
public bool ignoreFirst = false;
public bool randomOffset;
public bool easeIn = false;
public bool easeOut = false;
public bool curve = false;
public bool reSet = false;
public float curveRate = 0.1f;
public float curveTime = 1f;
public float newSlow = 0.5f;
public float[] changeTimes;
public float[] rotationAdd;
public float[] newSpeed;
public float changeEase = 0.05f;
public bool affector = false;
public bool affectorEnter = false;
public bool aimAtPlayer = false;
public bool randomRot = false;
public bool follow = false;
public float changeSpeed = 0f;
public bool destroyEnter;
public float min;
public float max;
public GameObject objChange;
public int rofChange;
public bool ssChange = false;
public float speedChange = 0;
public float bSpeedChange = 0.1f;
public bool homingChange = false;
public bool homingCChange = false;
public Color tintChange;
public int offsetChange = 0;
public AudioClip clipChange = null;
public bool easeInChange = false;
public bool easeOutChange = false;
public bool curveChange = false;
public float curveRateChange = 0.1f;
public float curveTimeChange = 1f;
public float newSlowChange = 0.5f;
//Movement Controls
public float speed = 0;
public bool homing = false;
public bool homingContinuous = false;
float fireNumber;
float bulletWait = 0;
int bulletCount = 0;
float originalSpeed;
float originalCurve;
float offsetCount;
public Quaternion initialRotation;
GameObject tempObj;
// Use this for initialization
void Start()
{
originalSpeed = bulletSpeed;
originalCurve = curveTime;
if (homing)
{
Vector2 dir = GameObject.Find("Player").transform.position - transform.position;
float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
angle -= 90;
angle += rotationOffset;
transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
}
if (aimAwayFromBoss)
{
Vector2 dir = GameObject.Find("BossInitialPosition").transform.position - transform.position;
float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
angle -= -90;
angle += rotationOffset;
transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
}
fireNumber = rateOfFire;
//offset += (float)Random.Range(-1f,1f);
offsetCount = 0;
}
// Update is called once per actual frame
void Update()
{
//Move if Possible
gameObject.transform.Translate(new Vector2(0, speed), Space.Self);
if (offsetCount < offset)
{
offsetCount += Time.deltaTime;
return;
}
if (homingContinuous)
{
initialRotation = gameObject.transform.rotation;
Vector2 dir = GameObject.Find("Player").transform.position - transform.position;
float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
angle -= 90;
transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
}
if (patterned && bulletCount >= everyBullet)
{
bulletWait += Time.deltaTime;
if(bulletWait >= waitTime)
{
bulletCount = 0;
bulletWait = 0;
bulletSpeed = originalSpeed;
curveTime = originalCurve;
}
else
return;
}
// Fire Bullets
if (fireNumber >= rateOfFire)
{
SpawnBullet();
fireNumber = 0;
bulletCount++;
}
else
fireNumber += Time.deltaTime;
if (homingContinuous)
gameObject.transform.rotation = initialRotation;
}
private void LateUpdate()
{
if (fireNumber >= rateOfFire)
{
if (randomRotation != null)
randomRotation.RandomRotation();
}
}
void SpawnBullet()
{
tempObj = Instantiate(spawnObject);//ObjectPooler.SharedInstance.GetPooledObject(spawnObject.name);
tempObj.transform.position = transform.position;
tempObj.transform.rotation = transform.rotation;
//tempObj.SetActive(true);
if(aimer != null)
aimer.Aim();
BulletManager.sharedInstance.GetSpawnSound(clip).Play();
if(playedAnimation != null)
playedAnimation.Play();
if (spawningSpawns)
{
BulletSpawn bulletSpawn = tempObj.GetComponent<BulletSpawn>();
bulletSpawn.spawnObject = objChange;
bulletSpawn.rateOfFire = rofChange;
bulletSpawn.spawningSpawns = ssChange;
bulletSpawn.speed = speedChange;
bulletSpawn.bulletSpeed = bSpeedChange;
bulletSpawn.homing = homingChange;
bulletSpawn.homingContinuous = homingCChange;
bulletSpawn.offset = offsetChange;
bulletSpawn.clip = clipChange;
bulletSpawn.fireNumber = tempObj.GetComponent<BulletSpawn>().rateOfFire;
if (easeInChange || easeOutChange || curveChange)
{
bulletSpawn.enabled = true;
bulletSpawn.easeIn = easeInChange;
bulletSpawn.easeOut = easeOutChange;
bulletSpawn.curve = curveChange;
bulletSpawn.curveRate = curveRateChange;
bulletSpawn.curveTime = curveTimeChange;
bulletSpawn.newSlow = newSlowChange;
}
}
else if (!lazer)
{
if (randomBulletSpeed)
{
RandomizeBulletSpeed();
}
tempObj.GetComponent<Bullet>().speed = bulletSpeed;
tempObj.GetComponent<Bullet>().ignoreFirst = ignoreFirst;
if(Colour != null)
tempObj.GetComponent<SpriteRenderer>().sprite = Colour;
}
else if (lazer)
{
tempObj.GetComponent<Lazer>().waitTime = lazerWait;
tempObj.GetComponent<Lazer>().time = lazerTime;
tempObj.transform.parent = gameObject.transform;
tempObj.transform.localRotation = Quaternion.identity;
}
if (easeIn || easeOut || curve || reSet || affectorEnter || affector)
{
tempObj.GetComponent<BulletEffects>().enabled = true;
tempObj.GetComponent<BulletEffects>().easeIn = easeIn;
tempObj.GetComponent<BulletEffects>().easeOut = easeOut;
tempObj.GetComponent<BulletEffects>().curve = curve;
tempObj.GetComponent<BulletEffects>().curveRate = curveRate;
tempObj.GetComponent<BulletEffects>().curveTime = curveTime;
tempObj.GetComponent<BulletEffects>().newslow = newSlow;
tempObj.GetComponent<BulletEffects>().reSet = reSet;
tempObj.GetComponent<BulletEffects>().changeTimes = changeTimes;
tempObj.GetComponent<BulletEffects>().rotationAdd = rotationAdd;
tempObj.GetComponent<BulletEffects>().newSpeed = newSpeed;
tempObj.GetComponent<BulletEffects>().initialSpeed = bulletSpeed;
tempObj.GetComponent<BulletEffects>().time = 0;
tempObj.GetComponent<BulletEffects>().changeNumber = 0;
tempObj.GetComponent<BulletEffects>().finished = false;
tempObj.GetComponent<BulletEffects>().affectorEnter = affectorEnter;
tempObj.GetComponent<BulletEffects>().affector = affector;
tempObj.GetComponent<BulletEffects>().aimAtPlayer = aimAtPlayer;
tempObj.GetComponent<BulletEffects>().randomRotation = randomRot;
tempObj.GetComponent<BulletEffects>().followDirection = follow;
tempObj.GetComponent<BulletEffects>().changeEase = changeEase;
tempObj.GetComponent<BulletEffects>().changeSpeed = changeSpeed;
tempObj.GetComponent<BulletEffects>().destroy = destroyEnter;
}
bulletSpeed += speedAdd;
curveTime += curveTimeAdd;
}
void RandomizeBulletSpeed()
{
bulletSpeed = Random.Range(min, max);
}
}
Is this being executed inside a coroutine or inside an update function? could you show a bit more of the code?
So is this more of a fire rate thing? you want to create X amount per second etc?
jhon-essy: It's more like a [spawn any missed bullets] problem
$$anonymous$$acDX: It is inside the Update Function, This is the heart of the spawning code.
Anything else isn't related to spawning bullets at a fixed rate.
Ok, there shouldn't be any problem with your code. You could also give a try to the code that john-essy posted in his answer below.
One thing tho, if you are pausing the game, are you changing Time.timeScale? And if so, what values are you setting it to? Remember that Time.timeScale affects the values Time.deltaTime returns.
Sorry for taking a long time to respond but doesn't John's code do the same thing?
I'm trying IEnumerator now, but I have trouble telling if it's frame rate independent. Can someone tell me?
Answer by john-essy · Sep 04, 2017 at 09:05 PM
public float fireRate;
public void Update()
{
fireRateTimer += Time.deltaTime;
if (fireRateTimer >= fireRate)
{
// CreateBullet()
// fireRateTimer = 0;
}
}
Of course add your check to trigger this in the update.
Answer by Cherno · Sep 11, 2017 at 09:42 AM
You can use CustomFixedUpdate, I had the same problem when coding a quick-firing gun.
http://answers.unity3d.com/questions/1143243/rapid-fire-how-to-accurately-wait-for-a-very-short.html
Doesn't work it's not framerate independent. If I hold the window for a second then release, It skips the spawning of some bullets.