0

For some reason the movement of my sprite is only diagonally up and left when pressing A, diagonally down and right when pressing D, and W/S just don't work despite the correct vectors being given to move in any direction. Here's where the inputs are handled:

class Operator:
    PLAYER = 'player'
    COMPUTER = 'computer'

    def __init__(self, type, AI=None):
        self.type = type
        self.AI = AI

    def handle(self, entity):
        keys = pygame.key.get_pressed()
        direction = Vector(0, 0)

        if self.type == Operator.PLAYER:
            if keys[pygame.K_w]:
                direction += Vector(0, -1)

            if keys[pygame.K_s]:
                direction += Vector(0, 1)

            if keys[pygame.K_a]:
                direction += Vector(-1, 0)

            if keys[pygame.K_d]:
                direction += Vector(1, 0)

        if direction:
            entity.move(direction)

        return bool(direction)

And here is the relevant sprite code:

class Sprite(pygame.sprite.Sprite):
    @property
    def x(self):
        return self._x_coordinate

    @x.setter
    def x(self, value):
        self._x_coordinate = self.rect.centerx = wrap(value,
                                                      WIDTH,
                                                      -self.width)

    @property
    def y(self):
        return self._y_coordinate

    @x.setter
    def y(self, value):
        self._y_coordinate = self.rect.centery = wrap(value,
                                                      HEIGHT,
                                                      -self.height)

    @property
    def position(self):
        return Vector(self.x, self.y)

    @position.setter
    def position(self, value: Vector):
        self.x, self.y = value

    @property
    def width(self):
        return self.rect.width

    @property
    def height(self):
        return self.rect.height

    def set_surface(self, surface):
        self.image = surface

class Entity(Sprite):
    @property
    def colliding(self):
        return pygame.sprite.spritecollide(self,
                                           sprites(self),
                                           False)

    @property
    def velocity(self):
        return self.internal_velocity + self.external_velocity

    @property
    def angle(self):
        return self.velocity.as_polar()[1]

    def __init__(self, size, position, operator=None, image=None, color='#FF4C4C'):
        super().__init__()

        if image:
            image = pygame.image.load(image)

        self.image = pygame.Surface(image.get_size() if image else size)
        self.rect = self.image.get_rect()

        self.position = position
        self.operator = operator
        self.internal_velocity = Vector(0, 0)
        self.external_velocity = Vector(0, 0)

        if not image:
            self.image.fill(color)
        else:
            self.image.blit(image, ORIGIN)

    def draw(self, surface):
        if camera.on_screen(self):
            surface.blit(self.image,
                         (self.x - self.width / 2, self.y - self.height / 2))

        if debugging:
            offset = Vector()
            offset.from_polar((20, self.angle))

            pygame.draw.line(surface,
                             '#54CE0E',
                             self.position,
                             self.position + offset,
                             1)

    def update(self):
        if self.operator and not self.operator.handle(self):
            self.internal_velocity *= FRICTION
            self.external_velocity *= FRICTION

        self.position += self.velocity

        if self.internal_velocity.x and 0.2 > self.internal_velocity.x > -0.2:
            self.internal_velocity.x = floor(self.internal_velocity.x)

        if self.internal_velocity.y and 0.2 > self.internal_velocity.y > -0.2:
            self.internal_velocity.y = floor(self.internal_velocity.y)

    def move(self, vector: Vector):
        self.internal_velocity += vector

        if self.internal_velocity.length() > MOVE_SPEED:
            self.internal_velocity.scale_to_length(MOVE_SPEED)

    def set_operator(self, operator):
        self.operator = operator

def wrap(number, maximum, minimum=0):
    return (number - minimum) % (maximum - minimum + 1) + minimum

def floor(number):
    if number > 0:
        return math.floor(number)
    elif not number:
        return 0
    else:
        return math.floor(abs(number)) * -1

I can provide the whole program, but it's a little over 350 lines so let me know if it's needed.

khelwood
  • 55,782
  • 14
  • 81
  • 108
Cubli
  • 39
  • 5
  • 2
    Yeaaaaaaah hmmmmm maybe don't provide the whole code. What you provided is already very long. I suspect you won't find many people interested in going through your code and debugging it for you. Could you try to reproduce the issue with a much smaller code? See [mre] for advice. – Stef Dec 22 '21 at 22:46
  • Please trim your code to make it easier to find your problem. Follow these guidelines to create a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). – Community Dec 31 '21 at 15:00

1 Answers1

0

Something weird seems to be going on in your Entiry.update function.

 if self.operator and not self.operator.handle(self):
      self.internal_velocity *= FRICTION
      self.external_velocity *= FRICTION

Firstly self.operator is not a boolean. Second, self.operator.handle returns true if both x and y values are non zero. This means friction is only applied when entity is not moving, which does not make any sense. But taking the whole if statement into account friction is always being applied because self.operator will always have a value. But all of this would only change scale not the direction.

The real problem seems to be the typo, again in update function. I have no idea what is happening here but I am pretty sure this is the problem because if these evaluate to true, your self.internal_velocity vector changes direction. If your vector has has friction applied to it and thus has a value between -1 and 1, it will get floored right down to 0. Assuming your FRICTION constant is less than 1. Which is why I am assuming it does not work.

if self.internal_velocity.x and 0.2 > self.internal_velocity.x > -0.2:

and

if self.internal_velocity.y and 0.2 > self.internal_velocity.y > -0.2: