class Volcano(object): BASE_CAVERN_RECT = pygame.Rect(0, 310, 600, 57) def __init__(self): self.lava_pool = TiledSprite('65000000bc/lava_pool', 4, 1) self.lava_pool.lethal = True self.lava_puddle = Sprite('65000000bc/volcano_lava_puddle') self.lava_puddle.collidable = False self.lava_puddle_blocker = Box(10, self.BASE_CAVERN_RECT.height, (0, 0, 0)) self.top_sprite = Sprite('65000000bc/volcano_top') self.top_sprite.use_pixel_collisions = True self.top_sprite.update_image() self.bottom_sprite = Sprite('65000000bc/volcano_bottom') self.bottom_sprite.update_image() self.cavern_blocker = Box(self.bottom_sprite.rect.width / 2, self.BASE_CAVERN_RECT.height, (0, 0, 0)) self.column_sprite = Sprite('65000000bc/volcano_column') self.column_sprite.use_pixel_collisions = True self.column_sprite.update_image() self.cover_sprite = Sprite('65000000bc/volcano_cover') self.cover_sprite.collidable = False self.rect = pygame.Rect(0, 0, self.bottom_sprite.rect.width, self.top_sprite.rect.height + self.BASE_CAVERN_RECT.height + self.bottom_sprite.rect.height) def add_to(self, area): self.eventbox = EventBox(area) self.eventbox.object_entered.connect( lambda x: self.cover_sprite.hide()) self.eventbox.object_exited.connect( lambda x: self.cover_sprite.show()) self.eventbox.watch_object_moves(area.engine.player) area.main_layer.add(self.lava_puddle_blocker) area.main_layer.add(self.cavern_blocker) area.main_layer.add(self.lava_puddle) area.main_layer.add(self.lava_pool) area.main_layer.add(self.top_sprite) area.main_layer.add(self.bottom_sprite) area.main_layer.add(self.column_sprite) area.fg_layer.add(self.cover_sprite) def move_to(self, x, y): self.rect.left = x self.rect.top = y self.lava_pool.move_to(x + 360, y + 10) self.top_sprite.move_to(x, y) self.column_sprite.move_to( x + 578, y + self.rect.height - self.column_sprite.rect.height) self.bottom_sprite.move_to( x, y + self.rect.height - self.bottom_sprite.rect.height) self.lava_puddle.move_to( x + 574, self.bottom_sprite.rect.top - self.lava_puddle.rect.height + 4) self.lava_puddle_blocker.move_to( self.lava_puddle.rect.right - 10, self.lava_puddle.rect.bottom - self.lava_puddle_blocker.rect.height) self.cavern_blocker.move_to( self.column_sprite.rect.right, self.bottom_sprite.rect.top - self.cavern_blocker.rect.height) self.cover_sprite.move_to( x, y + self.rect.height - self.cover_sprite.rect.height) self.eventbox.rects.append( pygame.Rect(x, y + self.BASE_CAVERN_RECT.top, self.rect.width, self.BASE_CAVERN_RECT.height)) self.eventbox.rects.append(self.column_sprite.rect) def clear_passage(self): self.column_sprite.remove() self.lava_puddle.remove() self.lava_puddle_blocker.remove() self.cavern_blocker.remove()
class Mountain(object): LEFT_OFFSETS = [0, 90, 189, 239, 313] RIGHT_OFFSETS = [1427, 1236, 1208, 1121, 940] def __init__(self): self.bg_sprite = Sprite('mountain_bg') self.cover_sprite = Sprite('mountain_cover') self.cover_sprite.collidable = False self.bottom_sprite = Sprite('mountain_bottom') self.bottom_sprite.use_pixel_collisions = True self.bottom_sprite.update_image() self.top_sprite = Sprite('mountain_top') self.top_sprite.use_pixel_collisions = True self.top_sprite.update_image() self.left_sprites = [] self.right_sprites = [] for i in range(1, 6): sprite = Sprite('mountain_left_%s' % i) if i != 3: # Sort of a hack. We need a blocker so you can't # climb the mountain. sprite.use_pixel_collisions = True sprite.update_image() self.left_sprites.append(sprite) sprite = Sprite('mountain_right_%s' % i) sprite.use_pixel_collisions = True sprite.update_image() self.right_sprites.append(sprite) self.rect = pygame.Rect( 0, 0, self.bottom_sprite.rect.width, sum([sprite.rect.height for sprite in self.right_sprites]) + self.top_sprite.rect.height + self.bottom_sprite.rect.height) def add_to(self, area): area.bg_layer.add(self.bg_sprite) area.main_layer.add(self.bottom_sprite) area.main_layer.add(self.top_sprite) area.fg_layer.add(self.cover_sprite) for sprite in self.left_sprites: area.main_layer.add(sprite) for sprite in self.right_sprites: area.main_layer.add(sprite) self.cave_eventbox = EventBox(area) self.cave_eventbox.object_moved.connect(self.on_cave_eventbox_moved) self.cave_eventbox.watch_object_moves(area.engine.player) self.floor_eventbox = EventBox(area) self.floor_eventbox.object_entered.connect( lambda x: self.cover_sprite.hide()) self.floor_eventbox.watch_object_moves(area.engine.player) def move_to(self, x, y): self.rect.left = x self.rect.top = y self.cover_sprite.move_to(x, y) self.bg_sprite.move_to(x, y) self.top_sprite.move_to(x + 485, y) self.bottom_sprite.move_to( x, y + self.rect.height - self.bottom_sprite.rect.height) new_y = self.bottom_sprite.rect.top for i, sprite in enumerate(self.left_sprites): new_y = new_y - sprite.rect.height sprite.move_to(x + self.LEFT_OFFSETS[i], new_y) new_y = self.bottom_sprite.rect.top for i, sprite in enumerate(self.right_sprites): new_y = new_y - sprite.rect.height sprite.move_to(x + self.RIGHT_OFFSETS[i], new_y) self.cave_eventbox.rects.append(pygame.Rect(x + 382, y + 110, 157, 110)) self.floor_eventbox.rects.append( pygame.Rect(x + 30, self.bottom_sprite.rect.top - 30, self.rect.width - 60, 30)) def on_cave_eventbox_moved(self, player): if player.rect.centerx <= self.cave_eventbox.rects[0].centerx: self.cover_sprite.show() else: self.cover_sprite.hide()
class Mountain(object): LEFT_OFFSETS = [0, 90, 189, 239, 313] RIGHT_OFFSETS = [1427, 1236, 1208, 1121, 940] def __init__(self): self.bg_sprite = Sprite('mountain_bg') self.cover_sprite = Sprite('mountain_cover') self.cover_sprite.collidable = False self.bottom_sprite = Sprite('mountain_bottom') self.bottom_sprite.use_pixel_collisions = True self.bottom_sprite.update_image() self.top_sprite = Sprite('mountain_top') self.top_sprite.use_pixel_collisions = True self.top_sprite.update_image() self.left_sprites = [] self.right_sprites = [] for i in range(1, 6): sprite = Sprite('mountain_left_%s' % i) if i != 3: # Sort of a hack. We need a blocker so you can't # climb the mountain. sprite.use_pixel_collisions = True sprite.update_image() self.left_sprites.append(sprite) sprite = Sprite('mountain_right_%s' % i) sprite.use_pixel_collisions = True sprite.update_image() self.right_sprites.append(sprite) self.rect = pygame.Rect( 0, 0, self.bottom_sprite.rect.width, sum([sprite.rect.height for sprite in self.right_sprites]) + self.top_sprite.rect.height + self.bottom_sprite.rect.height) def add_to(self, area): area.bg_layer.add(self.bg_sprite) area.main_layer.add(self.bottom_sprite) area.main_layer.add(self.top_sprite) area.fg_layer.add(self.cover_sprite) for sprite in self.left_sprites: area.main_layer.add(sprite) for sprite in self.right_sprites: area.main_layer.add(sprite) self.cave_eventbox = EventBox(area) self.cave_eventbox.object_moved.connect( self.on_cave_eventbox_moved) self.cave_eventbox.watch_object_moves(area.engine.player) self.floor_eventbox = EventBox(area) self.floor_eventbox.object_entered.connect( lambda x: self.cover_sprite.hide()) self.floor_eventbox.watch_object_moves(area.engine.player) def move_to(self, x, y): self.rect.left = x self.rect.top = y self.cover_sprite.move_to(x, y) self.bg_sprite.move_to(x, y) self.top_sprite.move_to(x + 485, y) self.bottom_sprite.move_to( x, y + self.rect.height - self.bottom_sprite.rect.height) new_y = self.bottom_sprite.rect.top for i, sprite in enumerate(self.left_sprites): new_y = new_y - sprite.rect.height sprite.move_to(x + self.LEFT_OFFSETS[i], new_y) new_y = self.bottom_sprite.rect.top for i, sprite in enumerate(self.right_sprites): new_y = new_y - sprite.rect.height sprite.move_to(x + self.RIGHT_OFFSETS[i], new_y) self.cave_eventbox.rects.append( pygame.Rect(x + 382, y + 110, 157, 110)) self.floor_eventbox.rects.append( pygame.Rect(x + 30, self.bottom_sprite.rect.top - 30, self.rect.width - 60, 30)) def on_cave_eventbox_moved(self, player): if player.rect.centerx <= self.cave_eventbox.rects[0].centerx: self.cover_sprite.show() else: self.cover_sprite.hide()
class Player(Sprite): MOVE_SPEED = 6 JUMP_SPEED = 6 MAX_JUMP_HEIGHT = 100 HOVER_TIME_MS = 1000 MAX_HEALTH = 3 MAX_LIVES = 3 PROPULSION_BELOW_OFFSET = 8 def __init__(self): super(Player, self).__init__('player', flip_image=True, obey_gravity=True) self.engine = get_engine() self.should_check_collisions = True # Sprites self.propulsion_below = Sprite("propulsion_below", flip_image=True) self.propulsion_below.collidable = False self.propulsion_below.visible = 0 self.tractor_beam = TractorBeam(self) # State self.jumping = False self.hovering = False self.block_events = False self.jump_origin = None self.hover_time_ms = 0 self.health = self.MAX_HEALTH self.lives = self.MAX_LIVES self.last_safe_spot = None self.vehicle = None self.vehicle_move_cnx = None # Signals self.health_changed = Signal() self.lives_changed = Signal() self.direction_changed.connect(self.on_direction_changed) self.reverse_gravity_changed.connect(self.on_reverse_gravity_changed) def handle_event(self, event): if self.block_events: return if event.type == KEYDOWN: if event.key == K_RIGHT: self.move_right() elif event.key == K_LEFT: self.move_left() elif event.key == K_SPACE: self.jump() elif event.key in (K_LSHIFT, K_RSHIFT): self.start_tractor_beam() elif event.type == KEYUP: if event.key == K_LEFT: if self.velocity[0] < 0: self.velocity = (0, self.velocity[1]) elif event.key == K_RIGHT: if self.velocity[0] > 0: self.velocity = (0, self.velocity[1]) elif event.key == K_SPACE: self.fall() elif event.key in (K_LSHIFT, K_RSHIFT): self.stop_tractor_beam() def move_right(self): self.velocity = (self.MOVE_SPEED, self.velocity[1]) if self.direction != Direction.RIGHT: self.direction = Direction.RIGHT self.tractor_beam.direction = Direction.RIGHT self.update_image() def move_left(self): self.velocity = (-self.MOVE_SPEED, self.velocity[1]) if self.direction != Direction.LEFT: self.direction = Direction.LEFT self.tractor_beam.direction = Direction.LEFT self.update_image() def start_tractor_beam(self): self.tractor_beam.show() self.tractor_beam.update_position(self) self.calculate_collision_rects() def stop_tractor_beam(self): self.tractor_beam.ungrab() self.tractor_beam.hide() self.calculate_collision_rects() def ride(self, vehicle): self.vehicle = vehicle self.velocity = (self.velocity[0], 0) self.vehicle_moved_cnx = \ self.vehicle.moved.connect(self.on_vehicle_moved) self.calculate_collision_rects() def jump(self): if (self.falling and not self.engine.god_mode) or self.jumping: return self.jump_origin = (self.rect.left, self.rect.top) self.jumping = True self.falling = False if self.reverse_gravity: self.velocity = (self.velocity[0], self.JUMP_SPEED) else: self.velocity = (self.velocity[0], -self.JUMP_SPEED) self.propulsion_below.show() self.stop_riding() def reset_gravity(self): if self.reverse_gravity: self.reverse_gravity = False if self.falling: # Reset the fall self.falling = False self.fall() self.update_image() def stop_riding(self): if self.vehicle: self.vehicle_moved_cnx.disconnect() self.vehicle = None self.calculate_collision_rects() def fall(self): if self.falling: return self.propulsion_below.hide() self.jumping = False self.hovering = False super(Player, self).fall() def hover(self): if self.hovering: return self.propulsion_below.show() self.jumping = False self.hovering = True self.hover_time_ms = 0 self.velocity = (self.velocity[0], 0) def calculate_collision_rects(self): self.collision_masks = [] self.collision_rects = [self.rect] if self.tractor_beam.item: self.collision_rects.append(self.tractor_beam.item.rect) if self.vehicle: self.collision_rects.append(self.vehicle.rect) def check_collisions(self, *args, **kwargs): super(Player, self).check_collisions(*args, **kwargs) def should_adjust_position_with(self, obj, dx, dy): from foreverend.sprites.common import FloatingSprite return (obj != self.vehicle and (dx == 0 or not isinstance(obj, FloatingSprite))) def tick(self): if self.hovering: self.hover_time_ms += 1.0 / self.engine.FPS * 1000 if self.hover_time_ms >= self.HOVER_TIME_MS: self.fall() super(Player, self).tick() def on_added(self, layer): for obj in (self.propulsion_below, self.tractor_beam, self.vehicle): if obj: layer.add(obj) def on_removed(self, layer): for obj in (self.propulsion_below, self.tractor_beam, self.vehicle): if obj: layer.remove(obj) def on_moved(self, dx, dy): if not self.last_safe_spot: self.last_safe_spot = self.rect.topleft self.rect.top = max(self.rect.top, 0) if self.rect.top > self.layer.area.size[1]: self.on_dead() return if (self.jumping and not self.engine.god_mode and ((not self.reverse_gravity and self.jump_origin[1] - self.rect.top >= self.MAX_JUMP_HEIGHT) or (self.reverse_gravity and self.rect.top - self.jump_origin[1] >= self.MAX_JUMP_HEIGHT))): self.hover() if self.propulsion_below.visible: if self.direction == Direction.RIGHT: offset = self.PROPULSION_BELOW_OFFSET if self.direction == Direction.LEFT: offset = self.rect.width - self.propulsion_below.rect.width - \ self.PROPULSION_BELOW_OFFSET if self.reverse_gravity: y = self.rect.top - self.propulsion_below.rect.height else: y = self.rect.bottom self.propulsion_below.move_to(self.rect.left + offset, y) if self.tractor_beam.visible: self.tractor_beam.update_position(self) if self.vehicle and dx != 0: self.vehicle.move_to( self.rect.left - (self.vehicle.rect.width - self.rect.width) / 2, self.vehicle.rect.top) self.calculate_collision_rects() super(Player, self).on_moved(dx, dy) def on_collision(self, dx, dy, obj, self_rect, obj_rect): if obj.lethal and not self.engine.god_mode and self_rect == self.rect: self.on_hit() return self.last_safe_spot = self.rect.topleft if self.tractor_beam.item and self_rect == self.tractor_beam.item.rect: move_player = True if self.tractor_beam.adjust_item_position(obj_rect): move_player = False if move_player: if self.direction == Direction.LEFT: self.move_to(obj_rect.right + (self.rect.left - self.tractor_beam.item.rect.left), self.rect.top) elif self.direction == Direction.RIGHT: self.move_to(obj_rect.left - (self.tractor_beam.item.rect.right - self.rect.left), self.rect.top) if dy > 0 and not self.vehicle and isinstance(obj, Vehicle): self.ride(obj) if self.jumping and dy < 0: self.fall() else: super(Player, self).on_collision(dx, dy, obj, self_rect, obj_rect) def on_direction_changed(self): if self.vehicle: self.vehicle.direction = self.direction def on_reverse_gravity_changed(self): self.propulsion_below.set_reverse_gravity(self.reverse_gravity) self.tractor_beam.set_reverse_gravity(self.reverse_gravity) if self.tractor_beam.item: self.tractor_beam.item.set_reverse_gravity(self.reverse_gravity) self.fall() def on_vehicle_moved(self, dx, dy): if dy != 0: self.move_by(0, dy) def on_hit(self): self.health -= 1 self.health_changed.emit() if self.health == 0: self.on_dead() else: self.move_to(*self.last_safe_spot) self.velocity = (0, 0) self.falling = False self.fall() def on_dead(self): self.lives -= 1 self.lives_changed.emit() self.velocity = (0, 0) if self.lives == 0: self.engine.game_over() else: self.health = self.MAX_HEALTH self.health_changed.emit() self.engine.dead()