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)
- use
ComputedParticle
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:
TranslatedParticle
By the givenOffset
translationchild
MovingParticle
, in two predefinedOffset
Move itchild
To supportCurve
AcceleratedParticle
Allows for basic physics-based effects such as gravity or velocity decayCircleParticle
Render all shapes and sizes of circlesSpriteParticle
Render Flame Sprite in particle effectImageParticle
Render the DART: UI in particle effectsImage
ComponentParticle
Render Flame’s in particle effectComponent
FlareParticle
Render 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.