3

I'm trying to write a simple game using the Pygame Lib. I coded a very simple behaviour of an "enemy" in order to follow the player.

The problem comes when I run the game and the "enemy" object moves faster when it goes to the right direction and slower when it goes to the left.

I already looked for any number or operator misstyped that can influence the function. Also I tracked the speed and time value (which I use to add or substact "distance") and they don't change (they're supposed to not change).

import os
import sys
import pygame as py
from pygame.locals import *

# Constantes
w = 500
h = 300
clock = py.time.Clock()

active_surf = py.Surface((500, 30))
active_surf.fill((255, 255, 0))

ground_surf = py.Surface((500, 50))
ground_surf.fill((127, 127, 127))

# Clases


class Robbie(py.sprite.Sprite):
    def __init__(self, ):
        py.sprite.Sprite.__init__(self)
        self.image = py.Surface((30, 30))
        self.rect = self.image.get_rect()
        self.rect.bottom = 250
        self.rect.centerx = 230
        self.speed = 0.2

    def move(self, keys, time):
        if self.rect.left >= 0:
            if keys[K_LEFT]:
                self.rect.centerx -= self.speed * time
        if self.rect.right <= w:
            if keys[K_RIGHT]:
                self.rect.centerx += self.speed * time

    def shoot(self, keys, time):
        pass


class Enemy(py.sprite.Sprite):
    def __init__(self):
        py.sprite.Sprite.__init__(self)
        self.image = py.Surface((25, 25))
        self.rect = self.image.get_rect()
        self.rect.bottom = 250
        self.rect.centerx = 260
        self.speed = 0.1

    def move(self, player, time):
        if player.rect.centerx > self.rect.centerx:
            self.rect.centerx += self.speed * time
        if player.rect.centerx < self.rect.centerx:
            self.rect.centerx -= self.speed * time

# Funciones
def img_load(img_name):
    img_path = os.path.join((os.path.dirname(__file__)), "Images", (img_name + ".png"))
    sprite_obj = py.image.load(img_path).convert_alpha()
    return sprite_obj


def main():
    screen = py.display.set_mode((w, h))
    py.display.set_caption("RobbiShoot")
    screen.blit(ground_surf, (0, 250))
    player = Robbie()
    enemy = Enemy()

    while True:
        time = clock.tick(60)
        keys = py.key.get_pressed()

        for events in py.event.get():
            if events.type == QUIT:
                sys.exit()

        screen.blit(active_surf, (0, 220))
        player.move(keys, time)
        enemy.move(player, time)
        screen.blit(player.image, player.rect)
        screen.blit(enemy.image, enemy.rect)
        py.display.flip()
    return 0


if __name__ == '__main__':
    py.init()
    main()

I thought it could be some simple math thing but if it's that, I can't see it.

Gama11
  • 31,714
  • 9
  • 78
  • 100
Pauete Galopa
  • 153
  • 1
  • 1
  • 9
  • 1
    Hi Pauete, welcome. Can you post the whole code instead of only two lines ? – Florian Jan 23 '19 at 12:45
  • Done, I hope it helps to understand more the problem. – Pauete Galopa Jan 23 '19 at 12:50
  • Welcome to Stack Overflow! Thanks for trying to be polite and introducing yourself, however here on Stack Overflow this is not considered necessary, even discouraged. See https://meta.stackexchange.com/questions/2950/should-hi-thanks-taglines-and-salutations-be-removed-from-posts – mkrieger1 Jan 23 '19 at 12:56
  • In my case it's the other way around - it's much faster going to the left than going to the right. – Tobias Brösamle Jan 23 '19 at 13:02
  • Just to be sure, try to wrap `self.speed * time` with parenthesis, and replace your second `if` (`if player.rect.centerx < self.rect.centerx`) by a `elif`. In your current method, it is possible for your two conditions to be True, which could maybe lead to this strange behavior... – olinox14 Jan 23 '19 at 13:04
  • olinox14 I've tried what you said, still having the problem. – Pauete Galopa Jan 23 '19 at 13:08
  • 1
    I think the problem is a conversion with floats and integers. I calculated `new_centerx - old_centerx`. Going to the right, the value was 1 (should have been 1.6), going left it's -2 (should have been -1.6). – Tobias Brösamle Jan 23 '19 at 13:08

1 Answers1

1

That is an issue of casting floating point value to integral values:

def move(self, player, time):
    if player.rect.centerx > self.rect.centerx:
        self.rect.centerx = (self.rect.centerx + self.speed * time + 0.5)
    if player.rect.centerx < self.rect.centerx:
        self.rect.centerx = (self.rect.centerx - self.speed * time + 0.5)

or

def move(self, player, time):
    if player.rect.centerx > self.rect.centerx:
        self.rect.centerx = round(self.rect.centerx + self.speed * time)
    if player.rect.centerx < self.rect.centerx:
        self.rect.centerx = round(self.rect.centerx - self.speed * time)

Note, if you convert 0.1 to an integral value than it is 0, but if you convert 0.9, it is 0, too. The floating point result of the calculation of the x coordinate has to be rounded up at 0.5.
In the code of the answer, the x coordinate is always truncated, this cause that the position tends to the left.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • It works and now I think I see the problem. Thanks!. PD: Could I explicitly convert all values to float to avoid rounding? – Pauete Galopa Jan 23 '19 at 13:21
  • 1
    @PaueteGalopa You've to round somewhere, because `screen.blit` works with `int`, so you have to convert a floating point coordinate . But you can store `floats` in the classes to improve the accuracy of the calculations and convert the position when you draw the objects. But note, [`pygame.Rect`](https://www.pygame.org/docs/ref/rect.html) consists of `int`s, too. I would prefer to do the calculations with [`pygame.math.Vector2`](https://www.pygame.org/docs/ref/math.html#pygame.math.Vector2). – Rabbid76 Jan 23 '19 at 13:24