Particle, Particle


Flame provides a basic, yet powerful, scalable particle system. The core concept of this system is the Particle class, which is similar in behavior to the Particle class.

The most basic use of Particle in BaseGame is as follows:

import 'package:flame/components/particle_component.dart'; game.add( ParticleComponent( particle: CircleParticle() ); ) ;Copy the code

When Particle is used with a custom Game implementation, make sure that the Update and Render lifecycle hooks for Particle are called every time the Game loops a frame.

The main ways to achieve the desired particle effect are:

  • A combination of existing behaviors
  • Use behavior chains (just a grammar sugar)
  • useComputedParticle

By working from top to bottom, the composition works in a similar way to the Flutter widget. By defining bottom-up behavior, chaining allows for a more fluid expression of the same combination tree. Computing particles in turn delegates the implementation of the behavior entirely to your code. Where necessary, any approach can be combined with existing behavior.

Below you can see an example of the effect showing a circle accelerating from (0,0) to a random direction using the three methods defined above.

Random rnd = Random(); Function randomOffset = () => Offset( rnd.nextDouble() * 200 - 100, rnd.nextDouble() * 200 - 100, ); game.add( ParticleComponent( particle: Particle.generate( count: 10, generator: (i) => AcceleratedParticle( acceleration: randomOffset(), child: CircleParticle( paint: Paint().. color = Colors.red ) ) ) ) ); game.add( Particle .generate( count: 10, generator: (i) => CircleParticle(paint: Paint().. color = Colors.red) .accelerating(randomOffset()) ) .asComponent() ); game.add( Particle .gnerate( count: 10, generator: (i) { var position = Offset.zero; var speed = Offset.zero; final acceleration = randomOffset(); final paint = Paint().. color = Colors.red;returnComputedParticle( renderer: (canvas, _) { speed += acceleration; position += speed; canvas.drawCircle(position, 10, paint); }); }))Copy the code

You can find more examples of using different built-in particles in various combinations here.

Lifecycle


The common behavior of all particles is that they accept the lifespan parameter. This value is used to cause the ParticleComponent to self-destruct once its internal particles have reached their useful life. The time inside Particle uses the Flame Timer. It can be configured as a double to represent the second (subtle to the point) by passing it to the corresponding Particle constructor.

Particle(lifespan: .2);
Particle(lifespan: 4);
Copy the code

You can also reset the Particle life to receive seconds of type double by using the setLifespan method.

final particle = Particle(lifespan: 2);
particle.setLifespan(2);
Copy the code

During lifetimes, Particle tracks how long it has been alive and exposes progess progress, which is a floating-point unit with values ranging from 0 to 1. Its value is similar to the value of the AnimationController of the Flutter.

final duration = const Duration(seconds: 2);
final particle = Particle(lifespan: duration.inMicroseconds / Duration.microsecondsPerSecond);

game.add(ParticleComponent(particle: particle));

Timer.periodic(duration * .1, () => print(particle.progress));
Copy the code

If any internal construction behavior is supported, the life cycle is passed to all descendants of a given Particle.

The built-in particle


Flame comes with some built-in particle behavior:

  • TranslatedParticleBy the givenOffsettranslationchild
  • MovingParticle, in two predefinedOffsetMove itchildTo supportCurve
  • AcceleratedParticleAllows for basic physics-based effects such as gravity or velocity decay
  • CircleParticleRender all shapes and sizes of circles
  • SpriteParticleRender Flame Sprite in particle effect
  • ImageParticleRender the DART: UI in particle effectsImage
  • ComponentParticleRender Flame’s in particle effectComponent
  • FlareParticleRender the Flare animation in particle effects

More particles that use these behaviors together can be found here. All available implementations can be found in the Particles folder of the Flame source code.

Translated Particle


Simply move the particle to the specified render canvas cheaply. Do not change or modify the position. If you need to change position, consider using MovingParticle or AcceleratedParticle. The same effect can be achieved by panning the canvas.

game.add(
    ParticleComponent(
        particle: TranslatedParticle(
            offset: game.size.center(Offset.zero),
            child: Particle(),
        )
    )
);
Copy the code

Moving particles


In the life of a particle, it moves from from to to. Support Curve with CurvedParticle.

game.add(
    ParticleComponent(
        particle: MovingParticle(
            from: game.size.topLeft(Offset.zero),
            to: game.size.bottomRight(Offset.zero),
            child: Particle(),
        )
    )
);
Copy the code

2. Accelerated particles are Accelerated


A basic physics particle that allows you to specify its initial position, velocity, and acceleration, the update cycle does the rest. All three are offsets, you can think of them as vectors. This is particularly effective for, but not limited to, physics-based outbreaks. Offset is in logical pixels per second. So the speed of Offset(0, 100) moves child particles 100 device pixels per second during game time.

final rnd = Random();
game.add(
    ParticleComponent(
        particle AcceleratedParticle(
            position: game.size.center(Offset.zero),
            speed: Offset(rnd.nextDouble() *200 - 100, -rnd.nextDouble() * 100),
            acceleration: Offset(0, 100),
            child:Particle(),
        )
    )
);
Copy the code

Circle particles


Render round particles on brush offset by 0 value passed to canvas. In order to achieve to the location of the, combined TranslatedParticle, MovingParticle or AcceleratedParticle.

game.add( ParticleComponent( particle: CircleParticle( radius: game.size.width / 2, paint: Paint().. color = Colors.red.withOpacity(.5), ) ) );Copy the code

Sprite Particle


Sprites that allow you to insert Flame into particle effects. It’s useful to use shapes that have a SpriteSheet effect

game.add(
    ParticleComponent(
        particle: SpriteParticle(
            sprite: Sprite('sprite.png'),
            size: Position(64, 64),
        )
    )
);
Copy the code

Image particles


Render the given DART: UI image in the particle tree.

await Flame.images.loadAll(const [
    'image.png'
]);

game.add(
    ParticleComponent(
        particle: ImageParticle(
            size: const Size.square(24),
            image: Flame.images.loadedFiles['image.png'],)));Copy the code

Animation Particle


Embed the particle for Flame animation. By default, align the animation stepTime so that it is fully played in the particle life cycle. This behavior can be overridden with the alignAnimationTime parameter.

final spritesheet = SpriteSheet(
    imageName: 'spritesheet.png', textureWidth: 16, textureHeight: 16, columns: 10, rows: 2 ); game.add( ParticleComponent( particle: AnimationParticle( animation: spritesheet.createAnimation(0, stepTime: 0.1),)));Copy the code

Component Particle


Particle allows you to embed your Flame Component into Particle effects. Component can have its own Update life cycle and be reused in different effect trees. If the only thing you need is to add dynamic effects to some Component instances, consider adding them directly to the Game, without Particle in between.

var longLivingRect = RectComponent(); game.add( ParticleComponent( particle: ComponentParticle( component: longLivingRect ) ) ); class RectComponent extends Component { void render(Canvas c) { c.drawRect( Rect.fromCenter(center: Offset.zero, width: 100, height: 100), Paint().. color = Colors.red ); } void update(double dt) { } }Copy the code

Flare Particle


FlareAnimation’s container that passes update and Render hooks to its children.

Const flareSize = 32.0; final flareAnimation = await FlareAnimation.load('assets/sparkle.flr');
flareAnimation.updateAnimation('Shine');
flareAnimation.width = flareSize;
flareAnimation.height = flareSize;

game.add(
    ParticleComponent(
        particle: FlareParticle(flare: flareAnimation),
    )
);
Copy the code

Computed particles


Particle can help you in situations like:

  • The default behavior is not enough
  • Complex effect optimization
  • Simplified customization

When created, the ParticleRenderDelegate provides a proxy for all rendering, is called in each frame, and performs the necessary calculations to render to the canvas. Once created, delegate all rendering to the supplied ParticleRenderDeletegate, calling the class on each frame to perform the necessary calculations and render something to the Canvas.

game.add( ParticleComponent( particle: ComputedParticle( renderer: (canvas, particle) => canvas.drawCircle( Offset.zero, particle.progress * 10, Paint() .. color = Color.lerp( Colors.red, Colors.blue, particle.progress, ) ) ) ) )Copy the code

Nesting Behavior


The particle implementation of Flame follows the same extreme synthesis pattern as the Flutter component. Encapsulate a small part of the behavior of each particle and then embed it together to achieve the desired visual effect.

Two entities that allow particles to be embedded within each other are the SingleChildParticle Mixin and ComposedParticle classes.

SingleChildParticle helps you create particles with custom behavior. For example, place the child components randomly in each frame:

var rnd = Random(); class GlitchParticle extends Particle with SingleChildParticle { @override Particle child; GlitchParticle({ @required this.child, double lifespan, }) : super(lifespan: lifespan); @override render(Canvas canvas) { canvas.save(); canvas.translate(rnd.nextDouble(0 * 100, rnd.nextDouble() *100); super.render(); canvas.restore(); }}Copy the code

ComposedParticle can be used alone or in existing particle species.