Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411496 Posts in 69373 Topics- by 58428 Members - Latest Member: shelton786

April 25, 2024, 06:38:51 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Timestep in platformer game?
Pages: [1] 2
Print
Author Topic: Timestep in platformer game?  (Read 3715 times)
indie11
Level 2
**


View Profile
« on: March 19, 2014, 10:34:16 PM »

I am making a platformer game and having a hard time implementing pixel perfect jumping.

Below is the algorithm I am using for jumping:


Quote
JUMP_SPEED         =      500
GRAVITY            =      25

Update(){

1)      if (SPACEBAR is pressed)
2)         yVelocity  = yVelocity + (JUMP_SPEED * Time.deltaTime)

      
3)      yVelocity -= ( GRAVITY * Time.deltaTime)
      
4)      Vector3 pos = transform.position;
      
5)      for ( i = 0 ; i < Abs (yVelocity) ; i++)
6)         if( ! Colliding ( Sign(yVelocity)  )
7)            transform.position = new Vector3( pos.x , pos.y + Sign( yVelocity ) , pos.z )
      
      
}


The collision function casts rays in a direction(-1 DOWN , 1  UP) and checks if there is a collision ( returns true )


If the game is running on a PC
with FPS = 60 , 1/60 = 0.0167

2 )  0 + ( 500 * 0.0167 ) = 8.33

3 ) 8.33 - ( 25 * 0.0167 ) = 7.91

so yVelocity is 7.91


Now FPS = 45 , 1/60 = 0.022

2 )  0 + ( 500 * 0.022 ) = 11.11

3 ) 11.11 - ( 25 * 0.022 ) = 0.55

so yVelocity is 0.55


My question, shouldn't the player jump be consistent? or is my concept of deltaTime wrong or my algorithm?

If i use a fixed delta time, what are the consequences?

Logged

Endurion
Level 2
**



View Profile WWW
« Reply #1 on: March 19, 2014, 11:15:44 PM »

Since you deal with acceleration there you should try to do without delta time and/or without float. They will always lead to rounding errors.

You could prepare a fixed curve table and use delta time to see which height you should have reached. This way the jump height stays the same.
Logged
HDSanctum
Guest
« Reply #2 on: March 19, 2014, 11:33:56 PM »

The result is different, because even though you took the calculation at the first frame, they were at different points in time (ie, the first frame took longer and more stuff happened in the 45fps example).

Also, unless my calculator skills are bad, I think you typo'd your calculations.

Because the equations you are using are linear, simply iterating the difference from the 60fps example to timestep 0.022 will give the same result as the corrected 45fps example. Same goes for if you were to use a fixed time step, so either way it doesn't matter you should end up with the same result.

But: There could be a difference caused by how long the spacebar is held down, and also a perceivable difference between jumps since you are not zeroing yvelocity when you jump. There may be an imperceivable difference due to rounding errors.
« Last Edit: March 20, 2014, 05:20:40 AM by HD » Logged
indie11
Level 2
**


View Profile
« Reply #3 on: March 20, 2014, 01:53:39 AM »


But: There could be a difference caused by how long the spacebar is held down, and also a perceivable difference between jumps since you are not zeroing yvelocity when you jump. There may be an in-perceivable difference due to rounding errors.

the jump is on BUTTON DOWN so the long press is neglected. I will try zeroing the yVelocity and reply back.

Also, this line of code:

Quote
7)            transform.position = new Vector3( pos.x , pos.y + Sign( yVelocity ) , pos.z )

Do I need to multiple  Delta time with Sign( yVelocity )  as well?
Logged

HDSanctum
Guest
« Reply #4 on: March 20, 2014, 02:08:20 AM »

Try this for line 7:
Code:
transform.position = new Vector3( pos.x , pos.y + yVelocity , pos.z )

Sign(value) restricts value to -1,0,1, which is probably not what you wanted ? You wouldn't want deltaTime there either.

The for loop seems bizarre to me too. Are you having problems detecting collisions?

edit:

Ah I get it, you are checking collisions one pixel at a time. Nasty. Any reason you don't use built in physics?
Logged
Fallsburg
Level 10
*****


Fear the CircleCat


View Profile
« Reply #5 on: March 20, 2014, 02:47:25 AM »

Actually, Mathf.Sign() only returns 1 or -1.  Mathf.Sign(0) == 1
Logged
indie11
Level 2
**


View Profile
« Reply #6 on: March 20, 2014, 02:52:36 AM »

Try this for line 7:
Code:
transform.position = new Vector3( pos.x , pos.y + yVelocity , pos.z )

Sign(value) restricts value to -1,0,1, which is probably not what you wanted ? You wouldn't want deltaTime there either.

The for loop seems bizarre to me too. Are you having problems detecting collisions?

edit:

Ah I get it, you are checking collisions one pixel at a time. Nasty. Any reason you don't use built in physics?

built-in physics is an overhead for the type of game I am making, so I don't really need it.





Actually, Mathf.Sign() only returns 1 or -1.  Mathf.Sign(0) == 1

I am using a custom Sign function which returns values -1,0,1
Logged

dek
Level 1
*



View Profile
« Reply #7 on: March 20, 2014, 02:55:53 AM »

Quote


My question, shouldn't the player jump be consistent? or is my concept of deltaTime wrong or my algorithm?


The problem at hand is that your delta step is dynamic. This is a basic problem that a lot of gamedevs encounter because most tutorials will simply teach them to use dynamic delta times. However, it is fundamentally flawed for anything physics and/or logic related. If you want to find out why, check http://en.wikipedia.org/wiki/Euler_method. Basically, euler integration behaves differently depending on the step size, especially as the steps get bigger.



If i use a fixed delta time, what are the consequences?



Your game engine basically becomes deterministic. That means that it will always perform the same way if it gets the same input. This allows all players to play the same game. If you allow players to play with different time steps, big problems can come up in special cases: http://web.archive.org/web/20080404111108/http://ucguides.savagehelp.com/Quake3/FAQFPSJumps.html
Fixing your timestep will solve a lot of issues. A fixed timestep will sound weird at first because it seems like it might look awkward. However, theres a really simple and clean way to keep your games visual smooth. Essentially you dont render every time step, and instead, you render time steps in a way that makes them appear smooth. How to do this is explained really well here: http://gafferongames.com/game-physics/fix-your-timestep/
Logged

HDSanctum
Guest
« Reply #8 on: March 20, 2014, 05:19:23 AM »

It's even easier to fix time step in Unity, you just put code in FixedUpdate() and use Time.fixedDeltaTime instead.

It's hard to help in this case though, because details of the issue weren't given.

In anycase, looking back over the code in first post:
Code:
  for ( i = 0 ; i < Abs (yVelocity) ; i++)
6)         if( ! Colliding ( Sign(yVelocity)  )
7)            transform.position = new Vector3( pos.x , pos.y + Sign( yVelocity ) , pos.z )

transform.position isn't actually updating across the for loop.
Logged
indie11
Level 2
**


View Profile
« Reply #9 on: March 20, 2014, 10:23:37 AM »

It's even easier to fix time step in Unity, you just put code in FixedUpdate() and use Time.fixedDeltaTime instead.

It's hard to help in this case though, because details of the issue weren't given.

In anycase, looking back over the code in first post:
Code:
  for ( i = 0 ; i < Abs (yVelocity) ; i++)
6)         if( ! Colliding ( Sign(yVelocity)  )
7)            transform.position = new Vector3( pos.x , pos.y + Sign( yVelocity ) , pos.z )

transform.position isn't actually updating across the for loop.

With fixed time step (FixedUpdate), the game doesn't runs as smooth as it does with variable time step (Update)
Logged

J-Snake
Level 10
*****


A fool with a tool is still a fool.


View Profile WWW
« Reply #10 on: March 20, 2014, 10:55:51 AM »

Use visual interpolation and it will look smooth. Google what it is, the idea is also explained in that gafferon article. Since most monitors are 60+ hz I would actually update at 60 hz and use an if-block for update, not the usual unstable while-loop you see all over in articles. That way the updates will be very stable since you only update once in a row. It will be practically as smooth as variable updates with v-sync.

Play TrapThem to convince yourself.

EDIT: I see you are using Unity. In that case you are out of luck with my suggestion, I guess.
« Last Edit: March 20, 2014, 11:08:20 AM by J-Snake » Logged

Independent game developer with an elaborate focus on interesting gameplay, rewarding depth of play and technical quality.<br /><br />Trap Them: http://store.steampowered.com/app/375930
indie11
Level 2
**


View Profile
« Reply #11 on: March 20, 2014, 07:37:14 PM »

Use visual interpolation and it will look smooth. Google what it is, the idea is also explained in that gafferon article. Since most monitors are 60+ hz I would actually update at 60 hz and use an if-block for update, not the usual unstable while-loop you see all over in articles. That way the updates will be very stable since you only update once in a row. It will be practically as smooth as variable updates with v-sync.

Play TrapThem to convince yourself.

EDIT: I see you are using Unity. In that case you are out of luck with my suggestion, I guess.

I just read this thread of yours http://forums.tigsource.com/index.php?topic=21838.15

you  faced the same issue as well? Is there any workaround for this in Unity? Or will I have to switch to some other game-engine  Cry


EDIT: I was wondering if this will work.
Lets say GRAVITY_CONSTANT = 200

in Update

FRAME 1: ( FPS = 60 )
gravity = GRAVITY_CONSTANT * ( 1/60 ) = 3.33

we assume that the value of gravity should be 3.33 in all frames.



FRAME 2: ( FPS = 50)
gravity = GRAVITY_CONSTANT * ( 1/50 ) = 4


Gravity difference Frame 2 and 1  = 4 - 3.33 = 0.67

What if we adjust the value of GRAVITY_CONSTANT every frame such that the gravity is always 3.33?

the equation will be

(GRAVITY_CONSTANT ) * deltaTime = 3.33
GRAVITY_CONSTANT = 3.33 / deltaTime

Will this cause any issues in movement smoothness or anything?





« Last Edit: March 20, 2014, 09:00:35 PM by indie11 » Logged

rosholger
Level 1
*



View Profile
« Reply #12 on: March 21, 2014, 08:06:41 AM »

the equation will be

(GRAVITY_CONSTANT ) * deltaTime = 3.33
GRAVITY_CONSTANT = 3.33 / deltaTime

Will this cause any issues in movement smoothness or anything?

if i understand you correctly that would be the same as doing GRAVITY_CONSTANT = GRAVITY_CONSTANT since, say deltaTime = 1/60 and GRAVITY_CONSTANT = 20 it becomes
GRAVITY_CONSTANT * 1/60 = 0.33...
GRAVITY_CONSTANT = 0.33... / (1/60) = 20

the only thing that would happen to GRAVITY_CONSTANT would be that it would accumulate rounding errors
Logged
indie11
Level 2
**


View Profile
« Reply #13 on: March 21, 2014, 11:16:42 AM »

actually, the gravity will change on every frame with respect to deltaTime.


Gravity Constant = targetGravity / Time.deltaTime;

where, targetGravity = (1/60) * Gravity Constant



our target gravity will always be fixed. If delta Time changes so will the gravity constant

in the end I apply gravity to the position multiplied by deltaTime.

I've implemented this and so far the jumping height is same. Haven't faced any stutter or lag.
Logged

J-Snake
Level 10
*****


A fool with a tool is still a fool.


View Profile WWW
« Reply #14 on: March 21, 2014, 11:19:49 AM »

It's still wrong to approximate it like that, regardless of rounding errors. Theoritically a proper integration can do the job. But I wouldn't want to do that, ideally you still want a fixed timestep for perfectly consistent mechanics.

If I had to stick with unity I would probably try the following: Assuming your platformer has camera controls I would update the camera in a variable step and add not too rough spring behavior to it. So even when the actual game-logic in the gameplay-layer stutters the camera will still be smoother at following the happening. It might probably help the overall impression.
Logged

Independent game developer with an elaborate focus on interesting gameplay, rewarding depth of play and technical quality.<br /><br />Trap Them: http://store.steampowered.com/app/375930
Gregg Williams
Level 10
*****


Retromite code daemon


View Profile WWW
« Reply #15 on: March 21, 2014, 05:45:46 PM »

I always wonder what stutter people actually see with fixed time step that doesn't have visual interpolation. I don't think I've ever really seen much/any assuming the framerate isn't dipping which means its very rare you get an extra update cycle.

Note that I'm also talking about in a rich graphical environment, it can indeed be easy to pick up the rare stutter if your just moving a sprite in a straight line across a solid background or something.
Logged

Trent
Level 0
***


Someday I'll make games!


View Profile WWW
« Reply #16 on: March 23, 2014, 01:13:48 AM »

As someone who's done a lot of rigidbody main characters, I can tell you that the stutter is mostly apparently when the camera is parented to your rigidbody. With your character interpolated- but the rest of the world's bodies not interpolated, the difference in updates really sticks out.

I often lower the fixed update rate for mobile- and it helps to see when things aren't being smoothed properly. You can also increase the fixed update rate depending on how many interactions you have. Just make sure you don't enter the spiral of death. (Updates that are physics heavy are computed slowly- adding to the time required, adding more updates, yadda yadda)

Unity handles death spirals by simply slowing your game down.

Anyway, platformers and Unity can be tricky- especially if you want to depend on the physics engine. Your gameplay will be inaccurate and non-deterministic- which varies in importance depending on your game type.

Hardcore platforming? Fixed updates, fixed maths, and possibly avoiding interpolation might be the best feel.

Fun, actiony, not hardcore? Go nuts with FixedUpdate and everything else can be smoothed.

Frankly, I only find deltatime useful for camera shit, or AI time tracking.

EDIT: Forgot to mention that for a physics platformer- you may want more frequent fixed updates to more closely match the framerate target- as keyboard input changes per frame, and with fixed update you can get missed inputs or duplicated inputs. However, I'm pretty far off topic because the OP wants a deterministic and classic platformer.
« Last Edit: March 23, 2014, 01:26:29 AM by Trent » Logged

indie11
Level 2
**


View Profile
« Reply #17 on: March 23, 2014, 08:40:39 PM »

I am not really using the built-in physics for the platformer game I am making, so I really just needed the Jump fix, rest all is working fine. The tweak I mentioned in the earlier post it kind of working.

The reason I don't want to use FixedUpdate is the android mobile devices, it will be impossible to set a general timestep because of device variation, though it may work on iOS
Logged

cplhasse
Level 1
*


View Profile
« Reply #18 on: March 24, 2014, 08:32:16 AM »

It's still wrong to approximate it like that, regardless of rounding errors. Theoritically a proper integration can do the job. But I wouldn't want to do that, ideally you still want a fixed timestep for perfectly consistent mechanics.

Can you give a reason?
Just implementing a basic RK4 solver is not much work and you can just treat it as a black box if you want. It will give you orders of magnitude more accuracy than Euler integration and you probably won't notice visual differences in repeat simulations. Don't condemn variable framerate physics just because EI is garbage, it's garbage even at fixed framerate but then it's deterministic so no one minds in game applications.

edit: also, as long as you use a method of order >= 2 you will solve the free fall problem exactly, since it's a parabola, which also means that you solve it exactly in each point so it will be stable with respect to variable time steps. There is NO reason to use Euler for that, at least use the trapezoidal rule.
« Last Edit: March 24, 2014, 08:59:11 AM by cplhasse » Logged
wanton
Level 0
*


View Profile
« Reply #19 on: December 09, 2014, 02:27:51 PM »

Use visual interpolation and it will look smooth. Google what it is, the idea is also explained in that gafferon article.
EDIT: I see you are using Unity. In that case you are out of luck with my suggestion, I guess.

Sorry to reply this late and but I think this statement is wrong that Unity can't do interpolation talked in gafferon article.
I've only tried Unity so I'm no expert but I think you can do this in Unity if you are not using Unity's physics.


Just add script and make it's priority highest so that it's Update is called before any other script.
When it's Update is called create your own fixed update loop and accumulator using delta time.
Make this script call your own fixed update, let's say called FixedUpdate2 in all scripts you have registered to be called by this script (maybe create script base class that registers and unregisters script automatically), many times as needed.
Then use your own accumulator to do the interpolation in LateUpdate.

Problem solved.
Logged
Pages: [1] 2
Print
Jump to:  

Theme orange-lt created by panic