class Enemy(Object): "Representa un enemigo del videojuego." def __init__(self, game, name, sprites, x, y, player): Object.__init__(self, game.stage) self.game = game self.name = name self.init_animations() self.image = self.animation.get_image() self.x = x self.y = y self.rect = pygame.Rect(self.x, self.y, 10, 10) self.flip = True self.change_state(Stand(self)) self.dy = 0 self.sprites = sprites self.last_attack = (0, 0) self.player = player self.shadow = shadow.Shadow(self) # Collision when is trowed self.collision_fly = None self.update_animation() if player: self.update() self.energy = energy.EnergyModel(name, 100, game.on_enemy_energy_model_change) else: Object.update(self) self.z = -self.y def init_animations(self): self.animation = Animation('enemies/' + self.name) def update(self): if self.are_in_camera_area(): self.state.update() Object.update(self) self.z = -self.y self.shadow.update_from_parent() def kill(self): Object.kill(self) self.shadow.kill() def update_animation(self): self.image = self.animation.get_image(self.flip) return self.animation.advance() def change_state(self, state): self.state = state def set_collision(self, power=1): """Define una zona como 'colisionable' para golpear a otros""" (_, _, w, h) = self.image.get_rect() cw, ch = 50, 10 if self.flip: x = self.x - cw - w/2 + cw + 15 else: x = self.x + w/2 - cw - 15 y = self.y + self.dy - h / 2 Object.set_collision(self, (x, y), cw, ch) self.collision_power = power def do_collision_check(self, new_state_if_occur): "Evalúa si recibe un golpe, si es así altera su estado." collision = self._get_collision_receive() if collision: power, self.flip = collision if self.energy.must_die(): self.change_state(HardHit(self)) else: if power == 1 or power == 3: self.change_state(HitStand(self)) elif power == 2: self.change_state(HitStand(self, 2)) elif power == 5: # special self.change_state(HardHit(self, -16, 8)) else: self.change_state(HardHit(self)) self.create_hit() def _get_collision_receive(self): """Determina si en ese momento es golpeado por otro personaje.""" e = self.game.player if self.sensitive and e.collision_rect and same_z_dist(e, self): if e.collision_rect.colliderect(self.get_screen_rect()): try: new_flip = (self.x - e.x) / abs(self.x - e.x) except: new_flip = 1 return e.collision_power, new_flip == 1 def get_collision_send(self): "Retorna True si detecta que ha golpeado a un personaje" e = self.player if e.sensitive and self.collision_rect and same_z_dist(e, self): if self.collision_rect.colliderect(e.get_screen_rect()): return True def create_hit(self, dy=0): """Genera un explosión que indica la existencia de un golpe.""" dx = -40 if self.flip else 0 x = self.x + dx y = self.y - 100 + dy self.sprites.add(Hit(x, y)) def can_take_by_player(self): "Informa al jugador si este enemigo se puede sujetar." return isinstance(self.state, (Stand, WalkToPlayer)) def see_to_player(self): self.flip = True if self.rect.x > self.player.rect.x else False def is_close_to_player(self): "Informa si el enemigo está muy cerca del protagonista." a, b = self, self.player return same_z_dist(a, b) and common.get_dist(a, b) < 100
class Player(Object): def __init__(self, game, control, sprites, datadir, x=100, y=350): Object.__init__(self) self.game = game self.name = 'shaolin' self.datadir = datadir self.init_animations(datadir) self.image = self.animation.get_image() self.rect = pygame.Rect(self.x, self.y, 10, 10) self.flip = False self.change_state(Stand(self)) self.x = x self.y = y self.dy = 0 self.control = control self.sprites = sprites self.last_attack = (0, 0) self.update() self.id = ID(self.name, 100) def init_animations(self, datadir): self.animation = Animation(datadir + '/player/') def update(self): self.control.update() self.state.update() Object.update(self) self.z = -self.y def update_animation(self): self.image = self.animation.get_image(self.flip) return self.animation.advance() def change_state(self, state): self.state = state def move(self, dx, dy): "Intenta avanzar en la dirección indicada" self.x += dx self.y += dy up, down, left, right = 470, 230, 20, 1250 if self.y > up: self.y = up elif self.y < down: self.y = down if self.x < left: self.x = left elif self.x > right: self.x = right def set_collision(self, power=1, dy=0, cw=50): """Define una zona como 'colisionable' para golpear a otros""" (_, _, w, h) = self.image.get_rect() ch = 10 if self.flip: x = self.x - cw - w/2 + cw + 15 else: x = self.x + w/2 - cw - 15 y = self.y + self.dy - h / 2 + dy Object.set_collision(self, (x, y), cw, ch) self.collision_power = power # intenta golpear a sus enemigos (ESTO FUNCIONA) #for e in self.enemies: # if same_z_dist(e, self): # if self.collision_rect.colliderect(e.get_screen_rect()): # print "He golpeado a otro personaje del juego" def get_collision_to_take_enemies(self, dy): """Verifica si puede sujetar a otros personajes del juego. Si están dadas las condiciones para sujetarlo (distancia y disponibilidad), retorna al enemigo. En caso contrario retorna None.""" y_min = 10 x_min = 30 for e in self.game.enemies: if abs(common.get_dist_x(self, e)) < x_min: dist_y = common.get_dist_y(self, e) if dy >= 0: if dist_y < 0 and dist_y > - y_min: # intenta sujetar al enemigo mientras sube. if e.can_take_by_player(): return e else: if dist_y > 0 and dist_y < y_min: # intenta sujetar al enemigo mientras baja. if e.can_take_by_player(): return e def get_collision_receive(self): """Determina si en ese momento es golpeado por otro personaje.""" for e in self.game.enemies: if self.sensitive and e.collision_rect and same_z_dist(e, self): if e.collision_rect.colliderect(self.get_screen_rect()): try: new_flip = (self.x - e.x) / abs(self.x - e.x) except: new_flip = 1 return e.collision_power, new_flip == 1 def get_collision_send(self): "Retorna True si detecta que ha golpeado a un personaje" for e in self.game.enemies: if e.sensitive and self.collision_rect and same_z_dist(e, self): if self.collision_rect.colliderect(e.get_screen_rect()): return True def get_screen_rect(self): image_rect = self.image.get_rect() return (self.rect.x, self.rect.y, image_rect.w, image_rect.h) def create_hit(self): """Genera un explosión que indica la existencia de un golpe.""" if self.flip: dx = - 60 else: dx = 30 x = self.x + dx y = self.y - 130 self.sprites.add(Hit(x, y, self.datadir)) def can_take_by_player(self): """Informa al jugador si este enemigo se puede sujetar.""" return isinstance(self.state, (Stand, Walk, Run))
class Player(Object): def __init__(self, game, control, sprites, datadir): Object.__init__(self, game.stage) self.game = game self.name = 'shaolin' self.datadir = datadir self.init_animations(datadir) self.image = self.animation.get_image() self.x = 100 self.y = 350 self.rect = pygame.Rect(self.x, self.y, 10, 10) self.flip = False self.bandage = bandage.Bandage(self) self.change_state(Starting(self)) self.dy = 0 self.control = control self.sprites = sprites self.last_attack = (0, 0) self.energy_model = energy.EnergyModel(self.name, 100, game.on_player_energy_model_change) self.hit_receive_counter = 0 self.shadow = shadow.Shadow(self) self.update() def init_animations(self, datadir): self.animation = Animation('shaolin') def update(self): self.state.update() Object.update(self) self.z = -self.y self.bandage.update_from_parent() self.shadow.update_from_parent() def update_animation(self): self.image = self.animation.get_image(self.flip) self.rect.size = self.image.get_width(), self.image.get_height() return self.animation.advance() def change_state(self, state): self.state = state def kill(self): Object.kill(self) self.shadow.kill() def set_collision(self, power=1, dy=0, cw=50): """Define una zona como 'colisionable' para golpear a otros""" (_, _, w, h) = self.image.get_rect() ch = 10 if self.flip: x = self.x - cw - w/2 + cw + 15 else: x = self.x + w/2 - cw - 15 y = self.y + self.dy - h / 2 + dy Object.set_collision(self, (x, y), cw, ch) self.collision_power = power # intenta golpear a sus enemigos (ESTO FUNCIONA) #for e in self.enemies: # if same_z_dist(e, self): # if self.collision_rect.colliderect(e.get_screen_rect()): # print "He golpeado a otro personaje del juego" def check_collision_receive(self): if self.get_collision_receive(): power, self.flip = self.get_collision_receive() if power > 1: self.hit_receive_counter = 0 self.change_state(HardHit(self)) else: self.hit_receive_counter += 1 if self.hit_receive_counter > 3: self.change_state(HardHit(self)) self.hit_receive_counter = 0 else: self.change_state(HitStand(self)) self.create_hit() def get_collision_to_take_enemies(self, dy): """Verifica si puede sujetar a otros personajes del juego. Si están dadas las condiciones para sujetarlo (distancia y disponibilidad), retorna al enemigo. En caso contrario retorna None""" y_min = 10 x_min = 30 for e in self.game.enemies: if abs(common.get_dist_x(self, e)) < x_min: dist_y = common.get_dist_y(self, e) if dy >= 0: if dist_y > 0 and dist_y < y_min: # intenta sujetar al enemigo mientras baja. if e.can_take_by_player(): return e else: if dist_y > 0 and dist_y < y_min: # intenta sujetar al enemigo mientras sube. if e.can_take_by_player(): return e def get_collision_receive(self): """Determina si en ese momento es golpeado por otro personaje.""" for e in self.game.enemies: if self.sensitive and e.collision_rect and same_z_dist(e, self): if e.collision_rect.colliderect(self.get_screen_rect()): try: new_flip = (self.x - e.x) / abs(self.x - e.x) except: new_flip = 1 return e.collision_power, new_flip == 1 def get_collision_send(self): "Retorna True si detecta que ha golpeado a un personaje" for e in self.game.enemies: if e.sensitive and self.collision_rect and same_z_dist(e, self): if self.collision_rect.colliderect(e.get_screen_rect()): return True def create_hit(self): """Genera un explosión que indica la existencia de un golpe.""" dx = - 60 if self.flip else 30 x = self.x + dx y = self.y - 130 common.audio.play('punch1') self.sprites.add(Hit(x, y)) def can_take_by_player(self): """Informa al jugador si este enemigo se puede sujetar.""" return isinstance(self.state, (Stand, Walk, Run)) def do_fall_if_are_in_air(self): """Previene que el personaje no quede 'volando' cuando se quiere bajar de una caja""" x, y = self.get_pos() dist = self.stage.get_dist_to_flood(x, y, self.dy) if dist < 0: self.change_state(JumpStand(self, 0)) return True def do_stand_if_are_in_flood(self): "Procura que el personaje 'pise' el suelo o los objetos del nivel" x, y = self.get_pos() dy = self.dy flood = self.stage.get_dist_to_flood(x, y, dy) if flood >= 0: self.change_state(Stand(self)) self.dy = self.stage.get_flood_dy(x, y) return