Home > Net >  Pygame.colliderect() appropriately stopping movement of 2 movable players (independant) upon collisi
Pygame.colliderect() appropriately stopping movement of 2 movable players (independant) upon collisi

Time:12-26

I'm making a simple arcade game for 2 players to play on 1 keyboard (one with arrows keys, the other with wasd) and have stumbled upon some issues when making appropriate players stop moving when collision between two player-controlable squares is detected. They seem to sort of merge into each other and also when they are moving the opposite directions they always move one way instead of stopping completely. Do you have any ideas on how to fix the issues? (Don't bother about the top collisions, they will be used for something else.)

import pygame
from pygame.locals import *

pygame.init()

vec = pygame.math.Vector2
width = 500
height = 500
FPS = 60

l_blue = (173,216,230)
blue = (0,32,255)
red = (200,0,0)

ACC = 1
GRND_ACC = 0.75
JUMP = 15
GRAV = 0.5
FRIC = -0.15

screen = pygame.display.set_mode((width, height))
screen.fill(l_blue)

class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.size = 30
        self.surf = pygame.Surface((self.size, self.size))
        self.surf.fill(blue)
        self.rect = self.surf.get_rect()
        self.jumps = 0
        self.jumplimit = 2

        self.pos = vec(width / 2, height)
        self.vel = vec(0,0)
        self.acc = vec(0,0)

        self.number = 1

    def move(self):
        self.acc = vec(0,GRAV)

        pressed_keys = pygame.key.get_pressed()
        if self.number == 1:
            if pressed_keys[K_LEFT]:
                if self.jumps == 0:
                    self.acc.x = - GRND_ACC
                else:
                    self.acc.x = -ACC
            if pressed_keys[K_RIGHT]:
                if self.jumps == 0:
                    self.acc.x = GRND_ACC
                else:
                    self.acc.x = ACC
        
        if self.number == 2:
            if pressed_keys[ord('a')]:
                if self.jumps == 0:
                    self.acc.x = -GRND_ACC
                else:
                    self.acc.x = -ACC
            if pressed_keys[ord('d')]:
                if self.jumps == 0:
                    self.acc.x = GRND_ACC
                else:
                    self.acc.x = ACC

        self.acc.x  = self.vel.x * FRIC
        self.vel  = self.acc
        self.pos  = self.vel   0.5 * self.acc

        if self.pos.x > width   self.size / 2:
            self.pos.x = - self.size / 2
        if self.pos.x < -self.size / 2:
            self.pos.x = width   self.size / 2
        if self.pos.y > height:
            self.pos.y = height
            self.jumps = 0
        if self.pos.y < self.size / 2:
            self.pos.y = self.size / 2

        self.rect.midbottom = self.pos

        P1_HU.pos.x = P1.pos.x
        P1_HU.pos.y = P1.pos.y - self.size   2

        P2_HU.pos.x = P2.pos.x
        P2_HU.pos.y = P2.pos.y - self.size   2

        P1_HU.rect.midbottom = P1_HU.pos
        P2_HU.rect.midbottom = P2_HU.pos

    def jump(self):
        self.vel.y = -JUMP

class Hitbox_Up(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.surf = pygame.Surface((P1.size - 4, 4))
        self.surf.fill(red)
        self.rect = self.surf.get_rect()
        self.pos = vec(0,0)

P1 = Player()
P2 = Player()
P1_HU = Hitbox_Up()
P2_HU = Hitbox_Up()

P2.surf.fill(red)
P2.number = 2

all_sprites = pygame.sprite.Group()
all_sprites.add(P1)
all_sprites.add(P2)
all_sprites.add(P1_HU)
all_sprites.add(P2_HU)
        
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP and P1.jumps < P2.jumplimit:
                P1.jumps  = 1
                P1.jump()
            if event.key == pygame.K_w and P2.jumps < P2.jumplimit:
                P2.jumps  = 1
                P2.jump()
    
    screen.fill(l_blue)
    
    if P1.rect.colliderect(P2.rect) or P2.rect.colliderect(P1.rect): 
        if P1.acc.x > 0:
            if P2.acc.x < 0:
                P2.acc.x = 0
                P2.vel.x = 0
            P1.pos.x = P2.pos.x - P1.size
            P2.pos.x = P1.pos.x   P2.size
            P1.vel.x = 0
            P1.acc.x = 0
        elif P1.acc.x < 0 :
            if P2.acc.x > 0:
                P2.acc.x = 0
                P2.vel.x = 0
            P1.vel.x = 0
            P1.acc.x = 0
            P1.pos.x = P2.pos.x   P1.size
            P2.pos.x = P1.pos.x - P2.size
        else:
            if P2.acc.x > 0:
                P2.pos.x = P1.pos.x - P2.size
                P1.pos.x = P2.pos.x   P1.size
            else:
                P2.pos.x = P1.pos.x   P2.size
                P1.pos.x = P2.pos.x - P1.size

    P1.move()
    P2.move()
        
    for entity in all_sprites:
        screen.blit(entity.surf, entity.rect)

    pygame.display.update()
    pygame.time.Clock().tick(FPS)

CodePudding user response:

The movement of the players can be calculated by subtracting the left from the right moment:

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

    def move(self):
        self.acc = vec(0,GRAV)

        pressed_keys = pygame.key.get_pressed()
        acc_x = 0
        if self.number == 1:
            acc_x = pressed_keys[K_RIGHT] - pressed_keys[K_LEFT]
        elif self.number == 2:
            acc_x = pressed_keys[K_d] - pressed_keys[K_a]
        if self.jumps == 0:
            self.acc.x = acc_x * GRND_ACC
        else:
            self.acc.x = acc_x * ACC

        # [...]

To prevent the players from sticking together, you need to check whether P1 is to the left or right of P2. Stop the player moving towards the other player:

while True:
    # [...]

    if P1.rect.colliderect(P2.rect):
        if P1.rect.x < P2.rect.x:
            if P1.acc.x >= 0 and P2.acc.x <= 0:
                P1.rect.right = P2.rect.left = round((P1.rect.right   P2.rect.left) / 2)
            if P1.acc.x > 0:
                P1.acc.x, P1.vel.x = 0, 0
                P1.rect.right = P2.rect.left
            if P2.acc.x < 0:
                P2.acc.x, P2.vel.x = 0, 0
                P2.rect.left = P1.rect.right
        else:
            if P1.acc.x <= 0 and P2.acc.x >= 0:
                P1.rect.left = P2.rect.right = round((P1.rect.left   P2.rect.right) / 2)
            if P1.acc.x < 0:
                P1.acc.x, P1.vel.x = 0, 0
                P1.rect.left = P2.rect.right
            if P2.acc.x > 0:
                P2.acc.x, P2.vel.x = 0, 0
                P2.rect.right = P1.rect.left
        P1.pos.x = P1.rect.centerx
        P2.pos.x = P2.rect.centerx

    # [...]
  • Related