python pygame collision

python - colisión de pared de sprites de pygame



collision (3)

¡Gracias al usuario perezoso! La pregunta que vinculaba me dio una claridad muy necesaria. Me tomó un poco pero lo implementé. Creé una función para la colisión.

def wallColl(self, xvel, yvel, colliders): for collider in colliders: if pygame.sprite.collide_rect(self, collider): if xvel > 0: self.rect.right = collider.rect.left self.xvel = 0 if xvel < 0: self.rect.left = collider.rect.right self.xvel = 0 if yvel < 0: self.rect.bottom = collider.rect.top self.onGround = True self.jumps = 3 self.yvel = 0 if yvel > 0: self.yvel = 0 self.rect.top = collider.rect.bottom

Y luego los llamo en mi función de actualización.

def update(self): self.rect.x += self.xvel # self.walls is an array of sprites. self.wallColl(self.xvel, 0, self.walls) self.rect.y -= self.yvel self.onGround = False self.wallColl(0, self.yvel, self.walls) self.wallCollisions() if self.otherplayers != None: self.playerCollisions() # Gravity if self.onGround == False: self.yvel-=.0066*self.mass self.boundries(highbound, lowbound, leftbound, rightbound) self.down = False

El uso real en mi juego hace que la usabilidad sea casi perfecta. Sin embargo, no es 100%, esta no es una respuesta perfecta.

Estoy trabajando en un juego de plataformas en python y pygame. El código completo se puede encontrar en " https://github.com/C-Kimber/FBLA_Game ". El problema que tengo es con la colisión entre el sprite del jugador y los sprites de la pared, específicamente las esquinas. Cuando el jugador presiona la tecla de movimiento del hacha y salta, el jugador no se mueve o se atasca. Aquí está la muestra de colisión:

def wallCollisions(self): block_hit_list = pygame.sprite.spritecollide(self, self.walls, False) for block in block_hit_list: if self.rect.bottom >= block.rect.top and self.rect.bottom <= block.rect.top + 15: # Moving down; Hit the top side of the wall if self.rect.right > block.rect.left: self.rect.bottom = block.rect.top self.yvel = 0 self.onGround = True self.jumps = 1 elif self.rect.top <= block.rect.bottom and self.rect.top >= block.rect.bottom - 15: # Moving up; Hit the bottom side of the wall self.rect.top = block.rect.bottom self.yvel = 0 if self.rect.right >= block.rect.left and self.rect.right <= block.rect.left + 15: # Moving right; Hit the left side of the wall if self.rect.bottom > block.rect.top+15: self.rect.right = block.rect.left#+1 self.xvel = 0 elif self.rect.left <= block.rect.right and self.rect.left >= block.rect.right - 15: # Moving left; Hit the right side of the wall self.rect.left = block.rect.right#-1 self.xvel = 0 = block.rect.right#-1 self.xvel = 0

He incluido imágenes de lo que está sucediendo y lo que quiero.

He intentado otros métodos, como usar la velocidad como determinante de factos para colisión, pero esto es lo que funciona mejor hasta ahora. Si pudiera proporcionar una solución, sería muy apreciada.


La forma más fácil de manejar las colisiones con paredes es mover primero el reproductor hacia atrás o hacia el sprite a lo largo del eje x, verificar si choca con una pared y luego establecer su self.rect.right = wall.rect.left si se mueve hacia el right o self.rect.left = wall.rect.right si se mueve hacia la izquierda. Luego haces lo mismo con el eje y. Tienes que hacer el movimiento por separado, de lo contrario no sabrías la dirección y cómo restablecer la posición del rect.

import pygame as pg from pygame.math import Vector2 class Player(pg.sprite.Sprite): def __init__(self, x, y, walls): super().__init__() self.image = pg.Surface((30, 50)) self.image.fill(pg.Color(''dodgerblue1'')) self.rect = self.image.get_rect(center=(x, y)) self.pos = Vector2(x, y) # Position vector. self.vel = Vector2(0, 0) # Velocity vector. self.walls = walls # A reference to the wall group. def update(self): self.pos += self.vel self.wall_collisions() def wall_collisions(self): """Handle collisions with walls.""" self.rect.centerx = self.pos.x for wall in pg.sprite.spritecollide(self, self.walls, False): if self.vel.x > 0: self.rect.right = wall.rect.left elif self.vel.x < 0: self.rect.left = wall.rect.right self.pos.x = self.rect.centerx self.rect.centery = self.pos.y for wall in pg.sprite.spritecollide(self, self.walls, False): if self.vel.y > 0: self.rect.bottom = wall.rect.top elif self.vel.y < 0: self.rect.top = wall.rect.bottom self.pos.y = self.rect.centery class Wall(pg.sprite.Sprite): def __init__(self, x, y, w, h): super().__init__() self.image = pg.Surface((w, h)) self.image.fill(pg.Color(''sienna1'')) self.rect = self.image.get_rect(topleft=(x, y)) def main(): screen = pg.display.set_mode((640, 480)) clock = pg.time.Clock() all_sprites = pg.sprite.Group() walls = pg.sprite.Group() wall = Wall(100, 200, 300, 30) wall2 = Wall(230, 70, 30, 300) walls.add(wall, wall2) all_sprites.add(wall, wall2) player = Player(300, 300, walls) all_sprites.add(player) done = False while not done: for event in pg.event.get(): if event.type == pg.QUIT: done = True keys = pg.key.get_pressed() if keys[pg.K_w]: player.vel.y = -3 elif keys[pg.K_s]: player.vel.y = 3 else: player.vel.y = 0 if keys[pg.K_a]: player.vel.x = -3 elif keys[pg.K_d]: player.vel.x = 3 else: player.vel.x = 0 all_sprites.update() screen.fill((30, 30, 30)) all_sprites.draw(screen) pg.display.flip() clock.tick(30) if __name__ == ''__main__'': pg.init() main() pg.quit()


elif self.rect.top <= block.rect.bottom and self.rect.top >= block.rect.bottom - 15: # Moving up; Hit the bottom side of the wall self.rect.top = block.rect.bottom self.yvel = 0

¿No yvel establecerse yvel en un número positivo para que suba?