예제 #1
0
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()
예제 #2
0
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()