colisiones entre sprites

Consulte acerca de programas, técnicas, algoritmos etc.

colisiones entre sprites

Notapor SingLung » Mié Ago 26, 2009 9:18 pm

Hola,

He estado mirando el foro sobre algun problema similar pero no he encontrado ninguna respuesta que me convenciese

La cuestion es que estoy intentando hacer un tipo de juego a lo GTA1 pero en simplon

me he encontrado con un problema

quiero que cuando el protagonista del juego tope con algun coche o edificio no se mueva en la direccion de esa sprite

El caso es que consigo que se detenga pero luego no vuelve a moverse nunca mas.

Me he basado en el ejemplo del seminario de pygame sobre un juego en el que un mono iba comniendo bananas como si fuese un pacman

No llevo mucho en este mundillo del pygame

Para solventar este problema he probado a hacer un kill de la sprite con la que choca y volverla a mostrar.

asi parece funcionar pero sin embargo ya no se vuelve a colisionar con esa sprite

os dejo un enlace con el codigo y las imagenes comprimidas

http://www.megaupload.com/?d=44ZQK7SZ

Gracias por adelantado
SingLung
 
Mensajes: 2
Registrado: Mié Ago 26, 2009 9:09 pm

Notapor endaramiz » Mié Sep 02, 2009 6:06 pm

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.
Avatar de Usuario
endaramiz
 
Mensajes: 283
Registrado: Vie Ago 31, 2007 9:25 am
Ubicación: Barcelona

Notapor SingLung » Lun Sep 07, 2009 8:38 am

Gracias por la informacion, despues de poner este post y mirando mas codigos cai en la cuenta de hacerlo asi tambien, el tema de comprobar primero que no haya colisiones adonde vas.

Ahora se me plantean otras dudas.

Por ejemplo, si quiero que el personaje entre en algun vehiculo, se que para que lo "conduzca" simplemente le cambio la sprite que tiene que usar y listo eso no es problema, pero como puedo hacerlo para que el personaje solo entre si esta pulsada por ejemplo la tecla 'E'?

He pensado que quiza haya que hacerlo comprobando algun event como cuando se comprueba si se ha pulsado la tecla Esc para salir de la aplicacion y tal, el caso es que no se me ocurre muy bien como podria hacerlo

Muchas gracias

PD: disculpad si mis dudas son de 'noob' pero es la primera vez que intento hacer algo por el estilo
SingLung
 
Mensajes: 2
Registrado: Mié Ago 26, 2009 9:09 pm

Notapor endaramiz » Sab Sep 12, 2009 10:37 am

SingLung escribió:Por ejemplo, si quiero que el personaje entre en algun vehiculo, se que para que lo "conduzca" simplemente le cambio la sprite que tiene que usar y listo eso no es problema, pero como puedo hacerlo para que el personaje solo entre si esta pulsada por ejemplo la tecla 'E'?

He pensado que quiza haya que hacerlo comprobando algun event como cuando se comprueba si se ha pulsado la tecla Esc para salir de la aplicacion y tal, el caso es que no se me ocurre muy bien como podria hacerlo


Aquí la cosa ya se complica un poco. La manera correcta de hacer esto no es simplemente cambiar la imagen sino crear diferentes estados. Para aprender un poco sobre el tema (si es que no lo sabes ya) te aconsejo el artículo "Autómatas y animaciones II" y el ejemplo del cofre.

Para entrar en el coche harían falta 3 estados:
- A pié
- Entrando en el coche (esto se puede omitir pero haría una teletransportación, lo comento porque puede llevar algún que otro quebradero de cabeza implementarlo)
- En coche

Entonces para entrar en el coche cuando se va a pié sería:
Código: Seleccionar todo
Si se pulsa la 'tecla E' entonces:
    Para cada coche dentro de conjunto_de_coches:
        Si distancia_entre(coche, prota) < dist_min entonces:
            prota.estado = en_coche(coche)


Para hacer la distancia puedes utilizar los centros del rect del coche y del prota. Si estás comenzando y no se te da muy bien las matemáticas, te aconsejaría poner la "dist_min" muy pequeña, de manera que el personaje tenga que estar casi pegado a la puerta y así te puedes ahorrar el estado de "Entrando en el coche"

Saludos.
Avatar de Usuario
endaramiz
 
Mensajes: 283
Registrado: Vie Ago 31, 2007 9:25 am
Ubicación: Barcelona


Volver a General

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado