I'm struggling to find an elegant solution to what seems to be a fairly simple problem.
In Update() some code executes in state1, and when if (Input.GetMouseButtonDown(0)) is clicked, some more code is executed and the state is changed to state2.
However, state2 also has a if (Input.GetMouseButtonDown(0)) which is being triggered by the original if (Input.GetMouseButtonDown(0)) from state1 as the change happens quickly, as Input.GetMouseButtonDown(0) can return true for several frames.
I've tried using booleans, and using Time.deltaTime() but I'm having issues with ensuring that the first mouse click doesn't trigger the second.
If anyone has any ideas or suggestions, I'd be very grateful.
Thanks
I think what you're looking for is edge detection. Essentially you check a condition for a change in state. While the boolean is the same as the last time you asked it you don't do anything but once it changes you execute some code.
//global variable
bool lastState = false;
//inside a method
bool newState = Input.GetMouseButtonDown(0);
if(newState != lastState)
{
lastState = newState;
//do stuff
}
Related
For my game you need to complete a mini-game to unlock abilities. But I atually have no clue how to do it cause the value gets resetted to false whenever I load the main-level.
Code playerMovement:
static bool FistAttackEnabled;
void Update ()
{
if (FistAttackEnabled == true)
{
if (Input.GetMouseButtonDown(0))
{
Debug.Log("Attack");
PlayerMovement.SetFloat("Attacking", 1f);
HitArea.SetActive(true);
}
}
}
Code miniGame:
void Start()
{
FistAttackEnabled = Player.GetComponent<Player_Movement>().FistAttackEnabledPortable;
}
void Update()
{
if (SheepsAmountGuess == NeededAni)
{
FistAttackEnabled = true;
}
}
But this doesnt work. I tried making a portable bool (FistAttackEnabledStatic = FistAttackEnabled) Because you cant transport static bool value's across scripts, but this also didn't work. Does anyone have a clue how to do it?
PS: The code is bigger but it doesn't have anything to do with the attack.
Each time the scene is loaded the scripts are reloaded, so variables will go to their "default" state
You can avoid the destruction of the gameObject by usign DontDestroyOnLoad(this.gameObject);
Since the GameObject wont be deleted each time you reload the scene a new copy will be created to solve that you should use a singleton(look for it you will find information easyly)
Both things will solve the problem temporaly but once you close the game everything will go to the original state. You should use some method to save the progress, PlayerPrefs is a really easy way to do it.
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
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.
First of all, I'm quite noob with animator and animation systems in unity.
What I'm trying to achieve (and I was trying with Animator component) is a randomized attack only while I keep my mouse button pressed on the enemy and which completes the execution of the attack clip that is playing even if i release the button meanwhile.
I tried adding my 2 attack animations to a list and play it, with something like
anim.Play(Random.Range(0, list.Count))
...but I don'tknow if the problem is that while I keep pressed one animation cancels the other or what.
Therefore I prefer to ask, because I'm probably doing things in the wrong way.
Thank you.
Yes the issue is probably what you said: You have to wait until one Animation finished before starting a new one otherwise you would start a new animation every frame.
You could use a Coroutine (also check the API) to do that.
Ofcourse the same thing could be implemented also only in Update without using a Coroutine but most of the times that becomes really cluttered and sometimes even more complicated to handle. And there is not really any loss or gain (regarding performance) in simply "exporting" it to a Coroutine.
// Reference those in the Inspector or get them elsewhere
public List<AnimationClip> Clips;
public AnimationClip Idle;
private Animator _anim;
// A flag to make sure you can never start the Coroutine multiple times
private bool _isAnimating;
private void Awake()
{
_anim = GetComponent<Animator>();
}
private void Update()
{
if(Input.GetMouseButtonDown(0)
{
// To make sure there is only one routine running
if(!_isAnimating)
{
StartCoroutine(RandomAnimations());
}
}
// This would immediately interrupt the animations when mouse is not pressed anymore
// uncomment if you prefer this otherwise the Coroutine waits for the last animation to finish
// and returns to Idle state afterwards
//else if(Input.GetMouseButtonUp(0))
//{
// // Interrupts the coroutine
// StopCoroutine (RandomAnimations());
//
// // and returns to Idle state
// _anim.Play(Idle.name);
//
// // Reset flag
// _isAnimating = false;
//}
}
private IEnumerator RandomAnimations()
{
// Set flag to prevent another start of this routine
_isAnimating = true;
// Go on picking clips while mouse stays pressed
while(Input.GetMouseButton(0))
{
// Pick random clip from list
var randClip = Clips[Random.Range(0, Clips.Count)];
// Switch to the random clip
_anim.Play(randClip.name);
// Wait until clip finished before picking next one
yield return new WaitForSeconds(randClip.length);
}
// Even if MouseButton not pressed anymore waits until the last animation finished
// then returns to the Idle state
// If you rather want to interrupt immediately if the button is released
// skip this and uncomment the else part in Update
_anim.Play(Idle.name);
// Reset flag
_isAnimating = false;
}
Note that this way of randomizing does not provide things like "Don't play the same animation twice in a row" or "Play all animations before repeating one".
If you want this checkout this answer to a very similar question. There I used a randomized list to run through so there are no doubles
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 :)