UNITY | Update or InvokeRepeating? - unity3d

I use many timers in my Unity project, they done like this:
void Update()
{
timer -= Time.deltaTime;
if(timer < 0)
{
DoSomething();
}
}
And in every google link they looks like this.
But today i found (im newbie) InvokeRepeating(); method.
So here is updated timer
int timer = 60;
void Start()
{
InvokeRepeating("Timer", 1f, 1f);
}
void Timer()
{
timer -= 1;
}
So why people change timers in Update()?
And which method less inpact on performance?

Depends!
As usual in programming there are most of the time multiple valid solutions for a problem.
In my eyes the bigest difference is that InvokeRepeating is also working on inactive GameObjects or disabled Components while Update is only called while the object is active and the component enabled.
Note, however, that your current examples do different things. To make them equivalent it should look like either
void Start()
{
timer = 1f;
}
void Update()
{
timer -= Time.deltaTime;
if(timer < 0)
{
timer = 1f;
DoSomething();
}
}
or
void Start()
{
InvokeRepeating(nameof(DoSomething), 1f, 1f);
}
Btw: A third basically equivalent solution would be a Coroutine (which is basically a temporary Update method - in fact the MoveNext call gets executed right after the Update would)
// Yes, Start can be an IEnumertaor and is in this case internally implicitly started as Coroutine!
IEnumerator Start()
{
while(true)
{
yield return new WaitForSeconds(1f);
DoSeomthing();
}
}
As mentioned by Kuruchy: There is also a difference in behavior related to the timeScale.
Update: since it uses Time.deltaTime to decrease the timer it will be affected by the time scale
→ in order to avoid this you would need to use Time.unscaledDeltaTime instead. But afaik still if setting Time.timeScale = 0; then Update isn't called at all.
Coroutine: Similar to update the WaitForSeconds is also timeScale dependent.
→ in roder to avoid this you would need to use WaitForSecondsRealitme but afaik even then setting Time.timeScale = 0; would lead to the routine not getting called at all.
InvokeRepeating: Fromt he docs I can only see that
This does not work if you set the time scale to 0.
not sure how it reacts to the timescale though but I would actually guess the same. Though, here there is no real work around like for the other two.
Performance wise you most probably don't even have to care! I guess it would be over-optimizing.
However my guess would be that Update is actually slightly faster since there you already know the method reference while when using InvokeRepeating you are passing it as a string which is additionally error prone and means that internally Unity has to find that method first.

Without going into too much detail is because of the performance.
The Update() method is invoked internally by Unity and they've done a pretty good job in optimizing it.
InvokeRepeating is much slower in comparison. First of all because the initial method invocation is using the Reflection to find the method you want to start and it's respective calls also take more time than Update. And you want to avoid using Reflection in your code as much as possible.
Here is nice, short article in which the tests were performed between these two methods - http://www.kittehface.com/2017/09/unity-performance-with-invokerepeating.html

Related

Player moves in Update() but not FixedUpdate() in Unity

I made a car controller in unity to drive around. I've read FixedUpdate is better to use for physical objects instead of Update, but when I switch to Fixed update my car no longer drives. Does anyone know why this might be? Thank so much you for any help you an provide!
public float speed;
public float turnSpeed;
private RigidBody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void FixedUpdate()
{
Move();
Turn();
}
void Move(){
// moves the car
if (Input.GetKey(KeyCode.W)){
rb.AddRelativeForce(new Vector3(Vector3.forward.x, 0, Vector3.forward.z) * speed);
}
else if (Input.GetKey(KeyCode.S)){
rb.AddRelativeForce(new Vector3(Vector3.forward.x, 0, Vector3.forward.z) * -speed);
}
// maintains forward velocity relative to car.
Vector3 localVelocity = transform.InverseTransformDirection(rb.velocity);
localVelocity.x = 0;
rb.velocity = transform.TransformDirection(localVelocity);
}
void Turn(){
// turns the car.
if (Input.GetKey(KeyCode.D)){
rb.AddRelativeTorque(Vector3.up * turnSpeed);
Debug.Log("TURNING CAR");
}
else if (Input.GetKey(KeyCode.A)){
rb.AddRelativeTorque(-Vector3.up * turnSpeed);
Debug.Log("TURNING CAR");
}
Here's the code. Pressing W or S adds a force, pressing A or D adds a torque. When I try turning in FixedUpdate the console will write "TURNING CAR" as it should which shows that it's making past the AddRelativeTorque line, but it still won't turn so I'm not really sure what's going on. Thanks again, I really appreciate any help.
Try increasing the force used.
Fixed update runs less frequently than update (using the default settings, in most scenarios). Since the code is running much less frequently, less force is being accumulated over the same time period.
Consider a game running at 100fps. The default fixed time step is 0.02s (50 frames per second). Since update is running at 100fps, you have twice as much force being applied from update than would be applied from fixed update.
If you make your force value independent of the time since the last update happened, you will not need to worry about this.
For Update use myForceValue * Time.deltaTime.
For FixedUpdate use myForceValue * Time.fixedDeltaTime.

Unity FixedUpdate vs Update physics on input

In multiple answers it was stated that Update is called once every frame and shouldn't be used for physics update, it should however be used for input or you might miss important events.
The problem that arises now is what if I ise Update to influence a physics object?
That for example on a mouse release, some balls start moving and spinning.
void Update
{
if (Input.GetMouseButtonUp(0))
{
ball.getComponent<Rigidbody>().AddForce(vector);
ball.getComponent<Rigidbody>().AddTorque(vector2);
}
}
To achieve optimal performance you should split the code.
Inside Update you get the input and store it somewhere.
Inside FixedUpdate you calculate physics.
In the specific case you mentioned the code will become:
bool mouseUp = false;
void Update()
{
mouseUp = Input.GetMouseButtonUp(0);
}
void FixedUpdate()
{
if (mouseUp)
{
ball.getComponent<Rigidbody>().AddForce(vector);
ball.getComponent<Rigidbody>().AddTorque(vector2);
mouseUp = false;
}
}
-------------
EDIT (after derHugo and Wouter Vandenputte comments)
In some cases FixedUpdate might be called multiple times a frame. So it is safer to reset the value after it's usage. In the example case by adding mouseUp = false.

Endless Runner Infinite track generation - Unity3D C#

I am new to unity and I am creating my first ever endless runner game. I currently have a cube as a player and another cube (prefab) as the track. I have created a script which aims at instantiating the prefab at runtime and moving the track towards the player (instead of moving the player). For some reason, the tracks instantiated at runtime are being generated at the same position and don't seem to move towards the player. Could anyone tell me if I am doing it right please? How do I generate an infinite/endless track? Thanks in advance
public GameObject[] trackPieces;
public float trackLength;
public float trackSpeed;
private GameObject trackObject;
// Update is called once per frame
void Update ()
{
GenerateInfiniteTrack();
}
private void GenerateInfiniteTrack()
{
trackObject = InstantiatePrefab();
trackObject.transform.Translate(-Vector3.forward * Time.deltaTime * trackSpeed);
}
private GameObject InstantiatePrefab()
{
return Instantiate(trackPieces[Random.Range(0, trackPieces.Length)]) as GameObject;
}
trackObject is overwritten every frame
Your track is not moving because the call to move it occurs only once at instantiation and never again. The value of which track to move is overwritten every update(). Here is what happens:
Every update you make a call to:
private void GenerateInfiniteTrack()
When this method is called you instantiate a new prefab (new instance of your object) and tell the object to move via
trackObject.transform.Translate(-Vector3.forward * Time.deltaTime * trackSpeed);
When you call the method the next time you lose the reference to the original object because you are creating another one that replaces the value held in trackObject. So the previously generated object will never move again. Your new object moves once and then is lost, again, and repeat.
Below I have suggested some code that may work. You will still have to decide how you will dispose of the track objects since you are creating them at a very fast rate. If you can think of a way to use InvokeRepeating() to address this problem, then that would be the cleanest. Invoke repeating has some limitations, like not being able to pass parameters to your repeating function so I did not use it here, but it is conceivably an alternative.
Here is my example.
var TrackObjects = new List<GameObject>();
private void MoveInfiniteTrack()
{
foreach(GameObject gO in TrackObjects )
{
gO.transform.Translate(-Vector3.forward * Time.deltaTime * trackSpeed);
}
}
private void GenerateInfiniteTrack()
{
TrackObject = InstantiatePrefab();
TrackObjects.Add(TrackObject);
}
void Update ()
{
GenerateInfiniteTrack();
MoveInfiniteTrack()
}
void Foo()
{
// Delete your track on some kind schedule or you will quickly get infinite objects and massive lag.
}
As a general observation, creating track this much (60x a second) is very inefficient. I would suggest that you either:
A. Create much larger segments of track, for example once every 1 or 10 seconds and move it along. I don't remember exactly how to do this, but it went something like this:
var lastchecked= datetime.now
Update()
{
if((datetime.now - lastchecked).seconds > 1)
{
// put here what you will do every 1 second.
lastchecked= datetime.now
}
}
B. Create a large cylinder and rotate it to use as a track.

Trying to program a timer to do something when it reaches 5 seconds

I can't seem to figure out what to do here. I'm creating a learn to type game where if the user doesn't get the word correct in 5 seconds, they lose a life.
Either this could be implemented by counting down to 0 from 5, or counting up to 5.
I tried using the stopwatch for c# system diagnostics, which works for everything except I can't figure out how to check when it hits 5 seconds. It is a time object you cant compare it to an int.
you have two options here.
You can check the time in the Update function with Time.time or Time.deltaTime, or you can use a Coroutine with the new WaitForSeconds(5) object.
It could be as simple as:
float time;
void Update()
{
time += Time.deltaTime;
if(time > 5)
{
LoseALife();
}
}
If you need to restart the timer each time you complete a word you might have an aditional method like:
public void RestartTimer()
{
time = 0;
}
This would make the timer go back to 0 any moment you need it.

Time Delay for a process in Unity 3D

I have to give the delay for the process to happen, which I am calling in the Update function.
I have tried CoUpdate workaround also. Here is my code:-
function Start()
{
StartCoroutine("CoStart");
}
function CoStart() : IEnumerator
{
while(true)
{
yield CoUpdate();
}
}
function CoUpdate()
{
//I have placed the code of the Update().
//And called the wait function wherever needed.
}
function wait()
{
checkOnce=1; //Whenever the character is moved.
yield WaitForSeconds(2); //Delay of 2 seconds.
}
I have to move an object when a third person controller(which is another object) moves out of a boundary. I have included "yield" in my code. But, the problem happening is: The object which was moving when I gave the code for in the Update(), is moving, but isn't stopping. And it is moving up and down. I don't know what is happening! Can someone help? Please, thanks.
I am not entirely clear what you are trying to accomplish, but I can show you how to set up a Time Delay for a coroutine. For this example lets work with a simple cool down, much like you set up in your example. Assuming you want to continuously do something every 2 seconds while your game is running a slight modification can be made to your code.
function Start()
{
StartCoroutine(CoStart);
}
function CoStart() : IEnumerator
{
while(true)
{
//.. place your logic here
// function will sleep for two seconds before starting this loop again
yield WaitForSeconds(2);
}
}
You can also calculate a wait time using some other logic
function Start()
{
StartCoroutine(CoStart);
}
function CoStart() : IEnumerator
{
while(true)
{
//.. place your logic here
// function will sleep for two seconds before starting this loop again
yield WaitForSeconds(CalculateWait());
}
}
function CalculateWait() : float
{
// use some logic here to determine the amount of time to wait for the
// next CoStart cycle to start
return someFloat;
}
If I have missed the mark entirely then please update the question with a more detail about what you are attempting to accomplish.
I am not 100% sure that I understand you question but if you want to start one object to move when the other is out of bound then just make a reference in the first object to the second object and when the first object is out of bounds (check for this in Update of the first object) call some public function StartMove on the second object.
I wouldn't suggest CoRoutines. It can sometimes crash your computer. Just define a variable and decrement it. Example:
private float seconds = 5;
then do anywhere you want to delay:
seconds -= 1 * Time.deltaTime;
if(seconds <= 0) {your code to run}
This will make a delay of 5 seconds. You can change 5 to any value to change the number of seconds. Also you can speed up the decrement by changing the value of 1. (This is mostly useful when you want to sync 2 delayed actions, by using the same variable)
Hope this helps. Happy coding :)