Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Framerate Difficulty Problem #2

Open
09jlardinois opened this issue Aug 9, 2018 · 5 comments
Open

Framerate Difficulty Problem #2

09jlardinois opened this issue Aug 9, 2018 · 5 comments

Comments

@09jlardinois
Copy link

Hi, I'm not sure what's going on, but it seems that when I play my completed game on crappy systems, it's significantly easier because it seems like the bird doesn't jump as high or fall as fast. I'm assuming this is an issue with framerate and deltatime.

I noticed this while testing on a Dell Inspiron laptop. ( parents' computer )

I got scores higher than 30 several times, and only died because I made the bird fall to end the test. It really could have gone on indefinitely.

The narrowed "jump / fall range" makes it very easy to slip through small pipe gaps. Is it a known phenomenon for framerate to affect a game this way, or is this just all a fluke?

Is there a way to compensate for low framerates in the gravity code?

@coltonoscopy
Copy link
Member

coltonoscopy commented Aug 9, 2018 via email

@snekbaev
Copy link

@coltonoscopy what would be the recommendation when it comes to 60+ FPS? It's quite unplayable at 144 :)

@sharifmarat
Copy link

@snekbaev Limit dt with some min_dt: https://github.com/games50/fifty-bird/pull/15/files

@snekbaev
Copy link

snekbaev commented Jun 1, 2020

@sharifmarat can't recall the details now, but I think the suggested approach wasn't good enough. I remember reading some article about fixing the frame rate issues using different methods and pros and cons of each. One of the better ones was to use the accumulator approach. I think I've implemented some variation of that

@yak1r
Copy link

yak1r commented Oct 9, 2023

A few years late to the party, but I didn't see this mentioned anywhere, so FWIW I'll explain why you experienced this issue and share a fix for it. Hopefully it will help future students:

**tl;dr: ** Pull Request #21 will fix this issue.

We'll start by discussing basic physics (probably mandatory knowledge for game developers anyway):
Our bird's location is defined by x and y values. The units of these values are pixels.
The speed, dy, is given in units of pixels / second (so, for example, if our bird has speed of dy = 20, it means it will pass 20 pixels every second).
Now we get to the gravity. Gravity is just acceleration towards the positive direction of the y-axis. Acceleration measures the degree in which the speed changes (so, for example, if gravity is 20, it means the bird's speed is increased by 20 pixels / second every second),
so if the speed's units are pixels / second, the acceleration units are pixels / second / second or pixels / second ^ 2.

now, when we calculate the bird's speed this is done correctly, we take the gravity and multiply it by the elapsed time, dt, giving us the speed:

self.dy = self.dy + GRAVITY * dt

And indeed, when looking at the units alone, (pixels / second ^ 2) * seconds = pixels / second and those are indeed the units of speed as expected.

The mess starts when we try and add this speed to the bird's y position:

self.y = self.y + self.dy

Notice how we take the bird's current y position and add the speed to it without multiplying it by the time elapsed, dt.
This makes no sense in physics. You can't simply add two measurements of different units!

To demonstrate how this affects users who run on a frame rate which is not 60 fps, let's consider two users, user A and user B.
User A runs the game on 60fps (dt of every frame is 1 / 60 = 0.01666). User B runs the game on 120fps (dt of every frame is 1 / 120 = 0.008333).
Now, let's check the bird's y position after 0.2 seconds (so 12 frames for user A and 24 frames for user B), by running this simple code (written in python for my convenience :) ):

GRAVITY = 20  # As defined in fifty-bird
def simulate_frames(num_frames: str, dt: float) -> float:
    y = 136  # As defined in fifty-bird
    dy = 0  # Starting y speed is 0
    for i in range(num_frames):
        dy += GRAVITY * dt
        y += dy
    return y

print(simulate_frames(num_frames=6, dt=1 / 60))  # User A
print(simulate_frames(num_frames=12, dt=1 / 120))  # User B

Running the above code prints:

>>> print(simulate_frames(num_frames=12, dt=1 / 60))  # User A
162.0
>>> print(simulate_frames(num_frames=24, dt=1 / 120))  # User B
186.0

so over the same timeframe, user A saw the bird move 26 pixels, and user B saw it moving 50 pixels, almost twice as much!

How can we fix this?
simply comply to the laws of physics, and multiply the speed by dt before adding it to the bird's y position:

function Bird:update(dt)
    self.dy = self.dy + GRAVITY * dt

    if love.keyboard.wasPressed('space') or love.mouse.wasPressed(1) then
        self.dy = -5
        sounds['jump']:play()
    end

    self.y = self.y + self.dy * dt
end

However, this will cause the bird to move much slower, and we will need to set new values.
There is no right answer here, but from playing around with different values I put it as GRAVITY = 750 and dy = -200 for jumping, that seemed similar enough to what's shown in the lecture's video.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants