Pygame.colliderect() 在碰撞时适当地停止 2 个可移动玩家(独立)的移动

Pygame.colliderect() appropriately stopping movement of 2 movable players (independant) upon collision

我正在制作一款简单的街机游戏,供 2 名玩家在 1 个键盘上玩(一个使用箭头键,另一个使用 wasd),并且在两个玩家发生碰撞时让适当的玩家停止移动时偶然发现了一些问题-检测到可控方块。它们似乎有点融合在一起,而且当它们向相反的方向移动时,它们总是朝一个方向移动而不是完全停止。您对如何解决这些问题有任何想法吗? (别管顶撞,它们会被用来做别的事情。)

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)

玩家的移动可以通过右矩减去左矩来计算:

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

        # [...]

为了防止玩家粘在一起,你需要检查P1是在P2的左边还是右边。阻止玩家向另一个玩家移动:

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

    # [...]