Hola, bienvenido al foro.
Me he mirado el código y para hacer los arreglos que se me ocurren, habría que replantear un poco el tema de las colisiones.
El problema es que primero compruebas si ha habido colisión entre los coches y el personaje y luego le dices al personaje que se pare. Pero como ha habido la colisión primero, se queda en un estado de colisión permanente ("atrapado").
Una posible solución, para la situación de coches parados, edificios y ese tipo de cosas, es moverlo solo si sabes que en la posición siguiente no va a haber colisión. Pongo un ejemplo a continuación. Es la que suelo utilizar yo, mejorandola un poco: si se va a producir una colisión, hago que el personaje se mueva de uno en uno hasta quedarse pegado. El efecto que provoca no hacer esto, se puede apreciar si se pone una velocidad más grande al siguiente ejemplo (por ejemplo, speed = 6).
El ejemplo es una adaptación de un código que puso hugoruscitti en una entrada del foro que no recuerdo (tengo bastante información del proyecto LosersJuegos almacenada en una carpeta).
- Código: Seleccionar todo
# -*- encoding: utf-8 -*-
import pygame
from pygame.sprite import Sprite
import random
class Caja(Sprite):
def __init__(self, x, y):
Sprite.__init__(self)
self.crear_imagen_representacion()
self.rect.center = x, y
def crear_imagen_representacion(self):
size = random.randint(10, 40)
self.image = pygame.surface.Surface((size, size))
self.image.fill((100, 100, 255))
self.rect = self.image.get_rect()
def draw(self, screen):
screen.blit(self.image, self.rect)
class Personaje(Sprite):
"Personaje rectangular que puede caminar y saltar."
def __init__(self):
Sprite.__init__(self)
self.crear_imagen_representacion()
def crear_imagen_representacion(self):
self.image = pygame.surface.Surface((20, 20))
self.image.fill((100, 255, 100))
self.rect = self.image.get_rect()
self.rect.center = 160, 120
def update(self, cajas):
"Actualiza la posicion del personaje en base al estado del teclado."
teclas = pygame.key.get_pressed()
if teclas[pygame.K_LEFT]:
self.try_move(-1, 0, cajas)
elif teclas[pygame.K_RIGHT]:
self.try_move(1, 0, cajas)
if teclas[pygame.K_UP]:
self.try_move(0, -1, cajas)
elif teclas[pygame.K_DOWN]:
self.try_move(0, 1, cajas)
def draw(self, screen):
"Muestra al personaje en pantalla."
screen.blit(self.image, self.rect)
def try_move(self, x, y, cajas):
dest_rect = pygame.Rect(self.rect.x, self.rect.y, \
self.rect.w, self.rect.h)
#en teoria se puede utilizar Pygame.Rect.copy()
speed = 1
#speed = 6 #efecto no deseado
dest_rect.move_ip(x * speed, y * speed)
collide = False
for caja in cajas:
if dest_rect.colliderect(caja.rect):
collide = True
break
if not collide:
self.rect.move_ip(x * speed, y * speed)
# Programa principal
if __name__ == '__main__':
salir = False
screen = pygame.display.set_mode((320, 240))
personaje = Personaje()
cajas = [Caja(50, 50), Caja(200, 200), Caja(100, 40)]
while not salir:
for evento in pygame.event.get():
if evento.type == pygame.QUIT:
salir = True
elif evento.type == pygame.KEYDOWN:
if evento.key == pygame.K_q:
salir = True
personaje.update(cajas)
screen.fill((100, 100, 100))
for caja in cajas:
caja.draw(screen)
personaje.draw(screen)
pygame.display.flip()
pygame.time.delay(10)
Yo suelo utilizar esta técnica por costumbre (creo que a partir de descubrir que el blit de SDL modificaba los rects si salían fuera de la pantalla) pero hay otras: primero mover y, si hay colisión, retroceder... Y puede que sean mejores, así que si alguien se anima a compartir otras...
Saludos y espero que te sea útil.