I'm making a game in which I want to player collect coins using a magnet
here is the coins spawning code
// Spawn Coins In Air
void SpawnCoinsInAir ()
{
float yPos = transform.position.y + 1f;
float zPos = transform.position.z + 4f;
for (int i = 0 ; i < 10 ; i += 1)
{
int line = i == 0 ?
RandomsPlayerController.Instance.CurrentLineIdx
:
Random.Range(0, RandomsPlayerController.Instance.Lines.Count);
for (int j = 0 ; j < Random.Range(3,6) ; j += 1)
{
zPos += j + 10f;
var it = Instantiate(
coinTransform,
new Vector3(RandomsPlayerController.Instance.Lines [line].x,yPos , zPos),
Quaternion.identity
);
// do random rotattion in y
it.transform.DORotate (
Utilities.VectorY (Vector3.zero, Random.Range(-360,360)),
1f,
RotateMode.FastBeyond360
)
.SetEase (Ease.InOutSine);
Destroy (it, actionDuration + 1f);
}
}
}
Now I got all my coins in my game and I have to find each coin by its tag and collect them in the shortest distance.
I'm wondering how much cost it takes to find all coins in the Update function OR is there any way to do the same thing by keeping performance in mind?
Here is the code
private void UseMagnet ()
{
// collect coins
foreach (var coin in GameObject.FindGameObjectsWithTag ("coin")) continue;
}
private void Update () => UseMagnet();
Thanks in Advance
For smaller games, the cost is insignificant to the player. But it tends to get exponential the larger the search-space it.
How much cost GameObject.FindGameObjects
This is a case-by-case answer, use the profiler to see what is causing the most lag in your game.
Though unity documentation did state For performance reasons, it is recommended to not use this function every frame.
OR is there any way to do the same thing by keeping performance in mind?
Yes, what you are looking for is called caching.Create a static list and store all the coins there, like so:
// NOTE: Alternatively, you can turn this into a singleton
public static class GlobalCache {
// Transform or Coin Object.
private static HashSet<Transform> coinCache = new HashSet<Transform>();
public static Transform FetchAnyCoin() {
if (coinCache.Count <= 0) {
// Create a new coin, return it;
// NOTE: Ideally, creation of coins into this cache should be done else-where.
// The 'cache' should only handle storing and get/set requests.
return CreateNewCoin();
}
var result = coinCache.First();
// You can remove the fetched coin from the cache if you like.
coinCache.Remove(result);
return result;
}
}
In contrary to the generic Find, which you should never use if there is any other option, the FindGameObjectsWithTag as the name says uses a hashed (pre-indexed) tag which is quite optimized and not too expensive.
Of course there is still other ways to go which are even faster.
I would use a collection so the type itself can keep track of its own instances:
public class Coin : MonoBehaviour
{
private static readonly HashSet<Coin> instances = new ();
public static IEnumerable<Coin> Instances => instances;
private void Awake()
{
// will automatically register itself when coming to live
instances.Add(this);
}
private void OnDestroy()
{
// will automatically unregister itself when destroyed
instances.Remove(this);
}
}
Now you can simply iterate all coins via e.g.
foreach(var coin in Coin.Instances)
{
// check if close enough for your magnet e.g.
if(Vector3.Distance(coin.transform.position, player.transform.position) <= magnetRange)
{
//TODO: e.g. add points ?
Destroy(coin.gameObject);
}
}
It is considered fairly costly and is advised against using it in the Update function.
Essentially what you wish to do is to have a list over all spawned coins, and you control the spawning. This means you could easily add the spawned object to the list when you spawn it, and - if needed - remove them when you destroy them (if you dont remove them, you need to check for null in the list).
Not perfect, but depending on what you need it might work for you (not perfect because you're looping through a list asynchronously as you're adding/removing things from it)
For simplicity's sake, let's add a static (accessible anywhere) list somewhere
public static List<GameObject> SpawnedCoins = new List<GameObject>();
var it = Instantiate<GameObject>(coinTransform, ...);
SpawnedCoins.Add(it);
StartCoroutine(RemoveCoin(it))
IEnumerator RemoveCoin(GameObject coin, float time) {
yield return new WaitForSeconds(time);
SpawnedCoins.Remove(coin);
Destroy(coin);
}
Another class
foreach (var coin in SpawnedCoins) {
// Check for null first, if you Destroy them they will be null in the list
}
Alternatively, Destroy and check for null and then every few seconds clear the list of nulls before running the loop.
Related
Let's say I have two scripts:
SpawnManager
Enemy
In SpawnManager, I have the function SpawnEnemyWave that should instantiate 3 enemies, if the random number generator is lower than 5, then one of them should have a higher movement speed, the other shouldn't move at all.
In SpawnManager:
bool toughEnemy = true;
int waveNumber = 3;
float randomNumber = Random.Range(0, 10);
void Start()
{
SpawnEnemyWave(waveNumber);
}
void SpawnEnemyWave(int enemiesToSpawn)
{
float randomNumber = Random.Range(0, 10);
print(randomNumber);
for (int i = 0; i < enemiesToSpawn; i++)
{
if ((randomNumber < 5) && toughEnemy)
{
print("Tough");
Instantiate(enemyPrefab, GenerateSpawnPosition(), enemyPrefab.transform.rotation);
toughEnemy = false; //I make sure there is only one tough enemy per wave
}
else
{
print("Weak");
Instantiate(enemyPrefab, GenerateSpawnPosition(), enemyPrefab.transform.rotation);
}
}
}
In Enemy, I'm checking if the toughEnemy variable is set to true to modify the enemy speed before the instantiation, I put those if statements in the start function because I think than when an enemy is instantiated is when it is called.
void Start()
{
spawnManager = GameObject.Find("Spawn Manager").GetComponent<SpawnManager>();
if (spawnManager.toughEnemy)
{
speed = 1;
print("Speed " + speed);
}
else
{
speed = 0;
print("Speed " + speed);
}
}
The problem is, when the random number is 0 in the logs i see this...
random number:0
Tough (the i in the for loop is 0)
Weak (the i in the for loop is 1)
Weak (the i in the for loop is 2)
speed 0
speed 0
speed 0
And what I was expecting was something like below, because I'm modifying the variable in the SpawnManager script first before instantiating the enemy.
random number:0
Tough (the i in the for loop is 0)
speed 1
Weak (the i in the for loop is 1)
speed 0
Weak (the i in the for loop is 2)
speed 0
What am I missing here?
Timing. You’re partly correct thinking that Start will be called when the object is instantiated. But, it will be called when the next frame starts. In your current loop, you’re setting up the objects to be instantiated, then you set the toughEnemy to true. When the next frame starts, all the enemies think that a tough enemy has been set, and the output you see is correct.
If you want the manager to control the enemies, I’d personally include something like a Setup method, called by the manager. For example, in the Enemy script:
public bool isSetup { get; private set; }
public bool isTough { get; private set; }
void Setup(bool tough)
{
if ( isSetup ) return;
isSetup = true;
isTough = tough;
speed = tough ? 1 : 0;
}
Then, when you instantiate the enemy in your manager, do something like:
for (int i=0; i<enemiesToSpawn; i++)
{
var enemy = Instantiate( enemyPrefab, GenerateSpawnPosition(), enemyPrefab.transform.rotation );
var e = enemy.GetComponent<Enemy> ( );
if ((randomNumber < 5) && toughEnemy)
{
print("Tough");
toughEnemy = false; //I make sure there is only one tough enemy per wave
e.Setup(true);
}
else
{
print("Weak");
e.Setup(false);
}
}
Here’s the life cycle of a ‘frame’
Notice that the Update method processing occurs about in the middle of the frame lifecycle. You’re Instantiating 3 objects in the same Update method. THEN … the frame ends, and at the beginning of the next frame, the Start event for each of the new objects is triggered.
I would do this by putting the toughEnemy flag in the Enemy script itself. I would then add a SetTough() method to Enemy, which I would call from SpawnManager via GetComponent() after the Enemy is instantiated.
I want to bind the up and down arrow keys to cycle through different sprites upon being pressed. If one end is reached, it would loop back to the first sprite. I've tried using the following code:
public class PhaseChanger : MonoBehaviour
{
// saved for efficiency
[SerializeField]
public GameObject prefabMoon0;
[SerializeField]
public GameObject prefabMoon1;
[SerializeField]
public GameObject prefabMoon2;
[SerializeField]
public GameObject prefabMoon3;
[SerializeField]
public GameObject prefabMoon4;
// needed for new phase
GameObject currentPhase;
bool previousFramePhaseChangeInput = false;
/// <summary>
/// Start is called before the first frame update
/// </summary>
void Start()
{
currentPhase = Instantiate<GameObject>(prefabMoon0);
}
/// <summary>
/// Update is called once per frame
/// </summary>
void Update()
{
// change phase on up arrow or down arrow
if (Input.GetAxis("ChangePhase") > 0)
{
// only change phase on first input frame
if (!previousFramePhaseChangeInput)
{
previousFramePhaseChangeInput = true;
// Save current position and destroy current phase
Destroy(currentPhase);
// instantiate next phase
if (currentPhase = prefabMoon0)
{
currentPhase = Instantiate(prefabMoon1);
}
else if (currentPhase = prefabMoon1)
{
currentPhase = Instantiate(prefabMoon2);
}
else if (currentPhase = prefabMoon2)
{
currentPhase = Instantiate(prefabMoon3);
}
else if (currentPhase = prefabMoon3)
{
currentPhase = Instantiate(prefabMoon4);
else
{
// no phase change input
previousFramePhaseChangeInput = false;
}
}
}
}
When I attach the script to my main camera and run it, I'm able to make a single change with the up arrow, and then nothing else happens on subsequent presses.
I feel like I'm really close to making this work, but I also may being doing the whole thing inefficiently. Help would be much appreciated, thanks!
Also: I know I said sprites in my post and am sharing a script that calls on prefabs. I didn't know how to approach this using just the sprites without making a prefab for each. Is it possible to do this without separate prefabs for each sprite?
Problems
First of all you are using assignments
currentPhase = XY
where you should be using
currentPhase == XY
The reason why it still compiles is the implicit conversion operator for UnityEngine.Object -> bool. Basically your assigning equals writing
currentPhase = XY;
if(currentPhase)
It won't work like this either way because you are using Instantiate to create a new clone of a prefab which will of course have a different reference than the original prefab it was cloned from.
So even if your checks where looking like
if(currentPhase == XY)
they will ever be true.
Solution
Instead of checking for reference equality I would rather store all prefabs/instances in an array
public GameObject[] phases;
and then simply have an int index for this array so you can simply move to the next element from the array by increasing the index.
private int currentPhase;
And you can increase it and make it wrap around using e.g.
currentPhase = (currentPhase + 1) % phases.Length;
so it will always grow from 0 up to phases.Length - 1 and then start over from 0 again.
And then I don't know the exact requirements of your use case but I would suggest to rather not all the time use Instantiate and Destroy but rather have already all the objects as instances under your object and just (de)actívate them!
you could do this like e.g.
public GameObject[] phases;
private int currentPhase;
private void Awake ()
{
Init();
}
private void Update ()
{
if (Input.GetAxis("ChangePhase") > 0)
{
if (!previousFramePhaseChangeInput)
{
previousFramePhaseChangeInput = true;
NextPhase();
}
}
else
{
previousFramePhaseChangeInput = false;
}
}
// Disables all phases except the first one and sets the current index to 0
private void Init()
{
for(var i = 1; i < phases.Length; i++)
{
phases[i].SetActive(false);
}
phases[0].SetActive(true);
currentPhase = 0;
}
// Disables the current phase and enables the next one
// wraps around at the end of the array
public void NextPhase()
{
phases[currentPhase].SetActive(false);
// increase the counter and wrap around at the end of the array
currentPhase = (currentPhase + 1) % phases.Length;
phases[currentPhase].SetActive(true);
}
If you still want to Instantiate the objects because having them already in the scene is no option (for whatever reason) you could do it right before calling Init like e.g.
public GameObject[] phasePrefabs;
private GameObject[] phases;
private void Awake ()
{
var amount = phasePrefabs.Length;
phases = new GameObject [amount];
for(var i = 0; i < amount; i++)
{
phases[i] = Instantiate(phasePrefabs[i]);
}
Init();
}
Though as said I would prefer to already have them right away as this is way less error prone ;)
I am trying to use ParticleSystem.Emit() to dynamically emit particles, and am unable to get Emit() to work outside of the Start() method.
I am able to emit particles in the Start() method, either directly or with a separate method. When attempting to do the same in Update(), LateUpdate(), or FixedUpdate() it no longer works.
There are no errors reported. I reported the number of particles in the update methods to make sure that the code there was actually running, and it reports however many particles I emit in the Start() method.
When trying to emit particles in the update methods I have tried:
Using Emit() directly in the update loop.
Using a separate method called directly in the update loop.
Using a separate method called using Invoke() in the update loop.
I'm able to check and alter particle position in Update(), so I don't think I'm having some kind of scope problem.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour
{
public ParticleSystem aSystem;
private ParticleSystem.Particle[] aParticle;
void Start()
{
aParticle = new ParticleSystem.Particle[aSystem.main.maxParticles];
// Emit particle.
DoEmit();
Debug.Log("Particle Count: " + aSystem.particleCount);
}
void Update()
{
int numParticles = aSystem.GetParticles(aParticle);
Debug.Log("Number of particles: " + numParticles);
for (int i = 0; i < numParticles; i++)
{
if (aParticle[i].position.z > 1)
{
aParticle[i].position = new Vector3(0f,0f,0f);
}
aParticle[i].velocity = new Vector3(0f, 0f, 1f);
}
aSystem.SetParticles(aParticle);
// Emit particle.
DoEmit();
}
void DoEmit()
{
// Configure render settings for particle.
ParticleSystemRenderer aRenderer = aSystem.GetComponent<ParticleSystemRenderer>();
aRenderer.renderMode = ParticleSystemRenderMode.Mesh;
aRenderer.mesh = Resources.Load<Mesh>("vector");
// Configure rest of settings and emit.
var emitParams = new ParticleSystem.EmitParams();
emitParams.startLifetime = 120;
emitParams.position = new Vector3(0.0f, 0.0f, 0.0f);
emitParams.velocity = new Vector3(0.0f, 0.0f, 0.0f);
emitParams.startSize = 1;
aSystem.Emit(emitParams, 1);
aSystem.Play(); // Continue normal emissions
Debug.Log("DoEmit() called!");
}
}
Expected result: A stream of particles moving in the +z direction.
Actual result: One particle moving in the +z direction.
I needed to do something similar and found this answer in the Unity forums gave me a great, reliable solution that I've reused and modified to my purposes many times. It's a particle pool from which you can emit one or more particles as needed, killing off the last particle made and reusing it once it reaches its max number of particles. I think it achieves exactly what you're looking for. I'll include the relevant script here for reference (complete with #Artifact-Jesse's colorful commentary for clarity).
Note that this script was written for Unity 2018.x, but still works great as of 2020.2.1
Artifact-Jesse's complete, functional example of a fairly generic particle pool:
using UnityEngine;
[RequireComponent(typeof(ParticleSystem))]
public class ParticlePool : MonoBehaviour
{
private int lastParticleIndex = 0; // keeps track of our oldest particle (for deletion)
// these will all be inited in Initialize() on Start()
private ParticleSystem particleSys; // our object's particle system
private ParticleSystem.Particle[] particles; // our reusable array of particles
private ParticleSystem.EmitParams emitParams; // reusable emitparams
private int maxParticles = 0; // total number of particles in our scene before re-using
private void Awake()
{
Initialize(); // initialize all of our member variables
}
public void CreateParticle(Vector3 position, float size, Vector3 velocity, float angularVelocity)
{
// if we're at our particle count limit, kill our oldest particle.
int activeParticles = particleSys.GetParticles(particles);
/// this thing sucks. Read the Unity docs VERY carefully to understand...
/// basically the parameter (particles) is an out parameter which will
/// write out the existing particles in the particle system to our
/// reusable array. After that, we can directly modify the particles
/// and then when we're done, write the particles back into the
/// particle system with ParticleSystem.SetParticles( particles, count )
if (activeParticles >= maxParticles)
{
// set lifetime to -1 to kill the particle
particles[lastParticleIndex].remainingLifetime = -1;
// we need to reset start lifetime to a normal value, too or the particle will still have infinite lifetime
particles[lastParticleIndex].startLifetime = 1;
lastParticleIndex++; // keep track of oldest particle
if (lastParticleIndex >= maxParticles) lastParticleIndex = 0;
// have to re-write
particleSys.SetParticles(particles, particles.Length); // write those pesky particles back into our ParticleSystem
}
// set up params for this particle, you can use whatever you want (see unity docs for EmitParams for what's available)
emitParams.angularVelocity = angularVelocity;
emitParams.position = position;
emitParams.startSize = size;
emitParams.velocity = velocity;
emitParams.startLifetime = float.MaxValue; // float.MaxValue makes the particle's lifetime infinite
particleSys.Emit(emitParams, 1);
particleSys.Play();
}
void Initialize()
{
if (particleSys == null)
particleSys = GetComponent<ParticleSystem>();
maxParticles = particleSys.main.maxParticles;
if (particles == null || particles.Length < particleSys.main.maxParticles)
particles = new ParticleSystem.Particle[particleSys.main.maxParticles];
}
}
Note: the particle system in this example is just bare mininum with a renderer. Not looping, no start on awake, simulation space set to World. MaxParticles is respected by the above script.
This question already has an answer here:
Move GameObject back and forth
(1 answer)
Closed 5 years ago.
I'm trying to move multiple objects, simultaneously from Point A to Point B and back again, looped to serve as obstacles in blocking the player.
I've tried
StartCoroutine(Oscillate(OscillationFunction.Sine, 1f));
public IEnumerator Oscillate(OscillationFunction method, float scalar)
right = GameObject.FindGameObjectsWithTag("MovingObs2");
foreach (GameObject r in right)
{
startPos = r.transform.position;
v = startPos;
v.x = (r.transform.position.x + (Mathf.Cos(Time.time) * scalar));
r.transform.position = v;
yield return new WaitForSeconds(2);
r.transform.position = startPos;
}
and others, but they're all difficult to contain within a desirable distance and speed from the starting position. It's too fast, and too far.
and I tried a seemingly simpler line, which is easier to understand, for me.
v.x = l.transform.position.x + speed * Time.deltaTime;
l.transform.position = v;
but since i'm using an array in a foreach loop, i don't know how to preserve each GameObjects' transform.position, so that it can be used as a condition to reverse the direction of the objects' movement every time it reaches either Point A, or point B.
if (l.transform.position.x <= startPos.x || l.transform.position.x >= startPos.x + endPos.x)
{
speed *= -1;
}
edit: I apologize if I asked a duplicate question, I thought it was different due to the number of objects involved in an array.
I tried to assume to resolve all your question, please see the code below.
Time.deltaTime is not needed, since your code (and my) using the Time.time to calculate each time the position of the object.
I also would recommend (if possible) to not put all in on script, but give each object a swing script and also try to not use the CoRoutine. But to answer your question I show you how to do it.
I have created an internal class, to store in the "Init" the targeted gameobjects and their startPosition in a list. Later you can simply loop throu this list and always have the start position.
You need an endless loop in the "Osciallate" routine and need to wait each turn. In your example you put the Wait on the wrong place, so it waits after moving each object and stops after the first run throu all of this objects.
Here the code:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class OscilateObs : MonoBehaviour {
// internal class where all gameobjects and their startposition will be saved
internal class OscGameObjects
{
public GameObject gameObject;
public Vector3 startPosition;
}
// Here the information of all gameObjects stored in a list
private List<OscGameObjects> objectList;
public float updateSpeed = 0.05f;
public float oscScalar = 2f;
public enum OscillationFunction {
Sine = 1
}
void Start () {
// First, the gameobjects have to saved to our internal List
InitializeOscGameObjects();
// Start the Corotine
StartCoroutine(Oscillate(OscillationFunction.Sine, oscScalar));
}
private void InitializeOscGameObjects()
{
var objects = GameObject.FindGameObjectsWithTag("MovingObs2");
objectList = new List<OscGameObjects>();
foreach (var o in objects)
{
var oscObject = new OscGameObjects();
oscObject.gameObject = o;
oscObject.startPosition = o.transform.position;
objectList.Add(oscObject);
}
}
public IEnumerator Oscillate(OscillationFunction method, float scalar)
{
// Loop forever
while(true)
{
foreach (var element in objectList)
{
var currentPosition = element.gameObject.transform.position;
currentPosition.x = element.startPosition.x + Mathf.Cos(Time.time) * scalar;
element.gameObject.transform.position = currentPosition;
}
yield return new WaitForSeconds(updateSpeed);
}
}
}
EDIT:
I forgot to meantion:
1) I would recommend to use "Animation" Component for the movement and not using C# at all, so you can change the behaviour if needed and you are more flexible.
2) I would also recommend if possible to make a parent "GameObject" and moving only this and put the "MovingOb2" simply as child objects.
EDIT2:
Adding a delay increment for each object, so they not running syncron:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class OscilateObs : MonoBehaviour {
// internal class where all gameobjects and their startposition will be saved
internal class OscGameObjects
{
public GameObject gameObject;
public Vector3 startPosition;
public float waitCount;
}
// Here the information of all gameObjects stored in a list
private List<OscGameObjects> objectList;
public float updateSpeed = 0.05f;
public float oscScalar = 2f;
public float waitIncrementTime = 0.01f;
public enum OscillationFunction {
Sine = 1
}
void Start () {
// First, the gameobjects have to saved to our internal List
InitializeOscGameObjects();
// Start the Corotine
StartCoroutine(Oscillate(OscillationFunction.Sine, oscScalar));
}
private void InitializeOscGameObjects()
{
var objects = GameObject.FindGameObjectsWithTag("MovingObs2");
objectList = new List<OscGameObjects>();
float i = 0;
foreach (var o in objects)
{
i += waitIncrementTime;
var oscObject = new OscGameObjects();
oscObject.gameObject = o;
oscObject.startPosition = o.transform.position;
oscObject.waitCount = i;
objectList.Add(oscObject);
}
}
public IEnumerator Oscillate(OscillationFunction method, float scalar)
{
// Loop forever
while(true)
{
foreach (var element in objectList)
{
var currentPosition = element.gameObject.transform.position;
currentPosition.x = element.startPosition.x + Mathf.Cos(Time.time + element.waitCount) * scalar;
element.gameObject.transform.position = currentPosition;
}
yield return new WaitForSeconds(updateSpeed);
}
}
}
they're all difficult to contain within a desirable distance and speed from the starting position. It's too fast, and too far
Before you start monkeying with the structure of your code, I suggest you stick with the cosine function but educate yourself on the (very simple) manner in which you can manipulate output frequency and amplitude. This knowledge will serve you well (if this question is typical of your average project) and will solve the problem trivially.
If it's too fast, you can reduce the frequency (or increase the wavelength/period) by multiplying the input (which is always absolute time) by a constant coefficient between 0.0 and +1.0 (not inclusive).
If it's too far, you can reduce the amplitude by multiplying the output by a constant coefficient between 0.0 and +1.0 (not inclusive).
You just need to pick two constants and adjust to taste by running the program and seeing how you like it.
I'm making a project with Augmented Reality, using Unity and Vuforia extensions. I'm new to C#, but I was looking for a method similar to ARToolKit's getFrame(), and I'm really not finding anything.
My questions are:
Is it necessary that I can calculate the frame-rate that my scene is operating at?
Which scene object should i use to track the frame-rate?
Thats as simple as:
public float avgFrameRate;
public void Update()
{
avgFrameRate = Time.frameCount / Time.time;
}
Put this code in any MonoBehaviour and attatch it to any GameObject in the scene hierarchy.
Please note: this will only give you an average frame-rate. For a more current frame-rate, other answers have addressed effective ways of accomplishing that.
None of the answers here consider the fact that the timescale can be modified in Unity and if it is, all the above approaches will be incorrect. This is because Time.Delta time is influenced by the timescale.
As such, you need to use Time.unscaledDeltaTime:
int fps = 0;
void Update () {
fps = (int)(1f / Time.unscaledDeltaTime);
}
You should look at Time.smoothDeltaTime. This returns a smoothed Time.deltaTime value which you can use instead of having to smooth it yourself using one of the techniques mentioned in other answers.
You will want something like a timer that tracks the time, and how long it took to update the screen, and extrapolates from that how many frames are drawn in a second.
I am fairly rusty with Unity, but I believe something like 1/Time.deltaTime should give you what you want.
So you'd have something like
public void Update()
{
framerateThisFrame = 1/Time.deltaTime;
}
Next you would have to decide how often to change the displayed FPS, since framerateThisFrame can change a lot during every frame. You might want to change it every two seconds for example.
EDIT
An improvement you might want to make is something like storing the past n frames, and use an average to calculate the FPS, then display it. So you could end up with something like:
public int Granularity = 5; // how many frames to wait until you re-calculate the FPS
List<double> times;
int Counter = 5;
public void Start ()
{
times = new List<double>();
}
public void Update ()
{
if (counter <= 0)
{
CalcFPS ();
counter = Granularity;
}
times.Add (Time.deltaTime);
counter--;
}
public void CalcFPS ()
{
double sum = 0;
foreach (double F in times)
{
sum += F;
}
double average = sum / times.Count;
double fps = 1/average;
// update a GUIText or something
}
EDIT
You might even multiply the frame time by Time.timeScale, if you want to be consistent while you apply slow-down/time altering effects.
Since the framerate can vary constantly, it will change many times during a given second. I've used the following recommended approach to get the current framerate. Just put it in a new script and add it to a new, empty game object in your scene.
float deltaTime = 0f;
void Update() {
deltaTime += (Time.deltaTime - deltaTime) * .1f;
}
Source, including display method: http://wiki.unity3d.com/index.php?title=FramesPerSecond
IEnumerator FramesPerSecond()
{
while (true)
{
yield return new WaitForSeconds(1);
Debug.LogFormat("Fps {0}", Time.frameCount/Time.time);
}
}
private void Start()
{
StartCoroutine(FramesPerSecond());
}