Puzzled by my sprite's unequal +/ - velocity

前端 未结 2 1750
暗喜
暗喜 2021-01-22 11:53

I have two sprites in my game. The zombie sprite works perfectly, moving in all directions at a velocity of 1.0. My player sprite however, despite moves more slowly in the posit

2条回答
  •  花落未央
    2021-01-22 12:20

    Problem

    The sprite group is drawing your sprite using the sprite's rect attribute. A pygame Rect object can only hold integers, so it'll truncate all floating point numbers.

    Let's say you have a x = 5.

    • If you add 1.1: x += 1.1 <=> x = x + 1.1 <=> x = 5 + 1.1 <=> x = 6.1 which will be truncated to x = 6. It have increased by 1.
    • If you subtract 1.1: x -= 1.1 <=> x = x - 1.1 <=> x = 5 - 1.1 <=> x = 3.9 which will be truncated to x = 3. It have decreased by 2.

    In other words: You'll move faster in the left direction than the right (the same principle applies to negative numbers). Here's an example demonstrating it:

    import pygame
    pygame.init()
    
    
    class Player(pygame.sprite.Sprite):
        def __init__(self, group):
            super(Player, self).__init__(group)
            self.image = pygame.Surface((32, 32))
            self.rect = self.image.get_rect()
    
    
    screen = pygame.display.set_mode((100, 100))
    group = pygame.sprite.Group()
    player = Player(group)
    clock = pygame.time.Clock()
    
    while True:
        clock.tick(10)
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RIGHT:
                    x = player.rect.x + 1.1
                    print("Actual x:", x)
                    player.rect.x = player.rect.x + 1.1
                    print("Truncated x:", player.rect.x)
                elif event.key == pygame.K_LEFT:
                    x = player.rect.x - 1.1
                    print("Actual x:", x)
                    player.rect.x = player.rect.x - 1.1
                    print("Truncated x:", player.rect.x)
    
        screen.fill((255, 255, 255))
        group.draw(screen)
        pygame.display.update()
    

    Solution

    Using floating point numbers for position is great; it makes it possible to move a sprite less than a pixel every frame (if your game updates 120 times per second and you want your sprite to move only 30 pixels per second).

    However, you have to compensate for the fact that the rect objects cannot hold them. The most straightforward solution is to have an attribute position which keep track of the position of the sprite in floating point precision. Then at every update change the rect to the position of the attribute. Like this:

    import pygame
    pygame.init()
    
    
    class Player(pygame.sprite.Sprite):
        def __init__(self, group):
            super(Player, self).__init__(group)
            self.image = pygame.Surface((32, 32))
            self.rect = self.image.get_rect()
            self.position = self.rect.x  # Or whatever point of the rect you want the position to be.
    
    
    screen = pygame.display.set_mode((100, 100))
    group = pygame.sprite.Group()
    player = Player(group)
    clock = pygame.time.Clock()
    
    while True:
        clock.tick(10)
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RIGHT:
                    player.position += 1.1
                    player.rect.x = player.position
                elif event.key == pygame.K_LEFT:
                    player.position -= 1.1
                    player.rect.x = player.position
    
        screen.fill((255, 255, 255))
        group.draw(screen)
        pygame.display.update()
    

    I've only showed how this movement works in the x-axis, but it's exactly the same on the y-axis.

提交回复
热议问题