def __init__(self): """Constructor""" # Partes del cuerpo self.__bounds = py.Rect(118, 431, 0, 0) self.__feet = py.Rect(0, 0, 18, 4) self.__body = py.Rect(0, 0, 16, 28) # Refertente a animator self.__animator = Animator() self.__animator.add_animation("idle", 0, "mario/mario_idle", 1, 2) self.__bounds.width, self.__bounds.height = self.__animator.add_animation( "walk", 150, "mario/mario_walk", 2, 2) self.__animator.add_animation("onStairs", 100, "mario/mario_stair", 2, 2) self.__bounds.y -= self.__bounds.height # Velocidad actual self.__vx, self.__vy = 0, 0 # Velocidad total self.__hSpeed = 2 self.__vSpeed = 7 # Referente a las plataformas self.__onGround = False self.__gravity = 1 self.__onLadder = False # Referente a los gráficos self.__facingLeft = False # Indica si el objeto está vivo self.__alive = True
def __init__(self): """Constructor""" self.__inimator = Animator() self.__bounds = Rect(250, 0, 0, 0) self.__bounds.size = self.__inimator.add_animation( "moving", 500, "peach/peach", 2, 2) self.__bounds.bottom = 79 # Elementos necesarios para mostrar el mensaje de HELP cada cierto tiempo self.__timer = Timer(550) self.__help = load_img("misc/help", 2) self.__showHelp = True
def __init__(self): """Constructor""" random.seed() # Configuración del cuerpo del objeto. self.__bounds = Rect(85, 0, 0, 0) self.__bounds.bottom = 127 # Configuración del objeto 'Animator'. self.__animator = Animator() self.__bounds.width, self.__bounds.height = self.__animator.add_animation( "angry", 500, "kong/kong_angry", 2, 2) self.__animator.add_animation("take_barrel", 750, "kong/kong_take_barrel", 2, 2) self.__animator.add_animation("idle", 0, "kong/kong_idle", 1, 2) self.__animator.play_animation("angry", 1) # Array de barriles. self.__barrels = Array()
def __init__(self, _x, _y): # Crea un nuevo objeto del tipo 'Animator' del motor PixelSmash self.__animator = Animator() # Crea un nuevo cuerpo para el objecto con la posición que hemos pasado # como parámetro, pero aún no le damos un tamaño. self.__bounds = Rect(_x, _y, 0, 0) # Añadimos una nueva animación al objecto animador y usamos el tamaño # del objeto devuelvo para terminar de configurar el cuerpo de nuestro # objecto. self.__bounds.size = self.__animator.add_animation( "fall", 300, "barrel/barrel_fall", 2, 2) # Añadimos una nueva animación a nuestro objeto animador, aunque esta vez # no necesitamos actualizar el tamaño de nuestro objeto. self.__animator.add_animation("move", 300, "barrel/barrel_move", 2, 2) # Velocidad que tendrá el objeto. # VX -- Velocidad actual horizontal # VY -- Velocidad actual vertical self.__vx, self.__vy = 1, 0 # Constante para modificar la velocidad actual del objeto self.__speed = 3 # Gravedad que se aplicará al objeto self.__gravity = 1 # La velocidad vertical del objeto no podrá ser superior # a la velocidad máxima self.__maxFallSpeed = 5 # Comprueba si el objeto sobre alguna plataforma self.__onGround = False # Guarda la plataforma que está tocando el objeto self.__oldPlatform = None # Si el objeto no está vivo, el sistema lo borrará self.__alive = True
def __init__(self): self.played_new_animation = False # An object of type animator is created self.animator = Animator() # In order to render the animation, a 'body' is needed. This body, among # other things, will indicate the area where you want the animation to be # redrawn and will also serve to check for collisions with other objects. self.bounds = py.Rect(WIDTH // 2, HEIGHT // 2, 0, 0) # We add two animations to the object (We add two animations because it # would not make sense to try an animation manager with only one animation. # You wouldn't even need an animation manager for a single animation). self.bounds.width, self.bounds.height = self.animator.add_animation( "animation_1", 250, "image", 2, 2) self.animator.add_animation("animation_2", 1000, "mario_flip", 2, 2) # Play animation #1 self.animator.play_animation("animation_1", 1)
class Peach(object): """Objeto que representa a la princesa Peach""" def __init__(self): """Constructor""" self.__inimator = Animator() self.__bounds = Rect(250, 0, 0, 0) self.__bounds.size = self.__inimator.add_animation( "moving", 500, "peach/peach", 2, 2) self.__bounds.bottom = 79 # Elementos necesarios para mostrar el mensaje de HELP cada cierto tiempo self.__timer = Timer(550) self.__help = load_img("misc/help", 2) self.__showHelp = True def update(self, _dt): """Actualiza todos los elementos del objeto. Parámetros: _dt -- Tiempo en milisegundos que ha transcurrido desde la última vez que se llamó el método.""" self.__inimator.update(_dt) self.__timer.update(_dt) # Muestra u oculta el MSG de HELP cada vez que el temporizador emite un # pulso. if self.__timer.getTick(): self.__showHelp = not self.__showHelp def render(self, _screen): """Dibuja todos las partes que componen el objeto en la pantalla. Parámetros: _screen -- Superficie donde se dibujarán los elementos.""" self.__inimator.render(_screen, self.__bounds) # Dibuja o no el mensaje de HELP en función del valor de la bandera # 'showHelp'. if self.__showHelp: _screen.blit(self.__help, (290, 25))
class Kong(object): """Objeto que representa a Donkey Kong""" def __init__(self): """Constructor""" random.seed() # Configuración del cuerpo del objeto. self.__bounds = Rect(85, 0, 0, 0) self.__bounds.bottom = 127 # Configuración del objeto 'Animator'. self.__animator = Animator() self.__bounds.width, self.__bounds.height = self.__animator.add_animation( "angry", 500, "kong/kong_angry", 2, 2) self.__animator.add_animation("take_barrel", 750, "kong/kong_take_barrel", 2, 2) self.__animator.add_animation("idle", 0, "kong/kong_idle", 1, 2) self.__animator.play_animation("angry", 1) # Array de barriles. self.__barrels = Array() def update(self, _dt, _level, _player): """Actualiza todos los componentes del objeto. Parámetros: _dt -- Tiempo en milisegundos que ha transcurrido desde que se ejecutó este método por última vez. _level -- Nivel del juego, este objeto no necesita procesar el nivel, pero sí lo debe pasar hacía los barriles ya que éstos sí lo necesitan procesar. _player -- Jugador (Mario) al igual que pasaba con el nivel, el objeto no es necesario para el buen funcionamiento del mono (Donkey Kong), pero sí es necesario pasarlo a los barriles.""" self.__animator.update(_dt) self.__manageAnimations() # Actualiza la lista de barriles self.__barrels.update(_dt, _level.getFloor()) # Si el jugador choca con algún barril if self.__barrels.intersect(_player.getBounds()): _player.setAlive(False) def render(self, _screen): """Dibuja en la pantalla todos los componentes del objeto. Parámetros: _screen -- Superficie donde se dibujarán los componentes.""" self.__animator.render(_screen, self.__bounds) self.__barrels.render(_screen) def __manageAnimations(self): """Gestiona las distintas animaciones que tiene el objeto. No hace falta explicar qué hace cada parte porque el nombre de los métodos son lo suficientemente descriptivos.""" if self.__animator.animationHasEndedPlaying("take_barrel"): self.__animator.resetCurrentAnimation() self.__barrels.add_element(Barrel(111, 104)) self.__animator.play_animation("angry", random.randrange(1, 4)) elif self.__animator.animationHasEndedPlaying("angry"): self.__animator.resetCurrentAnimation() self.__animator.play_animation("take_barrel", 1)
class Player(object): """Representa a Super Mario dentro del juego""" def __init__(self): """Constructor""" # Partes del cuerpo self.__bounds = py.Rect(118, 431, 0, 0) self.__feet = py.Rect(0, 0, 18, 4) self.__body = py.Rect(0, 0, 16, 28) # Refertente a animator self.__animator = Animator() self.__animator.add_animation("idle", 0, "mario/mario_idle", 1, 2) self.__bounds.width, self.__bounds.height = self.__animator.add_animation( "walk", 150, "mario/mario_walk", 2, 2) self.__animator.add_animation("onStairs", 100, "mario/mario_stair", 2, 2) self.__bounds.y -= self.__bounds.height # Velocidad actual self.__vx, self.__vy = 0, 0 # Velocidad total self.__hSpeed = 2 self.__vSpeed = 7 # Referente a las plataformas self.__onGround = False self.__gravity = 1 self.__onLadder = False # Referente a los gráficos self.__facingLeft = False # Indica si el objeto está vivo self.__alive = True def render(self, _screen): """Si está vivo, dibuja el objeto en la pantalla. Parámetros: _screen -- Superficie donde se dibujará el objeto""" if self.__alive: self.__animator.render(_screen, self.__bounds, self.__facingLeft) def update(self, _dt, _level): """Si el personaje está vivo, actualiza todos los componentes. Parámetros: _dt -- Tiempo que ha transcurrido en milisegundos desde la última vez que se llamó a este método. _level -- Referencia al nivel del juego para saber donde están las plataformas y las escaleras.""" if self.__alive: self.__animator.update(_dt) self.__manageAnimations() self.__applyGravity() self.__controls() self.__move() self.__updateFeet() self.__updateBody() self.__checkPlatformsCollision(_level) self.__checkLadders(_level) def __applyGravity(self): """Si el personaje no está tocando ninguna plataforma, aplicar gravedad para que caíga al suelo.""" if not self.__onGround: self.__vy += self.__gravity else: self.__vy = 0 def __controls(self): """Gestiona las pulsaciones del teclado y realiza una función diferente dependiendo de la tecla que se haya pulsado.""" key = py.key.get_pressed() if key[py.K_RIGHT]: # Flecha derecha self.__vx = self.__hSpeed self.__facingLeft = False elif key[py.K_LEFT]: # Flecha izquierda self.__vx = -self.__hSpeed self.__facingLeft = True else: # Ninguna flecha de dirección pulsada self.__vx = 0 # Si se ha pulsado la tecla espacio y además el personaje está sobre el suelo if key[py.K_SPACE] and self.__onGround: self.__onGround = False self.__vy = -self.__vSpeed # Si el personaje está en frente de una escalera y se pulsa la tecla de # dirección arriba. if key[py.K_UP] and self.__onLadder: self.__onGround = False self.__vy = -self.__hSpeed # Si el personaje está en frente de una escalera pero pulsa la tecla de # dirección hacía abajo. elif key[py.K_DOWN] and self.__onLadder: self.__vy = self.__hSpeed else: # Si el personaje no está sobre ninguna escalera o no se está pulsando # arriba o abajo. self.__onGround = True def __move(self): """Mueve al personaje en base a la velocidad actual""" self.__bounds.move_ip(self.__vx, self.__vy) def __manageAnimations(self): """Gestiona las animaciones del jugador en base a los distintos eventos que se den por ejemplo, que el jugador esté parado o que esté en frente de una escalera.""" if self.__onLadder: self.__animator.play_animation("onStairs") if self.__vy == 0: self.__animator.enableUpdating(False) else: self.__animator.enableUpdating(True) else: if self.__vx == 0: self.__animator.play_animation("idle") else: self.__animator.play_animation("walk") self.__animator.enableUpdating(True) def __checkPlatformsCollision(self, _level): """Comprueba que el jugador choque contra alguna de las piezas del suelo para poder saber si el jugador está sobre el suelo o no. Parámetros: _level -- Referencia al nivel. En el nivel están guardadas todas las piezas del suelo.""" self.__onGround = False for platform in _level.getFloor(): if self.__feet.colliderect(platform): if self.__vy > 0: self.__bounds.bottom = platform.top self.__onGround = True def __checkLadders(self, _level): """Comprueba que el jugador esté en frente de alguna escalera. Parámetros: _level -- Referencia al nivel. El nivel guarda la posición de todas las escaleras del juego.""" self.__onLadder = False for ladder in _level.getLadders(): if self.__body.colliderect(ladder): self.__onLadder = True self.__onGround = True # Estos dos métodos actualizan las distintas partes del cuerpo en base a # los 'bounds'. No es necesario crear estas subpartes del cuerpo para que # el juego funcione correctamente, pero sí añade algo de realismo. Si # estas partes no estuvieran definidas, el personaje estaría sobre el suelo # con tan solo tocar una plataforma con la cabeza y, estaría en frente de # una escalera aunque la imagen únicamente tuviera un píxel en frente. def __updateFeet(self): self.__feet.x, self.__feet.y = self.__bounds.x + 2, self.__bounds.y + 28 def __updateBody(self): self.__body.x, self.__body.y = self.__bounds.x + 4, self.__bounds.y # Getters & Setters def getBounds(self): return self.__body def setAlive(self, _alive): self.__alive = _alive
class Barrel(object): """Objeto que representa un barril dentro del juego. Parámetros: _x -- Posición X donde se colocará inicialmente el barril. _y -- Posición Y donde se colocará inicialmente el barril.""" def __init__(self, _x, _y): # Crea un nuevo objeto del tipo 'Animator' del motor PixelSmash self.__animator = Animator() # Crea un nuevo cuerpo para el objecto con la posición que hemos pasado # como parámetro, pero aún no le damos un tamaño. self.__bounds = Rect(_x, _y, 0, 0) # Añadimos una nueva animación al objecto animador y usamos el tamaño # del objeto devuelvo para terminar de configurar el cuerpo de nuestro # objecto. self.__bounds.size = self.__animator.add_animation( "fall", 300, "barrel/barrel_fall", 2, 2) # Añadimos una nueva animación a nuestro objeto animador, aunque esta vez # no necesitamos actualizar el tamaño de nuestro objeto. self.__animator.add_animation("move", 300, "barrel/barrel_move", 2, 2) # Velocidad que tendrá el objeto. # VX -- Velocidad actual horizontal # VY -- Velocidad actual vertical self.__vx, self.__vy = 1, 0 # Constante para modificar la velocidad actual del objeto self.__speed = 3 # Gravedad que se aplicará al objeto self.__gravity = 1 # La velocidad vertical del objeto no podrá ser superior # a la velocidad máxima self.__maxFallSpeed = 5 # Comprueba si el objeto sobre alguna plataforma self.__onGround = False # Guarda la plataforma que está tocando el objeto self.__oldPlatform = None # Si el objeto no está vivo, el sistema lo borrará self.__alive = True def render(self, _screen): """Dibuja el objeto en la pantalla. Parámetros: _screen -- Superficie donde se dibujará el objeto.""" self.__animator.render(_screen, self.__bounds) def update(self, _dt, _resources_needed): """Actualiza todos los componentes del objeto. Parámetros: _dt -- Tiempo que ha transcurrido (MS) desde que se llamó a método por última vez. _resources_needed -- Parámetro utilizado por el componente 'array' de PixelSmash. No tiene ningún tipo definido. Es decir, este parámetro podría significar cualquier cosa que utilice el objeto.""" self.__animator.update(_dt) self.__manageAnimations() self.__applyGravity() self.__move() self.__checkFloor(_resources_needed) self.__checkBounds() def __manageAnimations(self): """Gestiona las animaciones del objeto 'animator' en base a las propiedades actuales del objeto.""" if self.__vx != 0: # Si el objeto se está moviendo horizontalmente. self.__bounds.size = self.__animator.play_animation("move") else: # Si el objeto tiene una determinada velocidad de caída. if self.__vy >= self.__maxFallSpeed: self.__animator.play_animation("fall") self.__falling = True def __checkFloor(self, _floor): """Comprueba todas las plataformas del nivel para ver si el barril está sobre alguna de ellas. Parámetros: _floor -- Este objeto está compuesto por todas las piezas individuales del suelo.""" self.__onGround = False for floor in _floor: # Si el cuerpo del objeto está chocando con alguna parte del suelo if self.__bounds.colliderect(floor): self.__onGround = True self.__bounds.bottom = floor.top # Guarda la plataforma con la que ha chocado para que solo # se ejecute una única vez el evento. if floor != self.__oldPlatform: self.__oldPlatform = floor if self.__vy == self.__maxFallSpeed: self.__speed *= -1 def __applyGravity(self): """Aplica la gravedad al objeto""" if not self.__onGround: self.__vy += self.__gravity else: self.__vy = 0 if self.__vy > self.__maxFallSpeed: self.__vy = self.__maxFallSpeed def __move(self): """Mueve el objeto""" if not self.__onGround: self.__vx = 0 else: self.__vx = self.__speed self.__bounds.move_ip(self.__vx, self.__vy) def __checkBounds(self): """Comprueba que el objeto no se haya salido de la pantalla. Si se ha salido, se marcará para ser eliminado.""" if self.__bounds.top > 600: self.__alive = False # Getters & Setters def isAlive(self): return self.__alive def getBounds(self): return self.__bounds
class TestAnimator(object): def __init__(self): self.played_new_animation = False # An object of type animator is created self.animator = Animator() # In order to render the animation, a 'body' is needed. This body, among # other things, will indicate the area where you want the animation to be # redrawn and will also serve to check for collisions with other objects. self.bounds = py.Rect(WIDTH // 2, HEIGHT // 2, 0, 0) # We add two animations to the object (We add two animations because it # would not make sense to try an animation manager with only one animation. # You wouldn't even need an animation manager for a single animation). self.bounds.width, self.bounds.height = self.animator.add_animation( "animation_1", 250, "image", 2, 2) self.animator.add_animation("animation_2", 1000, "mario_flip", 2, 2) # Play animation #1 self.animator.play_animation("animation_1", 1) def update(self, _dt): # It is MANDATORY to update this object so that the animation plays correctly. self.animator.update(_dt) if self.animator.ended and not self.played_new_animation: # If the previous animation has finished, play animation No. 2 twice self.animator.play_animation("animation_2", 2) self.played_new_animation = True def render(self, _screen): # To draw the animator object on the screen it is necessary to use the # body that we have defined before. This body will indicate the exact # zone where we want to render the frames of the animation and it will # also indicate the body of the animation to be able to check the # collisions. The '_facing_left' parameter is optional and indicates for # which side you will be looking at the image. If its value is 'true' # the object will be looking to the left if it is 'true' the object will # be looking to the right. By default this parameter takes the value # 'false', that is unless we indicate otherwise the object will be facing # right. self.animator.render(_screen, self.bounds, _facing_left=False)