class Effect(object): def __init__(self): self.timer = None self.timer_ms = 150 # Signals self.started = Signal() self.stopped = Signal() def pre_start(self): pass def pre_stop(self): pass def start(self): assert not self.timer self.pre_start() self.timer = Timer(self.timer_ms, self.on_tick) self.timer.start() self.started.emit() def stop(self): assert self.timer self.pre_stop() self.timer.stop() self.timer = None self.stopped.emit() def on_tick(self): pass
class IceBoulder(Sprite): MELT_AMOUNT = 5 def __init__(self, *args, **kwargs): super(IceBoulder, self).__init__('12000bc/ice_boulder', *args, **kwargs) #self.use_pixel_collisions = True self.melting = False def melt(self, x, y): self.explosion = FlameThrowerParticleSystem(self.layer.area) self.explosion.start(x, y) self.explosion.repeat = True self.timer = Timer(60, self.on_melt_timer) self.melting = True def on_melt_timer(self): new_height = self.image.get_height() - self.MELT_AMOUNT if new_height <= 0: self.timer.stop() self.explosion.stop() self.remove() else: self.image = self.image.subsurface( pygame.Rect(0, 0, self.image.get_width(), new_height)) self.move_to(self.rect.left, self.rect.top + self.MELT_AMOUNT) def handle_collision(self, obj, *args, **kwargs): if (not self.melting and isinstance(obj, Player) and obj.tractor_beam.item and isinstance(obj.tractor_beam.item, FlameThrower)): flamethrower = obj.tractor_beam.item self.melt(flamethrower.rect.right, flamethrower.rect.centery)
class DelayPage(Page): def __init__(self, delay_ms): super(DelayPage, self).__init__() self.delay_ms = delay_ms self.timer = None def start(self): self.timer = Timer(self.delay_ms, self.stop, one_shot=True) def stop(self): self.timer.stop() self.done.emit()
class DelayPage(Page): def __init__(self, delay_ms): super(DelayPage, self).__init__() self.delay_ms = delay_ms self.timer = None def start(self): self.timer = Timer(self.delay_ms, self.stop, one_shot=True) def stop(self): self.timer.stop() self.done.emit()
class IceBoulder(Sprite): MELT_AMOUNT = 5 def __init__(self, *args, **kwargs): super(IceBoulder, self).__init__("12000bc/ice_boulder", *args, **kwargs) # self.use_pixel_collisions = True self.melting = False def melt(self, x, y): self.explosion = FlameThrowerParticleSystem(self.layer.area) self.explosion.start(x, y) self.explosion.repeat = True self.timer = Timer(60, self.on_melt_timer) self.melting = True def on_melt_timer(self): new_height = self.image.get_height() - self.MELT_AMOUNT if new_height <= 0: self.timer.stop() self.explosion.stop() self.remove() else: self.image = self.image.subsurface(pygame.Rect(0, 0, self.image.get_width(), new_height)) self.move_to(self.rect.left, self.rect.top + self.MELT_AMOUNT) def handle_collision(self, obj, *args, **kwargs): if ( not self.melting and isinstance(obj, Player) and obj.tractor_beam.item and isinstance(obj.tractor_beam.item, FlameThrower) ): flamethrower = obj.tractor_beam.item self.melt(flamethrower.rect.right, flamethrower.rect.centery)
class Outside65000000BC(Level1Area): def draw_bg(self, surface): surface.fill((0, 0, 0)) def setup(self): self.exploding = False self.exploded = False ground = TiledSprite("ground", self.size[0] / 32, 1) self.main_layer.add(ground) ground.move_to(0, self.size[1] - ground.rect.height) hills = Sprite("65000000bc/hills_1") self.bg_layer.add(hills) hills.move_to(0, ground.rect.top - hills.rect.height) # Volcano self.volcano = Volcano() self.volcano.add_to(self) self.volcano.move_to(1400, ground.rect.top - self.volcano.rect.height + 1) blocker = Box(150, self.size[1] - self.volcano.rect.height - 20, (0, 0, 0, 0)) self.main_layer.add(blocker) blocker.move_to(self.volcano.lava_pool.rect.right - 100, 0) # Left-side lava pool lava_pool = TiledSprite("65000000bc/lava_pool", 5, 1) lava_pool.lethal = True self.main_layer.add(lava_pool) lava_pool.move_to(self.volcano.rect.left - lava_pool.rect.width - 100, ground.rect.top - 18) # Platforms platform = FloatingSprite("65000000bc/platform") self.main_layer.add(platform) platform.move_to(lava_pool.rect.left + 250, lava_pool.rect.top - 10) platform = FloatingSprite("65000000bc/platform") self.main_layer.add(platform) platform.move_to(lava_pool.rect.left + 500, lava_pool.rect.top - 8) platform = FloatingSprite("65000000bc/platform") self.main_layer.add(platform) platform.move_to(lava_pool.rect.left + 750, lava_pool.rect.top - 12) # Right-side lava pool lava_pool = TiledSprite("65000000bc/lava_pool", 3, 1) lava_pool.lethal = True self.main_layer.add(lava_pool) lava_pool.move_to(self.volcano.rect.right + 200, ground.rect.top - 18) # Dynamite explosion trigger explosion_box = EventBox(self) explosion_box.rects.append( pygame.Rect( self.volcano.lava_puddle.rect.x, self.volcano.lava_puddle.rect.bottom - 5, self.volcano.lava_puddle.rect.width, 5, ) ) explosion_box.watch_object_moves(self.level.dynamite) explosion_box.object_entered.connect(self.on_dynamite_placed) # Artifact self.level.add_artifact(self, lava_pool.rect.right + 200, ground.rect.top) def on_dynamite_placed(self, obj): assert obj == self.level.dynamite if self.exploding or self.exploded: return self.level.dynamite.light() self.exploding = True self.detonate_timer = Timer(1000, self.start_explosion) def start_explosion(self): self.detonate_timer.stop() self.detonate_timer = None self.level.dynamite.remove() self.level.dynamite = None self.explosion = ExplosionParticleSystem(self) self.explosion.start(2040, 1500) self.explosion_timer = Timer(350, self.on_explosion_done) self.explosion_timer.start() def on_explosion_done(self): self.explosion_timer.stop() self.explosion_timer = None self.exploding = False self.exploded = True self.volcano.clear_passage()
class Outside65000000BC(Level1Area): def draw_bg(self, surface): surface.fill((0, 0, 0)) def setup(self): self.exploding = False self.exploded = False ground = TiledSprite('ground', self.size[0] / 32, 1) self.main_layer.add(ground) ground.move_to(0, self.size[1] - ground.rect.height) hills = Sprite('65000000bc/hills_1') self.bg_layer.add(hills) hills.move_to(0, ground.rect.top - hills.rect.height) # Volcano self.volcano = Volcano() self.volcano.add_to(self) self.volcano.move_to( 1400, ground.rect.top - self.volcano.rect.height + 1) blocker = Box(150, self.size[1] - self.volcano.rect.height - 20, (0, 0, 0, 0)) self.main_layer.add(blocker) blocker.move_to(self.volcano.lava_pool.rect.right - 100, 0) # Left-side lava pool lava_pool = TiledSprite('65000000bc/lava_pool', 5, 1) lava_pool.lethal = True self.main_layer.add(lava_pool) lava_pool.move_to(self.volcano.rect.left - lava_pool.rect.width - 100, ground.rect.top - 18) # Platforms platform = FloatingSprite('65000000bc/platform') self.main_layer.add(platform) platform.move_to(lava_pool.rect.left + 250, lava_pool.rect.top - 10) platform = FloatingSprite('65000000bc/platform') self.main_layer.add(platform) platform.move_to(lava_pool.rect.left + 500, lava_pool.rect.top - 8) platform = FloatingSprite('65000000bc/platform') self.main_layer.add(platform) platform.move_to(lava_pool.rect.left + 750, lava_pool.rect.top - 12) # Right-side lava pool lava_pool = TiledSprite('65000000bc/lava_pool', 3, 1) lava_pool.lethal = True self.main_layer.add(lava_pool) lava_pool.move_to(self.volcano.rect.right + 200, ground.rect.top - 18) # Dynamite explosion trigger explosion_box = EventBox(self) explosion_box.rects.append( pygame.Rect(self.volcano.lava_puddle.rect.x, self.volcano.lava_puddle.rect.bottom - 5, self.volcano.lava_puddle.rect.width, 5)) explosion_box.watch_object_moves(self.level.dynamite) explosion_box.object_entered.connect(self.on_dynamite_placed) # Artifact self.level.add_artifact(self, lava_pool.rect.right + 200, ground.rect.top) def on_dynamite_placed(self, obj): assert obj == self.level.dynamite if self.exploding or self.exploded: return self.level.dynamite.light() self.exploding = True self.detonate_timer = Timer(1000, self.start_explosion) def start_explosion(self): self.detonate_timer.stop() self.detonate_timer = None self.level.dynamite.remove() self.level.dynamite = None self.explosion = ExplosionParticleSystem(self) self.explosion.start(2040, 1500) self.explosion_timer = Timer(350, self.on_explosion_done) self.explosion_timer.start() def on_explosion_done(self): self.explosion_timer.stop() self.explosion_timer = None self.exploding = False self.exploded = True self.volcano.clear_passage()
class ParticleSystem(object): def __init__(self, area): # Settings self.particle_filename = None self.min_particles = 0 self.max_particles = 0 self.min_initial_speed = 0 self.max_initial_speed = 0 self.min_acceleration = 0 self.max_acceleration = 0 self.min_lifetime = 0 self.max_lifetime = 0 self.min_scale = 0 self.max_scale = 0 self.min_rotation_speed = 0 self.max_rotation_speed = 0 self.min_angle = 0 self.max_angle = 2 * math.pi self.repeat = False # State self.area = area self.image = None self.particles = [] self.free_particles = [] self.pos = None self.timer = Timer(60, self.on_particle_update) def start(self, x, y): assert self.pos is None self.pos = (x, y) self.particles = [] for i in range(self.max_particles): self.particles.append(Particle(self)) self.free_particles = list(self.particles) if not self.image: self.image = load_image(self.particle_filename).convert_alpha() self.add_particles() self.area.particle_systems.append(self) self.timer.start() def add_particles(self): num_particles = random.randint(self.min_particles, self.max_particles) for i in range(num_particles): if self.free_particles: self.setup_particle(self.free_particles.pop()) def stop(self): self.timer.stop() self.pos = None self.area.particle_systems.remove(self) self.particles = [] self.free_particles = [] def setup_particle(self, particle): direction = self.random_direction() velocity = self.random_float(self.min_initial_speed, self.max_initial_speed) particle.velocity = (velocity * direction[0], velocity * direction[1]) acceleration = self.random_float(self.min_acceleration, self.max_acceleration) particle.acceleration = (acceleration * direction[0], acceleration * direction[1]) particle.lifetime = self.random_float(self.min_lifetime, self.max_lifetime) particle.scale = self.random_float(self.min_scale, self.max_scale) particle.rotation_speed = \ self.random_float(self.min_rotation_speed, self.max_rotation_speed) particle.pos = self.pos particle.elapsed_time = 0.0 particle.rotation = self.random_float(0.0, 360.0) def random_direction(self): angle = self.random_float(self.min_angle, self.max_angle) return (math.cos(angle), math.sin(angle)) def random_float(self, min_value, max_value): return min_value + random.random() * (max_value - min_value) def draw(self, surface): for particle in self.particles: if particle.active: particle.draw(surface) def on_particle_update(self): active_count = 0 for particle in self.particles: if particle.active: active_count += 1 particle.update(self.timer.ms / 1000.0) if not particle.active: self.free_particles.append(particle) if not self.repeat and active_count == 0: self.stop() elif self.repeat: self.add_particles()
class ParticleSystem(object): def __init__(self, area): # Settings self.particle_filename = None self.min_particles = 0 self.max_particles = 0 self.min_initial_speed = 0 self.max_initial_speed = 0 self.min_acceleration = 0 self.max_acceleration = 0 self.min_lifetime = 0 self.max_lifetime = 0 self.min_scale = 0 self.max_scale = 0 self.min_rotation_speed = 0 self.max_rotation_speed = 0 self.min_angle = 0 self.max_angle = 2 * math.pi self.repeat = False # State self.area = area self.image = None self.particles = [] self.free_particles = [] self.pos = None self.timer = Timer(60, self.on_particle_update) def start(self, x, y): assert self.pos is None self.pos = (x, y) self.particles = [] for i in range(self.max_particles): self.particles.append(Particle(self)) self.free_particles = list(self.particles) if not self.image: self.image = load_image(self.particle_filename).convert_alpha() self.add_particles() self.area.particle_systems.append(self) self.timer.start() def add_particles(self): num_particles = random.randint(self.min_particles, self.max_particles) for i in range(num_particles): if self.free_particles: self.setup_particle(self.free_particles.pop()) def stop(self): self.timer.stop() self.pos = None self.area.particle_systems.remove(self) self.particles = [] self.free_particles = [] def setup_particle(self, particle): direction = self.random_direction() velocity = self.random_float(self.min_initial_speed, self.max_initial_speed) particle.velocity = (velocity * direction[0], velocity * direction[1]) acceleration = self.random_float(self.min_acceleration, self.max_acceleration) particle.acceleration = (acceleration * direction[0], acceleration * direction[1]) particle.lifetime = self.random_float(self.min_lifetime, self.max_lifetime) particle.scale = self.random_float(self.min_scale, self.max_scale) particle.rotation_speed = \ self.random_float(self.min_rotation_speed, self.max_rotation_speed) particle.pos = self.pos particle.elapsed_time = 0.0 particle.rotation = self.random_float(0.0, 360.0) def random_direction(self): angle = self.random_float(self.min_angle, self.max_angle) return (math.cos(angle), math.sin(angle)) def random_float(self, min_value, max_value): return min_value + random.random() * (max_value - min_value) def draw(self, surface): for particle in self.particles: if particle.active: particle.draw(surface) def on_particle_update(self): active_count = 0 for particle in self.particles: if particle.active: active_count += 1 particle.update(self.timer.ms / 1000.0) if not particle.active: self.free_particles.append(particle) if not self.repeat and active_count == 0: self.stop() elif self.repeat: self.add_particles()