1

I have a program that detects mask collisions and moves the player to prevent it overlapping. It program works by moving the player by the dimensions of the area that is overlapped depending on the direction the player is moving.

But when I press the left/right and up/down keys at the same (left + down, ...), the player doesn't overlap, but also moves in the opposite direction of the left/right key that is being pressed (left + down -> right + dowbn): example (text shows the direction)

I've tried making the player go in the proper direction when its on the top or bottom of the mask and not calling player.move() when on the outer edge of the mask, but each is either buggy or doesn't work.

import pygame
import sprites

SCREEN_HEIGHT, SCREEN_WIDTH = 800, 800
running = True

pygame.init()

screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
clock = pygame.time.Clock()

player = sprites.Block((100, 100))
block2 = sprites.Block((100, 100))
blocks = pygame.sprite.Group(block2)

block2.rect.topleft = 150, 150

while running:
    events = pygame.event.get()

    screen.fill((100, 100, 100))
    for event in events:
        if event.type == pygame.QUIT:
            running = False

    player.move(screen.get_rect())

    def check_collisions():
        collided_blocks = pygame.sprite.spritecollide(player, blocks, False, pygame.sprite.collide_mask)

        if collided_blocks:
            for block in collided_blocks:
                offset = (player.rect.x - block.rect.x, player.rect.y - block.rect.y)
                connected_comps = block.mask.connected_components()
                intersection_masks = player.mask.overlap_mask(block.mask, offset).connected_components()

                for comp in connected_comps:
                    for i_mask in intersection_masks:
                        offset = (0, 0)

                        if i_mask.overlap(comp, offset):
                            i_mask_rect = i_mask.get_bounding_rects()[0]

                            i_mask_rect.topleft = block.rect.x + i_mask_rect.x, block.rect.y + i_mask_rect.y

                            displacement = [i_mask_rect.width * -player.direction[0],
                                            i_mask_rect.height * -player.direction[1]]

                            player.rect.move_ip(displacement[0], displacement[1])
                            return

    check_collisions()

    blocks.draw(screen)
    screen.blit(player.image, player.rect)

    clock.tick(144)
    pygame.display.flip()

sprites module:

import pygame


class Block(pygame.sprite.Sprite):
    def __init__(self, size):
        self.image = pygame.image.load("flappy_bird.png").convert_alpha()
        self.rect = self.image.get_rect()
        self.mask = pygame.mask.from_surface(self.image)

        self.direction = (0, 0)
        self.speed = 1

        super().__init__()

    def move(self, screen_rect):
        pressed_keys = pygame.key.get_pressed()

        self.direction = (0, 0)
        if pressed_keys[pygame.K_w]:
            self.rect.move_ip(0, -self.speed)
            self.direction = 0, -1
        if pressed_keys[pygame.K_s]:
            self.rect.move_ip(0, self.speed)
            self.direction = 0, 1
        if pressed_keys[pygame.K_a]:
            self.rect.move_ip(-self.speed, 0)
            self.direction = -1, 0
        if pressed_keys[pygame.K_d]:
            self.rect.move_ip(self.speed, 0)
            self.direction = 1, 0

        self.rect.clamp_ip(screen_rect)

expoodo
  • 65
  • 1
  • 8

2 Answers2

1

pygame.key.get_pressed() returns a sequence with the state of each key. If a key is held down, the state for the key is 1, otherwise 0. So you can calculate the resulting movement when 2 keys are pressed with pressed_keys[pygame.K_d] - pressed_keys[pygame.K_a] and pressed_keys[pygame.K_s] - pressed_keys[pygame.K_w]:

class Block(pygame.sprite.Sprite):
    # [...]

    def move(self, screen_rect):
        pressed_keys = pygame.key.get_pressed()

        self.direction = (
            pressed_keys[pygame.K_d] - pressed_keys[pygame.K_a], 
            pressed_keys[pygame.K_s] - pressed_keys[pygame.K_w])
        
        self.rect.move_ip(
            self.direction[0] * self.speed
            self.direction[1] * self.speed)
        self.rect.clamp_ip(screen_rect)
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
0

Check when they're overlapping and if they do then instead of moving the player based on their movement move them to the blocks position minus the players width.

Bup
  • 11
  • 2