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);
    }
}

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.

You can use CustomFixedUpdate, I had the same problem when coding a quick-firing gun.

http://wiki.unity3d.com/index.php/CustomFixedUpdate