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?