class MyGame(arcade.Window): def __init__(self): super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) # Set the working directory (where we expect to find files) to the same # directory this .py file is in. You can leave this out of your own # code, but it is needed to easily run the examples using "python -m" # as mentioned at the top of this program. file_path = os.path.dirname(os.path.abspath(__file__)) os.chdir(file_path) arcade.set_background_color(arcade.color.BLACK) # collect particle factory functions self.factories = [v for k, v in globals().items() if k.startswith("emitter_")] self.emitter_factory_id = -1 self.label = None self.emitter = None self.emitter_timeout = 0 self.obj = arcade.Sprite(":resources:images/pinball/bumper.png", 0.2, center_x=0, center_y=15) self.obj.change_x = 3 self.frametime_plotter = FrametimePlotter() pyglet.clock.schedule_once(self.next_emitter, QUIET_BETWEEN_SPAWNS) def next_emitter(self, _time_delta): self.emitter_factory_id = (self.emitter_factory_id + 1) % len(self.factories) print("Changing emitter to {}".format(self.emitter_factory_id)) self.emitter_timeout = 0 self.label, self.emitter = self.factories[self.emitter_factory_id]() self.frametime_plotter.add_event("spawn {}".format(self.emitter_factory_id)) def update(self, delta_time): if self.emitter: self.emitter_timeout += 1 self.emitter.update() if self.emitter.can_reap() or self.emitter_timeout > EMITTER_TIMEOUT: self.frametime_plotter.add_event("reap") pyglet.clock.schedule_once(self.next_emitter, QUIET_BETWEEN_SPAWNS) self.emitter = None self.obj.update() if self.obj.center_x > SCREEN_WIDTH: self.obj.center_x = 0 self.frametime_plotter.end_frame(delta_time) def on_draw(self): arcade.start_render() self.obj.draw() if self.label: arcade.draw_text("#{} {}".format(self.emitter_factory_id, self.label), SCREEN_WIDTH / 2, SCREEN_HEIGHT - 20, arcade.color.PALE_GOLD, 20, width=SCREEN_WIDTH, align="center", anchor_x="center", anchor_y="center") if self.emitter: self.emitter.draw() arcade.draw_text("Particles: " + str(self.emitter.get_count()), 10, 30, arcade.color.PALE_GOLD, 12) def on_key_press(self, key, modifiers): if key == arcade.key.ESCAPE: arcade.close_window()
class ParticleBurst: def __init__(self, center_pos, velocity=None): self.emitter_timeout = 0 if velocity: self.speed = PARTICLE_SPEED_FAST + velocity.speed else: self.speed = PARTICLE_SPEED_FAST self.frametime_plotter = FrametimePlotter() self.emitter = arcade.Emitter( center_xy=center_pos, emit_controller=arcade.EmitBurst(BURST_PARTICLE_COUNT), # emit_controller=arcade.EmitterIntervalWithTime(DEFAULT_EMIT_INTERVAL, DEFAULT_EMIT_DURATION), particle_factory=lambda emitter: arcade.LifetimeParticle( filename_or_texture=TEXTURE, change_xy=arcade.rand_on_circle((0.0, 0.0), self.speed), lifetime=random.uniform(DEFAULT_PARTICLE_LIFETIME - 0.5, DEFAULT_PARTICLE_LIFETIME), #lifetime=DEFAULT_PARTICLE_LIFETIME, scale=DEFAULT_SCALE, alpha=DEFAULT_ALPHA ) ) def draw(self): if self.emitter: self.emitter.draw() def advance(self, delta_time): if self.emitter: self.emitter_timeout += 1 self.emitter.update() if self.emitter.can_reap() or self.emitter_timeout > EMITTER_TIMEOUT: self.frametime_plotter.add_event("reap") #pyglet.clock.schedule_once(self.next_emitter, QUIET_BETWEEN_SPAWNS) self.emitter = None self.frametime_plotter.end_frame(delta_time) @property def alive(self): is_alive = False if self.emitter: is_alive = True return is_alive #p = ParticleBurst((constants.SCREEN_WIDTH/2, constants.SCREEN_HEIGHT/2))
class FireworksApp(arcade.Window): def __init__(self): super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) # Set the working directory (where we expect to find files) to the same # directory this .py file is in. You can leave this out of your own # code, but it is needed to easily run the examples using "python -m" # as mentioned at the top of this program. file_path = os.path.dirname(os.path.abspath(__file__)) os.chdir(file_path) arcade.set_background_color(arcade.color.BLACK) self.emitters = [] self.frametime_plotter = FrametimePlotter() self.launch_firework(0) arcade.schedule(self.launch_spinner, 4.0) stars = arcade.Emitter( center_xy=(0.0, 0.0), emit_controller=arcade.EmitMaintainCount(20), particle_factory=lambda emitter: AnimatedAlphaParticle( filename_or_texture=random.choice(STAR_TEXTURES), change_xy=(0.0, 0.0), start_alpha=0, duration1=random.uniform(2.0, 6.0), mid_alpha=128, duration2=random.uniform(2.0, 6.0), end_alpha=0, center_xy=arcade.rand_in_rect( (0.0, 0.0), SCREEN_WIDTH, SCREEN_HEIGHT))) self.emitters.append(stars) self.cloud = arcade.Emitter( center_xy=(50, 500), change_xy=(0.15, 0), emit_controller=arcade.EmitMaintainCount(60), particle_factory=lambda emitter: AnimatedAlphaParticle( filename_or_texture=random.choice(CLOUD_TEXTURES), change_xy=(_Vec2(arcade.rand_in_circle( (0.0, 0.0), 0.04)) + _Vec2(0.1, 0)).as_tuple(), start_alpha=0, duration1=random.uniform(5.0, 10.0), mid_alpha=255, duration2=random.uniform(5.0, 10.0), end_alpha=0, center_xy=arcade.rand_in_circle((0.0, 0.0), 50))) self.emitters.append(self.cloud) def launch_firework(self, delta_time): self.frametime_plotter.add_event("launch") launchers = ( self.launch_random_firework, self.launch_ringed_firework, self.launch_sparkle_firework, ) random.choice(launchers)(delta_time) pyglet.clock.schedule_once( self.launch_firework, random.uniform(LAUNCH_INTERVAL_MIN, LAUNCH_INTERVAL_MAX)) def launch_random_firework(self, _delta_time): """Simple firework that explodes in a random color""" rocket = make_rocket(self.explode_firework) self.emitters.append(rocket) def launch_ringed_firework(self, _delta_time): """"Firework that has a basic explosion and a ring of sparks of a different color""" rocket = make_rocket(self.explode_ringed_firework) self.emitters.append(rocket) def launch_sparkle_firework(self, _delta_time): """Firework which has sparks that sparkle""" rocket = make_rocket(self.explode_sparkle_firework) self.emitters.append(rocket) def launch_spinner(self, _delta_time): """Start the spinner that throws sparks""" spinner1 = make_spinner() spinner2 = make_spinner() spinner2.angle = 180 self.emitters.append(spinner1) self.emitters.append(spinner2) def explode_firework(self, prev_emitter): """Actions that happen when a firework shell explodes, resulting in a typical firework""" self.emitters.append(make_puff(prev_emitter)) self.emitters.append(make_flash(prev_emitter)) spark_texture = random.choice(SPARK_TEXTURES) sparks = arcade.Emitter( center_xy=prev_emitter.get_pos(), emit_controller=arcade.EmitBurst(random.randint(30, 40)), particle_factory=lambda emitter: arcade.FadeParticle( filename_or_texture=spark_texture, change_xy=arcade.rand_in_circle((0.0, 0.0), 9.0), lifetime=random.uniform(0.5, 1.2), mutation_callback=firework_spark_mutator)) self.emitters.append(sparks) def explode_ringed_firework(self, prev_emitter): """Actions that happen when a firework shell explodes, resulting in a ringed firework""" self.emitters.append(make_puff(prev_emitter)) self.emitters.append(make_flash(prev_emitter)) spark_texture, ring_texture = random.choice(SPARK_PAIRS) sparks = arcade.Emitter( center_xy=prev_emitter.get_pos(), emit_controller=arcade.EmitBurst(25), particle_factory=lambda emitter: arcade.FadeParticle( filename_or_texture=spark_texture, change_xy=arcade.rand_in_circle((0.0, 0.0), 8.0), lifetime=random.uniform(0.55, 0.8), mutation_callback=firework_spark_mutator)) self.emitters.append(sparks) ring = arcade.Emitter( center_xy=prev_emitter.get_pos(), emit_controller=arcade.EmitBurst(20), particle_factory=lambda emitter: arcade.FadeParticle( filename_or_texture=ring_texture, change_xy=arcade.rand_on_circle( (0.0, 0.0), 5.0) + arcade.rand_in_circle((0.0, 0.0), 0.25), lifetime=random.uniform(1.0, 1.6), mutation_callback=firework_spark_mutator)) self.emitters.append(ring) def explode_sparkle_firework(self, prev_emitter): """Actions that happen when a firework shell explodes, resulting in a sparkling firework""" self.emitters.append(make_puff(prev_emitter)) self.emitters.append(make_flash(prev_emitter)) spark_texture = random.choice(SPARK_TEXTURES) sparks = arcade.Emitter( center_xy=prev_emitter.get_pos(), emit_controller=arcade.EmitBurst(random.randint(30, 40)), particle_factory=lambda emitter: AnimatedAlphaParticle( filename_or_texture=spark_texture, change_xy=arcade.rand_in_circle((0.0, 0.0), 9.0), start_alpha=255, duration1=random.uniform(0.6, 1.0), mid_alpha=0, duration2=random.uniform(0.1, 0.2), end_alpha=255, mutation_callback=firework_spark_mutator)) self.emitters.append(sparks) def update(self, delta_time): # prevent list from being mutated (often by callbacks) while iterating over it emitters_to_update = self.emitters.copy() # update cloud if self.cloud.center_x > SCREEN_WIDTH: self.cloud.center_x = 0 # update for e in emitters_to_update: e.update() # remove emitters that can be reaped to_del = [e for e in emitters_to_update if e.can_reap()] for e in to_del: self.emitters.remove(e) self.frametime_plotter.end_frame(delta_time) def on_draw(self): arcade.start_render() for e in self.emitters: e.draw() arcade.draw_lrtb_rectangle_filled(0, SCREEN_WIDTH, 25, 0, arcade.color.DARK_GREEN) mid = SCREEN_WIDTH / 2 arcade.draw_lrtb_rectangle_filled(mid - 2, mid + 2, SPINNER_HEIGHT, 10, arcade.color.DARK_BROWN) def on_key_press(self, key, modifiers): if key == arcade.key.ESCAPE: arcade.close_window()