We know there's a "rule" that Input functions shouldn't be used inside the FixedUpdate(); Input.GetKeyDown() may not work if we do so, but is it really wrong to use Input.GetKey()?
Let's say we want to fire something when pressing and holding a key at some rate that is not dependent on hardware performance. I don't want to create a logic to control this using delta time or writing key detection code in Update and firing code in FixedUpdate.
Doesn't make sense to just do everything inside FixedUpdate? What can happen - we may lose some key pressed events, the ones that we didn't want anyway, to keep our desired rate.
But what if one single key event happens, can we lose it? Is there a reset after Update, so we won't see it on FixedUpdate?
From the GetKeyDown docs:
You need to call this function from the Update function, since the
state gets reset each frame
So yes, the Input state is reset each frame meaning hardware will have an effect depending on how frequently Update fires between FixedUpdate.
There really isn't an easy way to avoid creating a copy of the Input that is used by FixedUpdate, though I would suggest reevaluating your logic to move things in to Update.
Update:
Regarding Rutter's comment below. I just noticed the OP was asking about GetKey(), what I wrote about GetKeyDown() remains true for GetKey() though the documentation doesn't explicitly say so.
This can be verified by going in to the Time Manager and changing the FixedUpdate rate to some long interval like 1 second. Then do something like:
void FixedUpdate() {
if(Input.GetKey(KeyCode.D)){
Debug.Log("D-Key Down");
} else {
Debug.Log("No key down");
}
}
If you press and release 'D' between the 1 second fixed frames you will only see "No Key Down".
In my experience, Update occurs at frame-time, unlike Fixed Update which can occur multiple times per-frame. In addition, The physics of objects are actually updated before FixedUpdate() is called, which means there could be a delay based on the complexity of the scene.
I believe that Input is actually broadcasted per-frame, so when the FixedUpdate() is behind and needs to catch up by firing multiple times, the Input check will fail.
Additional Resources:
http://answers.unity3d.com/questions/10993/whats-the-difference-between-update-and-fixedupdat.html
Related
I am creating a basic 2D fighter game and am trying to replace what was the old input system with the new input system. Because of this the old systems update would wait for buttons and then call appropriate functions when they were pressed. Movement was actually the easiest part, simply rigging a 1D Vector and then grabbing the float to use with movement, awesome. However the difficulty is in pressing keys to change things in the game. For example, I have an input 's' which should lead to the method Crouch(). This method changes the animation running and alters the hitbox to be shorter and tell the attack to use a smaller hitbox as well. A Stand() method is called on release of 's' to return everything to the way it is. I have my Player Input object set to 'Invoke Unity Events' which leads to the corresponding method needed. The problem is that even though these events are set to be push and release they are read as a toggle effect instead of press and release triggers(respectively). This does the same thing with my attack function because it forces the animation to play twice, one for pressing and one for releasing. Is there a fix for this or is this currently a bug? Edit: Here are some images to clarify and the code used to reflect everything happening associated with the Attack functionality. Let me know if anything else should be needed
public void Attack(){
anim.SetTrigger("attack");
StartCoroutine(wait());
}
IEnumerator wait(){
if(!isCrouched){
yield return new WaitForSeconds(1.3f);
SHitBox.enabled = true;
yield return new WaitForSeconds(.5f);
SHitBox.enabled = false;
}
if(isCrouched){
yield return new WaitForSeconds(1.3f);
CHitBox.enabled = true;
yield return new WaitForSeconds(.5f);
CHitBox.enabled = false;
}
}
Binding
Action
Think I figured it out. At least for the purposes of this specific thread. The answer was it was not my code. There is what I am going to call a bug in the new Unity Input System. Specifically there were three lines of code all simultaneously being hooked which caused three calls on my method. The fix was commenting out two lines of code. Here's the thread where this is solved, coincidentally found on GitHub help pages, heres the link:
https://github.com/Unity-Technologies/InputSystem/issues/959
the issue is listed as close but its still a problem for me, lol...
The only issue left is that the behavior of selecting the type of button press that I want to use is still acting funky. Mainly the inputs are still simply firing without listening to the type of input I want. I am basically just going to start searching through unity code to find where these choices have impact. If there are no comments/answers in 8 hours I'll accept my own answer because this has technically been answered, it just leads to another question.
I am curious what to use for my game. A timer:
let goodFPS = SKAction.wait(forDuration: 0.01666)
let mainGameRunner = SKAction.run {
//my code is here
}
let toRepeat = SKAction.repeatForever(SKAction.sequence([goodFPS,mainGameRunner]))
inGameHighScore.run(toRepeat,withKey:"mainGame")
or the update function:
override func update(_ currentTime: TimeInterval){
//my code is here
}
Which provides faster more consistent updates?
note: my frame rate is in the range of 45 to 58
First I think you are taking the FPS problem the wrong way around. You cannot "force" a faster frame rate than the device can give you. If you are basing the movements in your game on the assumption that every frame will be consistent, you are doing it wrong. It's actually how they did in the early days because CPUs were so slow and the difference from one generation to the new one wasn't too bad at first. But running an old DOS game on younger hardware will be tricky because the framerate is so high that the whole game mechanic becomes unstable or simply too fast to be playable.
The concept here is to think "over time" and to scale down any action in relation with the time elapsed between two frames.
The update() method gives you that opportunity by providing the current system clock state every frame. By keeping track of the time on the last frame, you can calculate the time difference with the current frame and use that difference to scale down what you are doing.
Using a timer to get the update on a consistent frame rate is not recommended nor practical. You may be calling the update closure at a given time interval, but the code inside that closure is taking time to execute on its own, and depending on your game logic, it might even have different execution times. So maybe the pause timing is consistent, but the code running before and after that pause might not be consistent. Then what happens if you run your game on a slower CPU? The code speed will change even more, making your timing inaccurate.
Another point against using an SKAction for your game loop is simply what they are. An action is an object in memory, meany to be reused by multiple objects. If you are making a "jump" action, for example, it is recommended to store that action somewhere and to reuse the same object every time you need something that "jumps", no matter what node it is. Your game loop is meant to be executed every frame, but not by different objects. Actions are also disposable. Meaning that you can kill an action even while it's running. If you put your game loop in an action, it will probably be run by the SKScene. If you use another action on your scene it becomes a puzzle right away because there are only two ways of removing an action besides letting it come to term: removing all actions or creating the action with an identifier key and use that key to remove any action with that key. If you don't see it already, it then forces you to put identifiers on every action that will be run by the scene and remove them one by one. And them again it leave a door open for a mistake that will get rid of your game loop because, keep it in mind, actions are DISPOSABLE! Then there is also no guarantee that your action will get executed first every single frame.
Why use the update() method? Simply because it is built IN your scene. No matter what, every frame, update() gets called first. THEN, the actions get executed. You cannot flush the update() method accidentally like you can with an action. You don't have to be careful about strong/weak relationships causing memory leaks because you are referring to objects from inside a closure like you do with an action.
Suggested reads:
SKAction API reference
SKScene API reference : read about the frame processing in SpriteKit. It will help you understand how they put everything together at every frame.
I hope it makes things clearer.
I'm pretty sure that SKAction's timing facilities are based on the same game loop that is calling update.
The advantage of SKAction is that it's fire and forget for you, while using update would get awkward with setting and checking a bunch of timer variables.
I don't have a ton of experience with SpriteKit but I do have some experience making games and animations in iOS.
There is a class called CADisplayLink that fires a call to a delegate every time the screen is refreshed, this is a great way to update the screen, either in a game or in an animation, because you can know it will be called every frame and no more.
I'm not sure if SpriteKit uses that class to fire the update method, but I'm sure it uses something similar. This is usually called the run loop.
SKActions run on top of this run loop.
By creating your own run loop using a wait action, not only you're not gaining any benefits, you could be introducing inconsistencies in the way your logic is run.
Imagine that you have your wait action set to 0.01 seconds (I rounded it down for simplicity). If the screen is refreshing faster than you expect, and the action is updated every 0.009 seconds, the first time it's checked, it won't fire because there's a remaining 0.001 second on the wait command, so another 0.009 seconds will pass, and your code will be executed after 0.018 seconds, instead of your desired 0.01. Not only that, but two frames will have passed between the execution.
If you use the update function, you can know that your logic will be executed once every screen refresh, and no more.
I have written below code for Back button event.
void Update()
{
if (Input.GetKey(KeyCode.Escape))
{
SceneManager.LoadScene("PreviousLevel");
}
}
In almost all cases this is fine. But I have found a small issue. When the user pauses the game, this doesn't work. When the user pauses the game, I do Time.timeScale=0. Initially, I gave a thought of modifying pause method and instead of doing Time.timeScale=0, use a bool variable and modify other pause logic accordingly. But then I also realized that I have over 14 co-routines whose logic is heavily dependent on Time.timeScale and modifying those will take a lot of time. They are heavily dependent on time.timeScale.
I wanted to know, is there any other method where I can write back button logic and which is not dependent on Time.timeScale.
It should work, input polling in Unity is not dependent on the time scale.
Try by inserting a Debug.Log inside the condition, and you should see it in the console.
Watch out if you put the if inside FixedUpdate and not Update: in that case it won't work since FixedUpdate is completely skipped when time scale is 0.
However, if you want a "dirty" trick, you can slow the timescale to a very low number, without using 0, i.e.: 10e-8. But use it with a lot of care, since it can lead to unwanted behaviour.
Input is dependent on time scale: GetButton() works normally but GetAxis() works inconsistently, for example getting mouse movement with GetAxis() works as expected, but getting Horizontal and Vertical returns 0 when timeScale is 0. You can get around this by using Input.GetAxisRaw().
It should also be noted that any axis also counts as a button, so you can also use GetButton() on those but the return value will be bool instead of float.
What is the best way to handle this situation on an iPhone device: My program ramps the pitch of a sound between two values. A button pressed calls a method that has a while loop that does the ramping in small increments. It will take some time to finish. In the meantime the user has pressed another button calling the same method. Now I want the loop in the first call to stop and the second to start from the current state. Here is the something like what the method should look like:
-(void)changePitchSample: (float) newPitch{
float oldPitch=channel.pitch;
if (oldPitch>newPitch) {
while (channel.pitch>newPitch) {
channel.pitch = channel.pitch-0.001;
}
}
else if (oldPitch<newPitch) {
while (channel.pitch<newPitch) {
channel.pitch = channel.pitch+0.001;
}
}
}
Now how to best handle the situation where the method is called again? Do I need some kind of mulitthreading? I do not need two processes going at the same time, so it seems there must be some easier solution that I cannot find (being new to this language).
Any help greatly appreciated!
You cannot do this like that. While your loop is running no events will be processed. So if the user pushes the button again nothing will happen before your loop is finished. Also like this you can’t control the speed of your ramp. I’d suggest using a NSTimer. In your changePitchSample: method you store the new pitch somewhere (don’t overwrite the old one) and start a timer that fires once. When the timer fires you increment your pitch and if it is less than the new pitch you restart the timer.
Have a look at NSOperation and the Concurrency Programming Guide. You can first start you operation the increase the pitch and also store the operation object. On the second call you can call [operation cancel] to stop the last operation. Start a second operation to i.e. decrease the pitch and also store the new object.
Btw: What you are doing right now is very bad since you "block the main thread". Calculations that take some time should not be directly executed. You should probably also have a look at NSTimer to make your code independent of the processor speed.
Don't use a while loop; it blocks everything else. Use a timer and a state machine. The timer can call the state machine at the rate at which you want things to change. The state machine can look at the last ramp value and the time of the last button hit (or even an array of UI event times) and decide whether and how much to ramp the volume during the next time step (logic is often just a pile of if and select/case statements if the control algorithm isn't amenable to a nice table). Then the state machine can call the object or routine that handles the actual sound level.
I'm developing a game in which I'm reducing the frame size of an imageView. When I'm introducing a condition using while loop, I'm not able to see the image reducing its size gradually, since it immediately jumps to the final result. So, I want to introduce a delay after every instruction so that I can see the effect of its size reduction little by little.
I can't use timer since it needs me to specify a function to be executed after that time interval.
while(ravanImage1.frame.origin.y>=end.y)
{
ravanImage1.frame=CGRectMake(150,((ravanImage1.frame.origin.y)-5),q,z);
if(ravanImage1.center.y>=300&&ravanImage1.center.y<=370)
{
q=60;
z=60;
ravanImage1.frame=CGRectMake(150,((ravanImage1.frame.origin.y)-5),q,z);
}
if(ravanImage1.center.y>=230&&ravanImage1.center.y<=299)
{
q=40;
z=40;
ravanImage1.frame=CGRectMake(150,((ravanImage1.frame.origin.y)-5),q,z);
}
if(ravanImage1.center.y>=150&&ravanImage1.center.y<=229)
{
q=20;
z=20;
ravanImage1.frame=CGRectMake(150,((ravanImage1.frame.origin.y)-5),q,z);
}
}
I want to introduce delay after every frame change.
Can anybody please help me?
How about using
[NSThread sleepForTimeInterval:]
inbetween every instruction?
If you just need to pause the change during development, use the debugger's breakpoints.
For release, you should use an animation block to make the changes. Create a separate block for each possible change and then set the animation duration to what you'd like.
As a general rule, you never change the frame of a view directly anymore unless you wish it to be instantaneous. Animations exist precisely for this purpose i.e. to create an effect that communicates a change in view state to the user. They're not just eye candy.
If for some reason, you don't want to use animations, you could move each size change into it's own method and then call each method with a timer. You could call the first method, which would set a timer to call the second, which would set a timer to call the third and so on.
So use the timer and give it a function which will take up the right amount of time to execute but have no impact on your display ? Maybe run a long loop of meaningless calculations at the right place in your program ?