0

I am trying to create a spaceship style game that uses delta time.

The code I have is this:

import pygame, sys, time
from math import sin,cos, pi

class Main:
    def __init__(self):
        
        # window setup
        pygame.init()
        self.display_surface = pygame.display.set_mode((1280, 720))
        pygame.display.set_caption('Asteroids')
        self.clock = pygame.time.Clock()

        # groups
        self.all_sprites = pygame.sprite.Group()

        # sprites
        self.player = Player((640,360),self.all_sprites) 

    def run(self):
        while True:
            
            # delta time
            dt = self.clock.tick(60) / 1000 # remove 60 to get unlimited frames 

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

            self.display_surface.fill((10,10,10))
            self.all_sprites.update(dt)
            self.all_sprites.draw(self.display_surface)
            
            pygame.display.update()

class Player(pygame.sprite.Sprite):
    def __init__(self,pos,groups):
        super().__init__(groups)
        self.original = pygame.Surface((40,80))
        self.original.fill('red')
        self.image = self.original
        self.rect = self.image.get_rect(center = pos)

        # rotation
        self.angle = 0
        self.rotation_speed = 300

        # movement
        self.pos = pygame.math.Vector2(self.rect.topleft)
        self.direction = pygame.math.Vector2((0,-1))
        self.speed = 0

        self.max_speed = 1000
        self.velocity = 0
        self.acceleration = 0.5
        self.deceleration = 0.2

    def input(self,dt):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_RIGHT]:
            self.angle += self.rotation_speed * dt      
        if keys[pygame.K_LEFT]:
            self.angle -= self.rotation_speed * dt
        
        if keys[pygame.K_SPACE]: self.velocity += self.acceleration
        else: self.velocity -= self.deceleration
        self.velocity = max(0, min(self.velocity, self.max_speed))

    def rotate(self):
        self.image = pygame.transform.rotozoom(self.original,-self.angle,1)
        self.rect = self.image.get_rect(center = self.rect.center)
        self.pos = pygame.math.Vector2(self.rect.topleft)

    def move(self,dt):
        
        direction = pygame.math.Vector2(cos((self.angle - 90) * pi / 180), sin((self.angle - 90) * pi / 180))
        self.pos += direction * self.velocity # add '* dt' to account for delta time
        self.rect.topleft = (round(self.pos.x), round(self.pos.y))

    def update(self,dt):
        self.input(dt)
        self.rotate()
        self.move(dt)


if __name__ == '__main__':
    main = Main()
    main.run()

It is a spaceship that can rotate and is moved by a direction. If I lock the framerate to 60 and ignore delta time, all of this is working really well. However, if I remove the framerate limited from self.clock in run method of the Main class and add delta time to the player's move method (I added comments in the code), the movement becomes choppy and inconsistent.

I am aware there is a similar question here: pygame delta time causes inconsistent movement but the issue here is different: I am storing the position information in a separate vector (self.pos) for the player and the rect position gets the information from that, so no data should be lost from truncated values.

So, my question would be why the movement is choppy when delta time is used even though the movement position is stored inside of a vector that can store floating point numbers.

Another_coder
  • 728
  • 1
  • 9
  • 23
  • 1
    *"However, if I remove the framerate limited from self.clock in run method of the Main class and add delta time ..."* Why do you do that at all? [`pygame.time.Clock.tick()`](https://www.pygame.org/docs/ref/time.html#pygame.time.Clock) returns the delta time. It can even be called without the optional framerate argument. – Rabbid76 Mar 28 '22 at 20:56
  • I use time.time() because it gets more precise numbers. In this example, I added a clock to test if the game was acting differently when the framerate was capped. In the actual project I didn't include it. – Another_coder Mar 28 '22 at 20:59
  • 1
    But you call `time.time()` twice. A little time elapses between the two calls. I'm almost sure `time.time()` is not more accurate than `tick`. Under the hood they use the same system clock. `pygame.time.Clock.tick()` is precise enough for every use case (except for rocket science). If you want to do something scientifically and physically correct, you can't use pygame at all. – Rabbid76 Mar 28 '22 at 21:00
  • 1
    Note that if you use a very high frame rate, you may reach the limits of floating point precision. If you add a very small number to a very large number, the small number is lost. Try `a = 1` `b = 0.00000000000000001` `print(a+b)` – Rabbid76 Mar 28 '22 at 21:13

0 Answers0