Particle -- 粒子
Flame提供了基本的,同時也很強大的,可擴充套件的粒子系統。這個系統的核心概念是Particle
類,在行為上和ParticleComponent
很相似。
Particle
在BaseGame
的最基本使用如下:
import 'package:flame/components/particle_component.dart';
game.add(
ParticleComponent(
particle: CircleParticle()
);
);
複製程式碼
當Particle
和自定義的Game
實現一起使用時,請確保在每次遊戲迴圈幀時,Particle
的update
和render
生命週期鉤子被呼叫。
實現想要的粒子效果的主要方式:
- 現有行為的組合
- 使用行為鏈(只是一個語法糖)
- 使用
ComputedParticle
通過從上到下的效果,合成的工作方式與Flutter小部件的工作方式類似。通過定義自底向上的行為,鏈式允許更流暢的表達相同的組合樹。計算粒子又將行為的實現完全委派給您的程式碼。在需要的地方,任何方式都可以和現存的行為組合使用。
下面你可以看到顯示使用上面定義的三種方式從(0,0)加速到隨機方向的一個圓圈的效果示例。
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;
return ComputedParticle(
renderer: (canvas, _) {
speed += acceleration;
position += speed;
canvas.drawCircle(position, 10, paint);
}
);
}
)
)
複製程式碼
你可以在這裡找到更多以各種組合使用不同的內建粒子的示例。
Lifecycle 生命週期
所有Particle
的普遍行為是它們都接受lifespan
引數。一旦其內部粒子達到其使用壽命時,該值用於使ParticleComponent
自我銷燬。Particle
內部的時間使用Flame的Timer
。可以將其配置為double
,通過將其傳遞到相應的Particle構造器來表示秒(精確到微妙)。
Particle(lifespan: .2);
Particle(lifespan: 4);
複製程式碼
通過使用setLifespan
方法,也可以重置Particle
壽命,接收double型別的秒。
final particle = Particle(lifespan: 2);
particle.setLifespan(2);
複製程式碼
在存活時間內,Particle
追蹤它存活的時間,並暴露progess
進度,這是一個浮點型單位,值從0跨度到1.它的值與Flutter的AnimationController的value值類似。
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));
複製程式碼
如果支援任何一個內建行為,生命週期會被傳遞給定Particle
的所有後代。
內建粒子
Flame附帶了一些內建的粒子行為:
TranslatedParticle
,通過給定的Offset
平移child
MovingParticle
,在兩個預定義的Offset
移動它的child
,支援Curve
AcceleratedParticle
,允許基本的基於物理的效果,比如重力或者速度衰減CircleParticle
,渲染所有形狀和大小的圓形SpriteParticle
,在粒子效果中渲染Flame精靈ImageParticle
,在粒子效果中渲染dart:ui的Image
ComponentParticle
,在粒子效果中渲染Flame的Component
FlareParticle
,在粒子效果中渲染Flare動畫
一起使用這些行為的更多粒子可以在這裡找到。所有的可用實現都可以在Flame原始碼的particles資料夾中找到。
Translated Particle
只需平移粒子到渲染畫布的指定便宜即可。不改變或修改位置。如果需要改變位置,考慮使用MovingParticle
或者AcceleratedParticle
。通過平移畫布也可以達到相同的效果。
game.add(
ParticleComponent(
particle: TranslatedParticle(
offset: game.size.center(Offset.zero),
child: Particle(),
)
)
);
複製程式碼
Moving Particle 移動粒子
在粒子的生命週期中,從from
移動到to
。通過CurvedParticle
支援Curve
。
game.add(
ParticleComponent(
particle: MovingParticle(
from: game.size.topLeft(Offset.zero),
to: game.size.bottomRight(Offset.zero),
child: Particle(),
)
)
);
複製程式碼
Accelerated Particle 加速粒子
一個允許你指定它的初始位置,速度和加速度的基本物理粒子,update
週期完成剩餘工作。三個指定的都是Offset
,你可以認為是向量。對於基於物理的爆發尤其有效,但不侷限於此。Offset
的單位是每秒邏輯畫素。所以Offset(0, 100)的速度會在遊戲時間的每秒移動子粒子100個裝置畫素。
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(),
)
)
);
複製程式碼
Circle Particle 原型粒子
傳遞給畫布的0值偏移的畫筆上渲染圓形的粒子。為了達到想要的位置,組合使用TranslatedParticle
,MovingParticle
或者AcceleratedParticle
。
game.add(
ParticleComponent(
particle: CircleParticle(
radius: game.size.width / 2,
paint: Paint()..color = Colors.red.withOpacity(.5),
)
)
);
複製程式碼
Sprite Particle 精靈粒子
允許你在粒子效果中插入Flame的精靈。使用SpriteSheet效果的圖形時很有用
game.add(
ParticleComponent(
particle: SpriteParticle(
sprite: Sprite('sprite.png'),
size: Position(64, 64),
)
)
);
複製程式碼
Image Particle 圖片粒子
在粒子樹種渲染給定的dart:ui
圖片。
await Flame.images.loadAll(const [
'image.png'
]);
game.add(
ParticleComponent(
particle: ImageParticle(
size: const Size.square(24),
image: Flame.images.loadedFiles['image.png'],
)
)
);
複製程式碼
Animation Particle 動畫粒子
嵌入Flame動畫的粒子。預設情況下,對齊“動畫” stepTime,以便在“粒子”生命週期中完全播放。可以使用alignAnimationTime
引數覆蓋此行為.
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),
)
)
);
複製程式碼
Component Particle 元件粒子
Particle
允許你將Flame Component嵌入到粒子效果中。Component
可以有自己的update
生命週期,並且在不同的效果樹種被重用。如果您唯一需要的是向某些Component的例項新增一些動態效果,請考慮將其直接新增到Game
中,而中間不包含Particle
。
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) {
}
}
複製程式碼
Flare Particle
FlareAnimation
的容器,向它的子代傳遞update
和render
鉤子。
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),
)
);
複製程式碼
Computed Particle 計算的粒子
Particle
可以在如下情況幫助你:
- 預設的行為不夠
- 複雜效果優化
- 簡化自定義
當建立的時候,提供的ParticleRenderDelegate
代理所有的渲染,在每一幀被呼叫,並且執行必要的計算,渲染到畫布上。
建立後,將所有渲染委託給提供的ParticleRenderDeletegate
,在每一幀上呼叫該類,以執行必要的計算並將某些內容渲染到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,
)
)
)
)
)
複製程式碼
Nesting behavior 內嵌行為
Flame的粒子實現遵循與Flutter 小元件相同的極端合成模式。封裝每個粒子的小部分行為,然後嵌入到一起來達到想要的視覺效果來實現的。
允許粒子內嵌彼此的兩個實體是:SingleChildParticle
mixin 和ComposedParticle
類。
SingleChildParticle
可以幫助你建立自定義行為的粒子。
比如,在每幀中隨機放置子元件的位置:
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();
}
}
複製程式碼
ComposedParticle
可以單獨使用,也可以使用在已存的粒子樹種。