Foros del Web » Programando para Internet » Python »

Problema con la gravedad en Pygame

Estas en el tema de Problema con la gravedad en Pygame en el foro de Python en Foros del Web. Hola de nuevo! Bueno, el titulo lo dice todo. Despues de probar algunas cosas con el modulo Pygame, me he atascado con la gravedad. Esta ...
  #1 (permalink)  
Antiguo 14/06/2016, 13:56
 
Fecha de Ingreso: diciembre-2009
Ubicación: Spain
Mensajes: 180
Antigüedad: 10 años, 1 mes
Puntos: 9
Problema con la gravedad en Pygame

Hola de nuevo!

Bueno, el titulo lo dice todo. Despues de probar algunas cosas con el modulo Pygame, me he atascado con la gravedad. Esta claro que es algo tan sencillo como manejar la coordenada Y. De esa forma nuestro personaje desciende si no colisiona con un objeto definido.

Dos problemas me han surgido:

1. Que se queda pegado al objeto que colisiona y no obedece a la ordenes del teclado.

2. Si aumentamos la gravedad, nuestro personaje se detiene al colisionar. Pero deja unos pixeles de distancia el objeto que colisiona.

Este es el codigo que seguro tendra errores:

Código Python:
Ver original
  1. import pygame
  2. from pygame.locals import *
  3. import sys
  4. import os
  5.  
  6. os.environ['SDL_VIDEO_CENTERED'] = '1'
  7. pygame.init()
  8.  
  9. ANCHO = 1024
  10. ALTO = 768
  11.  
  12. # pygame.NOFRAME sin margenes
  13. ventana = pygame.display.set_mode((ANCHO, ALTO))
  14.  
  15. NEGRO = (0, 0, 0)
  16. AZUL = (0, 0, 255)
  17. VERDE = (0, 192, 0)
  18.  
  19. # Clases -----------------------------------------------------------------------
  20. class Pared(pygame.sprite.Sprite):
  21.     def __init__(self, x, y, largo, alto, color):
  22.         pygame.sprite.Sprite.__init__(self)
  23.         self.image = pygame.Surface((largo, alto))
  24.         self.image.fill(color)
  25.         self.rect = self.image.get_rect()
  26.         self.rect.centerx = ANCHO/2
  27.         self.rect.centery = ALTO/2
  28.         self.velocidad = 0  
  29.     def update(self):
  30.         ventana.blit(self.image, self.rect)
  31.  
  32. class Personaje(pygame.sprite.Sprite):
  33.     def __init__(self, x, y):
  34.         pygame.sprite.Sprite.__init__(self)
  35.         self.image = pygame.Surface((64, 64))
  36.         self.image.fill(VERDE)
  37.         self.rect = self.image.get_rect()
  38.         self.rect.x = x
  39.         self.rect.y = y
  40.        
  41.     def __str__(self):
  42.         return ('Coordenada X: ' + str(self.rect.x) + ' Coordenada Y: ' + str(self.rect.y))
  43.        
  44.     def mover(self, x,y):
  45.         self.rect.move_ip(x, y)
  46.        
  47.     def colision(self, other):
  48.         return self.rect.colliderect(other)
  49.    
  50.     def update(self):
  51.         ventana.blit(self.image, self.rect)
  52.        
  53. class Enemigos(pygame.sprite.Sprite):
  54.     pass
  55. # ------------------------------------------------------------------------------
  56.        
  57. muro = Pared(0, 0, 800, 32, AZUL)
  58. heroe = Personaje(100, 100)
  59.  
  60.  
  61.  
  62. def run():
  63.     fps = pygame.time.Clock()
  64.     salir = False
  65.     heroe.velocidad = 4
  66.     gravedad = 8
  67.     while not salir:
  68.         for evento in pygame.event.get():
  69.             # con raton: pygame.MOUSEBUTTONDOWN
  70.             if evento.type == pygame.QUIT:
  71.                 salir = True
  72.                
  73.          # Movimiento del personaje          
  74.         oldx = heroe.rect.x
  75.         oldy = heroe.rect.y
  76.         tecla = pygame.key.get_pressed()
  77.        
  78.         if tecla[K_LEFT] and not tecla[K_RIGHT]:                        
  79.             heroe.mover(-heroe.velocidad, 0)          
  80.                                                                    
  81.         elif tecla[K_RIGHT] and not tecla[K_LEFT]:
  82.             heroe.mover(heroe.velocidad, 0)          
  83.         elif tecla[K_UP] and not tecla[K_DOWN]:
  84.             heroe.mover(0, -heroe.velocidad)        
  85.         elif tecla[K_DOWN] and not tecla[K_UP]:
  86.             heroe.mover(0, heroe.velocidad)
  87.            
  88.         # Muestra las coordenadas del personaje por consola
  89.         print(heroe)
  90.        
  91.         # Gravedad
  92.         if not heroe.colision(muro):
  93.             heroe.mover(0, gravedad)
  94.        
  95.         # Colision con el muro
  96.         if heroe.colision(muro):
  97.             heroe.rect.x = oldx
  98.             heroe.rect.y = oldy
  99.        
  100.         # Evita que salga por los extremos de la ventana
  101.         if heroe.rect.left < 0:
  102.             heroe.rect.left = 0
  103.         elif heroe.rect.right > ANCHO:
  104.             heroe.rect.right = ANCHO
  105.         elif heroe.rect.top < 0:
  106.             heroe.rect.top = 0
  107.         elif heroe.rect.bottom > ALTO:
  108.             heroe.rect.bottom = ALTO
  109.            
  110.            
  111.        
  112.         # Actulizacion y dibujo de pantalla
  113.         ventana.fill(NEGRO)
  114.         muro.update()
  115.         heroe.update()
  116.         pygame.display.flip()
  117.         fps.tick(30)
  118. run()
  119. pygame.quit()
  120. sys.exit()

Seguro que debe ser algo tan sencillo como poner algun ELSE en alguna parte del script. Pero no me funcionan.

Si en la variable gravedad ponemos 12, si que se queda bien asentado en el objeto muro. Si ponemos 8, no.
  #2 (permalink)  
Antiguo 14/06/2016, 23:58
Avatar de razpeitia
Moderador
 
Fecha de Ingreso: marzo-2005
Ubicación: Monterrey, México
Mensajes: 7.321
Antigüedad: 14 años, 10 meses
Puntos: 1360
Respuesta: Problema con la gravedad en Pygame

Pues no era tan fácil como ponerle un else.

Algunas cosas:
1. Maneja velocidades por separado
2. Maneja contadores de tiempo o de fps
3. Maneja estados

Código Python:
Ver original
  1. import pygame
  2. from pygame.locals import *
  3. import sys
  4. import os
  5.  
  6. os.environ['SDL_VIDEO_CENTERED'] = '1'
  7. pygame.init()
  8.  
  9. ANCHO = 1024
  10. ALTO = 768
  11.  
  12. # pygame.NOFRAME sin margenes
  13. ventana = pygame.display.set_mode((ANCHO, ALTO))
  14.  
  15. NEGRO = (0, 0, 0)
  16. AZUL = (0, 0, 255)
  17. VERDE = (0, 192, 0)
  18.  
  19. # Clases -----------------------------------------------------------------------
  20. class Pared(pygame.sprite.Sprite):
  21.     def __init__(self, x, y, largo, alto, color):
  22.         pygame.sprite.Sprite.__init__(self)
  23.         self.image = pygame.Surface((largo, alto))
  24.         self.image.fill(color)
  25.         self.rect = self.image.get_rect()
  26.         self.rect.centerx = ANCHO/2
  27.         self.rect.centery = ALTO/2
  28.         self.velocidad = 0
  29.     def update(self):
  30.         ventana.blit(self.image, self.rect)
  31.  
  32. class Personaje(pygame.sprite.Sprite):
  33.     def __init__(self, x, y):
  34.         pygame.sprite.Sprite.__init__(self)
  35.         self.image = pygame.Surface((64, 64))
  36.         self.image.fill(VERDE)
  37.         self.rect = self.image.get_rect()
  38.         self.rect.x = x
  39.         self.rect.y = y
  40.         self.velocidad_x = 0
  41.         self.velocidad_y = 0
  42.         self.state_y = 'falling'
  43.         self.jump_timer = 0
  44.         self.falling_timer = 0
  45.  
  46.     def __str__(self):
  47.         return ('Coordenada X: ' + str(self.rect.x) + ' Coordenada Y: ' + str(self.rect.y))
  48.  
  49.     def mover_x(self):
  50.         self.rect.move_ip(self.velocidad_x, 0)
  51.  
  52.     def mover_y(self):
  53.         self.rect.move_ip(0, self.velocidad_y)
  54.  
  55.     def mover(self):
  56.         self.rect.move_ip(self.velocidad_x, self.velocidad_y)
  57.  
  58.     def colision(self, other):
  59.         return self.rect.colliderect(other)
  60.  
  61.     def update(self):
  62.         ventana.blit(self.image, self.rect)
  63.  
  64. class Enemigos(pygame.sprite.Sprite):
  65.     pass
  66. # ------------------------------------------------------------------------------
  67.  
  68. muro = Pared(0, 0, 800, 32, AZUL)
  69. heroe = Personaje(100, 100)
  70.  
  71.  
  72.  
  73. def run():
  74.     fps = pygame.time.Clock()
  75.     salir = False
  76.     heroe.velocidad_y = 4
  77.     heroe.velocidad_x = 0
  78.     gravedad = 8
  79.     myfont = pygame.font.SysFont("monospace", 15)
  80.  
  81.     while not salir:
  82.         for evento in pygame.event.get():
  83.             # con raton: pygame.MOUSEBUTTONDOWN
  84.             if evento.type == pygame.QUIT:
  85.                 salir = True
  86.  
  87.          # Movimiento del personaje
  88.         tecla = pygame.key.get_pressed()
  89.  
  90.         if tecla[K_q]:
  91.             break
  92.  
  93.         if tecla[K_LEFT] and not tecla[K_RIGHT]:
  94.             heroe.velocidad_x = -4
  95.         elif tecla[K_RIGHT] and not tecla[K_LEFT]:
  96.             heroe.velocidad_x = 4
  97.         else:
  98.             heroe.velocidad_x = 0
  99.         heroe.mover_x()
  100.         if heroe.colision(muro):
  101.             if heroe.velocidad_x > 0:
  102.                 heroe.rect.right = muro.rect.left
  103.             if heroe.velocidad_x < 0:
  104.                 heroe.rect.left = muro.rect.right
  105.  
  106.         # Estado a velocidad
  107.         if heroe.state_y == 'falling':
  108.             heroe.velocidad_y = heroe.falling_timer * gravedad
  109.             heroe.falling_timer += 0.15
  110.         elif heroe.state_y == 'jumping':
  111.             heroe.velocidad_y = (heroe.jump_timer / 15.0) * -gravedad
  112.             heroe.jump_timer -= 1
  113.         elif heroe.state_y == 'standing':
  114.             heroe.velocidad_y = 0
  115.             heroe.jump_timer = 30
  116.             heroe.falling_timer = 0
  117.  
  118.         if tecla[K_UP]:
  119.             if heroe.state_y == 'standing':
  120.                 heroe.state_y = 'jumping'
  121.         else:
  122.             if heroe.state_y == 'jumping':
  123.                 heroe.state_y = 'falling'
  124.         if heroe.jump_timer <= 0:
  125.             heroe.state_y = 'falling'
  126.  
  127.         heroe.mover_y()
  128.         if heroe.colision(muro):
  129.             if heroe.state_y == 'falling':
  130.                 heroe.rect.bottom = muro.rect.top
  131.                 heroe.state_y = 'standing'
  132.             elif heroe.state_y == 'jumping':
  133.                 heroe.rect.top = muro.rect.bottom
  134.         if heroe.state_y == 'standing':
  135.             heroe.velocidad_y = 1
  136.             heroe.mover_y()
  137.             ground = heroe.rect.bottom > ALTO
  138.             wall_colision = heroe.colision(muro)
  139.             heroe.velocidad_y = -1
  140.             heroe.mover_y()
  141.             heroe.velocidad_y = 0
  142.  
  143.             if not wall_colision and not ground:
  144.                 heroe.state_y = 'falling'
  145.  
  146.         # Evita que salga por los extremos de la ventana
  147.         if heroe.rect.left < 0:
  148.             heroe.rect.left = 0
  149.         elif heroe.rect.right > ANCHO:
  150.             heroe.rect.right = ANCHO
  151.         if heroe.rect.top < 0:
  152.             heroe.rect.top = 0
  153.         elif heroe.rect.bottom > ALTO:
  154.             heroe.rect.bottom = ALTO
  155.             heroe.state_y = 'standing'
  156.  
  157.         # Actulizacion y dibujo de pantalla
  158.         ventana.fill(NEGRO)
  159.         muro.update()
  160.         heroe.update()
  161.         # render text
  162.         if heroe.state_y == 'jumping':
  163.             label = myfont.render("%s %.03f" % (heroe.state_y, heroe.jump_timer), 1, (0,255,0))
  164.         elif heroe.state_y == 'falling':
  165.             label = myfont.render("%s %.03f" % (heroe.state_y, heroe.falling_timer), 1, (0,255,0))
  166.         else:
  167.             label = myfont.render("%s" % (heroe.state_y,), 1, (0,255,0))
  168.         ventana.blit(label, (800, 100))
  169.         pygame.display.flip()
  170.         fps.tick(30)
  171. run()
  172. pygame.quit()
  173. sys.exit()
  #3 (permalink)  
Antiguo 15/06/2016, 11:25
 
Fecha de Ingreso: diciembre-2009
Ubicación: Spain
Mensajes: 180
Antigüedad: 10 años, 1 mes
Puntos: 9
Respuesta: Problema con la gravedad en Pygame

Muchas gracias por las correcciones. Ahora me tocara estudiar las partes que has añadido/modificado. Si, tenias razon...no era tan simple como un ELSE.

EDITO:

Se me ocurrio traduccir al castellano algunas variables y me empezo a dar errores. Lo que me dio que pensar que son atributos de la clase sprite.Sprite. Y claro, no veo informacion sobre los mismos. En la pagina oficial si hablan de los metodos de esta clase. De la clase sprite.Sprite conozco los clasicos: self.image y self.rect

state_y
'jumping'
'falling'
'standing'
self.jump_timer
self.falling_timer

Última edición por Koan; 15/06/2016 a las 13:38
  #4 (permalink)  
Antiguo 15/06/2016, 22:36
Avatar de razpeitia
Moderador
 
Fecha de Ingreso: marzo-2005
Ubicación: Monterrey, México
Mensajes: 7.321
Antigüedad: 14 años, 10 meses
Puntos: 1360
Respuesta: Problema con la gravedad en Pygame

Si quieres aprender mas sobre programación de video juegos, puedes mirar:
http://gameprogrammingpatterns.com/ (Solo disponible en Ingles).

Para las traducciones:
state_y -> 'estado_y'
'jumping' -> 'saltando'
'falling' -> 'cayendo'
'standing' ->'parando'
self.jump_timer -> 'temporizador_de_salto'
self.falling_timer -> 'temporizador_de_caida'
  #5 (permalink)  
Antiguo 16/06/2016, 12:31
 
Fecha de Ingreso: diciembre-2009
Ubicación: Spain
Mensajes: 180
Antigüedad: 10 años, 1 mes
Puntos: 9
Respuesta: Problema con la gravedad en Pygame

Cita:
Iniciado por razpeitia Ver Mensaje
Si quieres aprender mas sobre programación de video juegos, puedes mirar:
http://gameprogrammingpatterns.com/ (Solo disponible en Ingles).

Para las traducciones:
state_y -> 'estado_y'
'jumping' -> 'saltando'
'falling' -> 'cayendo'
'standing' ->'parando'
self.jump_timer -> 'temporizador_de_salto'
self.falling_timer -> 'temporizador_de_caida'
Ayer mismo hice esas traducciones y no me funcionaba el salto. Hoy si. No se, cosas de la programacion. La duda que tenia es que no fueran atributos de la clase sprite.Sprite de la que hereda. Ya veo que no.

Gracias por el enlace. Pero del ingles ni jota. Como comente alguna vez, si me dedicara a esto como profesion aprenderia dicha lengua y quizas otras. Pero es un hobby que tengo.

Por si interesa a alguien, paso unos enlaces sobre Pygame en español (edita alguno si crees que no cumple alguna norma del foro).

http://www.nachocabanes.com/python/pygame.php
http://inventwithpython.com/es/
http://www.pythondiario.com/search/label/juegos
http://programarcadegames.com/index.php
http://razonartificial.com/tutoriales-pygame/
http://pitando.net/tag/pygame/

Última edición por Koan; 16/06/2016 a las 12:59
  #6 (permalink)  
Antiguo 16/06/2016, 20:56
Avatar de razpeitia
Moderador
 
Fecha de Ingreso: marzo-2005
Ubicación: Monterrey, México
Mensajes: 7.321
Antigüedad: 14 años, 10 meses
Puntos: 1360
Respuesta: Problema con la gravedad en Pygame

Aquí hay otro en español por si quieres aprender mas:
http://www.losersjuegos.com.ar/
  #7 (permalink)  
Antiguo 17/06/2016, 11:43
 
Fecha de Ingreso: diciembre-2009
Ubicación: Spain
Mensajes: 180
Antigüedad: 10 años, 1 mes
Puntos: 9
Respuesta: Problema con la gravedad en Pygame

Cita:
Iniciado por razpeitia Ver Mensaje
Aquí hay otro en español por si quieres aprender mas:
http://www.losersjuegos.com.ar/
Gracias. Esa pagina es de las primeras que conoci. Aunque su autor, Hugo, se ha pasado a su modulo Pilasengine y a abandonado un poco pygame. De todas formas, hay articulos muy interesantes, claro.

Dejo otro enlace (esta vez en ingles) de un modulo para usar animaciones mas facilmente con pygame (el modulo se llama pyganim):

http://inventwithpython.com/pyganim/

Etiquetas: funcion, pygame
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 01:48.