Search code examples
pythonanimationpygamegame-physics

Smooth Jump over different FPS


I've created a game, but I have problems controlling the jump of the player. This code is a simplified version only showing the jump problem. Keep in mind that in the game itself the FPS may vary in mid jump. I've separated the jump code so it's the easier to identify, and also with the UP/DOWN arrows you can change the FPS to make tests.

Problem

The higher the FPS the smaller the jumps are, and the lower the FPS are the higher the jumps.

Expected Result

The jump reach the same height over many different FPS. Example: 30 and 120 FPS

Code

import pygame
Screen = pygame.display.set_mode((250,300))
Clock = pygame.time.Clock()
X = 50; Y = 250
FPS = 60; Current_FPS = FPS
Move = 480 / Current_FPS; Dir = "Up"

while True:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()

    if pygame.key.get_pressed()[pygame.K_UP]: FPS += 10 / Current_FPS
    elif pygame.key.get_pressed()[pygame.K_DOWN] and FPS > 2: FPS -= 10 / Current_FPS
    pygame.display.set_caption("FPS: "+str(int(FPS)))

    Screen.fill((255,255,255))

    X += 120 / Current_FPS

    #---------------- JUMP CODE ---------------------#

    if Dir == "Up":
        if Move <= 0.0: Dir = "Down"
        else:
            Move -= 10 / Current_FPS
            Y -= Move
    else:

        #RESET \/
        if Y >= 250:
            Dir = "Up"
            X = 50; Y = 250
            Move = 480 / Current_FPS; Dir = "Up"
        #RESET /\

        else:
            Move += 120 / Current_FPS
            Y += Move

    #--------------------------------------------------#

    pygame.draw.circle(Screen,(0,0,0),(int(X),int(Y)),5)
    pygame.display.update()
    Current_FPS = 1000.0 / Clock.tick_busy_loop(FPS)

Solution

  • You should set your initial jump velocity to be independent of frame rate, i.e:

    Move = 480
    

    Note that when you update the velocity (or in your case, it looks, speed) you do need to divide by the frame rate, since you are essentially multiplying by the time interval: v ~ u + a*dt. The same applies when updating the position, so this should be Y += Move / Current_FPS.

    There are a couple of other things worth mentioning. Why do you track the direction variable? Why not just have your variable Move be the velocity. That way you would just need: Y += Move / Current_FPS and have positive/negative values indicate the direction. Also, your gravity is currently a lot stronger on the way down than on the way up, but this could be entirely deliberate!