Ayuda con mi intento de maquina de estados

Si tienes alguna duda sobre cómo usar pilas, o tienes problemas para instalar o hacer algo en pilas comentalo aquí.

Ayuda con mi intento de maquina de estados

Notapor borgo66 » Vie Oct 21, 2011 7:56 pm

Hola a todos, nesecito ayuda con el siguiente codigo:
import pygame
from pygame.locals import*
from pygame.sprite import Sprite
import os

ANCHO = 640
ALTO = 480

def load_spritesheet(archivo,filas,columnas):
fullname = os.path.join ('data', archivo)
img=pygame.image.load(fullname).convert()
images=[]
alto=img.get_height()/filas
ancho=img.get_width()/columnas
aux_img=pygame.Surface((ancho,alto))

for i in range(filas):
for j in range(columnas):
aux_img=pygame.Surface((ancho,alto))
area=pygame.Rect(j*ancho,i*alto,ancho,alto)
aux_img.blit(img,(0,0),area)
aux_img=aux_img.convert()
aux_img.set_colorkey(aux_img.get_at((0,0)))
images.append(aux_img)
return images

class Animation(object):
def __init__(self, ima, str_frames = ""):
self.imagenes = ima
self.frames = self.load_frames(str_frames)
self.image = self.imagenes[self.frames[0]]
self.rect = self.image.get_rect()
self.step = 0
self.delay = 0
self.index = self.frames[0]
self.longitud = len(self.frames)

def load_frames(self,frames):
lista = []
frames = frames.split(',')
for i in frames:
lista.append(int(i))
return lista

def set_frame(self, indice):
self.image = self.imagenes[indice]

def update(self, delay = 9):
if self.step >= self.longitud-1:
self.end = True
self.step = 0
self.delay -= 1
if self.delay <= 0:
self.delay = delay
self.step += 1
self.set_frame(self.frames[self.step])

def draw(self,screen):
screen.blit(self.image,self.rect)

class State(object):
def __init__(self,luchador,state_name):
self.luchador = luchador
self.name = state_name

def update(self):
pass

class Intro(State):
def __init__(self, luchador):
State.__init__(self,luchador,"intro")
self.luchador.set_animation('intro')

def update(self):
self.luchador.current_animation.update()

class Guardia(State):
def __init__(self, luchador):
State.__init__(self,luchador,"guardia")
self.luchador.set_animation('guardia')

def update(self):
self.luchador.current_animation.update()


class Saltar(State):
def __init__(self, luchador):
State.__init__(self,luchador,"saltar")
self.luchador.set_animation('saltar')

def update(self):
self.luchador.current_animation.update()


class Luchador(Sprite):
def __init__(self, archivo, filas, columnas):
Sprite.__init__(self)
self.states = {}

self.frames = load_spritesheet(archivo,filas,columnas)
self.x2frames = self.double_sized_images()

self.animations = {'guardia': Animation(self.x2frames,'1,2,3,4,5'),
'saltar': Animation(self.x2frames,'76,77,76'),
'intro': Animation(self.x2frames,'181,182,183,184,185,186,187,188,189,190,191,192,193')}
intro = Intro(self)
saltar = Saltar(self)
guardia = Guardia(self)

self.add_state(intro)
self.add_state(guardia)
self.add_state(saltar)

self.set_state("intro")

def set_animation(self, anim_id):
self.current_animation = self.animations[anim_id]

def get_animation(self,anim_id):
return self.animations[anim_id]


def add_state(self, state):
self.states[state.name] = state

def set_state(self,sname):
self.current_state = self.states[sname]

def double_sized_images(self):
frames2x = []
for i in range (len(self.frames)-1):
frames2x.append(pygame.transform.scale2x(self.frames[i]))
return frames2x

def update(self):
self.current_state.update()

key = pygame.key.get_pressed()
if key[K_a]:
self.set_state("saltar")
if key[K_s]:
self.set_state("guardia")


def draw(self, screen):
self.current_animation.draw(screen)


def main():
quit = False
screen = pygame.display.set_mode((ANCHO, ALTO))

luchador = Luchador("Ryu.png",17,15)

clock = pygame.time.Clock()

while not quit:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit = True

screen.fill((200, 200, 200))

luchador.update()
print luchador.current_state
luchador.draw(screen)

pygame.display.flip()

if __name__ == '__main__':
pygame.init()
main()



Cuando se produce un cambio de estado del personaje, al presionar una tecla, NO se produce el cambio de animacion corespondiente a ese estado, no se si esta claro lo que pregunto.
Por las dudas pueden correr el codigo ustedes:
(la imagen debe estar en la carppeta "data" y el script en el mismo directorio que "data")
http://www.mediafire.com/?q919bsu39200qd7
Desde ya les estare muy agradecido por la ayuda.
borgo66
 
Mensajes: 9
Registrado: Lun Abr 18, 2011 8:37 pm

Re: Ayuda con mi intento de maquina de estados

Notapor MrBB4 » Vie Oct 21, 2011 11:01 pm

Oooook. Me tomó un buen tiempo encotrar el bug, pero ya lo pillé. Resulta que en las clases Intro(), Saltar() y Guardia() se redefine en cada una de ellas cuales son las imagenes correspondientes para el personaje, la cosa es que creaste los estados (siendo el ultimo el de Guradia()), luego las metiste dentro de una lista y las llamate con el metodo update, pero no vuelves a redefinir en ningún otro momento los frames correspondientes a las otras funciones, y como la ultima que creaste fue Guardia() cualquiera de los otros estados llamará a estos mismos frames. Para que te des cuenta por ti mismo deja a Luchador() así:
class Luchador(Sprite):
def __init__(self, archivo, filas, columnas):
Sprite.__init__(self)
self.states = {}

self.frames = load_spritesheet(archivo,filas,columnas)
self.x2frames = self.double_sized_images()

self.animations = {'guardia': Animation(self.x2frames,'1,2,3,4,5'),
'saltar': Animation(self.x2frames,'76,77,76'),
'intro': Animation(self.x2frames,'181,182,183,184,185,186,187,188,189,190,191,192,193')}
intro = Intro(self)
saltar = Saltar(self)
#guardia = Guardia(self)

self.add_state(intro)
#self.add_state(guardia)
self.add_state(saltar)

self.set_state("intro")

················Resto del código················

Ahora en vez de quedarse la animación pegada en Guardia, se quedará pegada en Saltar. Para solucionar esto simplemente debes poner la función luchador.set_animation() dentro de la función set_state(), quedandonos así:
def set_state(self,sname):
self.current_state = self.states[sname]
self.set_animation(sname)


Ahora si. Pero te quedan tres lineas de codigo que se pueden reducir a una sola. Quita la linea que dice self.luchador.set_animation(anim_id) de las clases Intro(), Saltar() y Guardia(), y agrega self.set_animation("intro") en la clase Luchador() despues de self.set_state("intro").
Te aseguro que funciona, ya lo probé.

Cualquier otra cosa, pregunta. Fue un gusto debugear tu codigo.
Suerte en tu proyecto ;)
Avatar de Usuario
MrBB4
 
Mensajes: 49
Registrado: Mar Dic 14, 2010 11:39 pm
Ubicación: Purto Madryn, Chubut, Argentina.

Re: Ayuda con mi intento de maquina de estados

Notapor Barajas » Sab Oct 22, 2011 11:17 am

Que curioso, precisamente ayer estaba explicando eso y su implementación para un juego de peleas XD...

Para ser sincero, me parece que hay una mejor y mas sencilla forma de implementarlos, pero me parece bastante bien hasta donde has llegado :)

Por si te interna, adjunto los ejemplos que había hecho para explicárselo a mis compañeros :).

P.D.
También era el ejemplo con un juego de peleas jeje.. :)
Vi veri universum vivus vici
Avatar de Usuario
Barajas
 
Mensajes: 209
Registrado: Mar Nov 16, 2010 12:06 am

Re: Ayuda con mi intento de maquina de estados

Notapor borgo66 » Lun Oct 24, 2011 7:21 pm

MrBB4 : gracias por responder pero no llego a entender que esta pasando exactamente.No deberia cada estado tomar el control del la variable current_animation del personaje?, no se si probaste hacer esto
en la funcion update del personaje:
def update(self):
key = pygame.key.get_pressed()
if key[K_a]:
self.set_state(Guardia(self))

De esta manera si funciona, creo que eso me confunde.

Barajas: Muchas gracias por el codigo que subiste lo estuve ojeando y creo es bastante similar al mio, lo de funciones en vez de clases para manejar estados ya lo habia pensado pero lo quiero hacer con clases, me parece mas prolijo y extensible sobre todo para usarlo en otros juegos .
Ademas el "modelo" de fsm que use es casi igual al usado por el autor del libro "Beginning Game Development with Pygame"(Will McGugan)
Pero igual si tenes alguna sugerencia, se agradece y sepan disculpar la insistencia pero soy un principiante en el mundo de la programacion.
borgo66
 
Mensajes: 9
Registrado: Lun Abr 18, 2011 8:37 pm

Re: Ayuda con mi intento de maquina de estados

Notapor MrBB4 » Lun Oct 24, 2011 11:01 pm

@Borgo66: No deberia cada estado tomar el control del la variable current_animation del personaje?

La verdad cuando se trata de programación no importa como uno escriba un programa. Claro, existen patrones y formas comunes de hacer las cosas pero eso no quiere decir que haya siempre que seguir un orden especifico de como hacer las cosas. Cada unos escribe su codigo como se le de la gana. Como lo escribí yo era porque como ya habias creado un diccionario dentro del personaje con los frames determinador para cada estado en:
self.animations = {'guardia': Animation(self.x2frames,'1,2,3,4,5'),
'saltar': Animation(self.x2frames,'76,77,76'),
'intro': Animation(self.x2frames,'181,182,183,184,185,186,187,188,189,190,191,192,193')}

me parecio que lo mejor era aprovechar eso y así se ahorraban un par de lineas de codigo. Pero de la forma en que lo hiciste tú tambien es valido. Escribe el programa como se te haga más comodo. Si lo que quieres es mantener todo bien ordenado dentro de clases, pues mantenlo así ;)

Saludos y (nuevamente) suerte en el proyecto.
Avatar de Usuario
MrBB4
 
Mensajes: 49
Registrado: Mar Dic 14, 2010 11:39 pm
Ubicación: Purto Madryn, Chubut, Argentina.

Re: Ayuda con mi intento de maquina de estados

Notapor borgo66 » Jue Oct 27, 2011 6:57 pm

Gracias por responder
borgo66
 
Mensajes: 9
Registrado: Lun Abr 18, 2011 8:37 pm


Volver a Consultas, problemas o bugs.

¿Quién está conectado?

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