
动画特效里面,烟花是比较常见的一种,特别是在做夜间背景或者节日活动的时候。
一、前言:
新一代烟花效果实现方式:Compose + 协程 + Flow + Channel + 实现
- 核心逻辑设计:
- 采用三层设计结构来完成:数据层即:粒子模型、逻辑层即:协程更新、视图层即:Compose渲染
- 采用响应式编程:通过State和Flow实现数据驱动UI
- 采用新一代声明式UI Compose来完成展示烟花效果。
二、 烟花粒子系统模型设计
Firework
:烟花数据模型
launchTime
:一次烟花的绽放,需要烟花绽放时间,方便短时间后清楚计算时间
particles
:一次的烟花总共需要多少个微粒子组成,具体生产那边是随机生产
color
:烟花绽放的粒子基础颜色,具体到每个烟花微粒上面的颜色根据透明度和衰减计算:具体方法: color = firework.color.copy(alpha = particle.alpha * particle.life)
Particle
: 烟花微粒子模型:
position
:具体到一堆粒子中每个微粒的位置
velocity
:每个微粒子受到的空气阻力
size
:每个微粒子大小
alpha
:每个微粒子透明度
life
:每个微粒子生命周期衰减,直到完全消失
kotlin
//烟花模型
data class Firework(
val particles: List<Particle>,//一次的烟花总共需要多少个微粒子组成
val color: Color, //烟花颜色
val launchTime: Long = System.currentTimeMillis()//烟花绽放时间,方便短时间后清楚计算时间
)
//微粒子
data class Particle(
val position: Offset, //展示位置
val velocity: Offset, // 空气阻力
val size: Float, //烟花大小
val alpha: Float, //透明度
val life: Float = 1f // 生命周期衰减
)
三、烟花粒子控制器:
- 1、设置控制粒子命令:密封类
FireworkCommand
:包含,执行开始(开始执行时,带有烟花绽放基础位置),执行清除两个命令。
kotlin
sealed class FireworkCommand {
data class Launch(val position: Offset) : FireworkCommand()
object Clear : FireworkCommand()
}
- 2、初始化开始:粒子系统使用协程Flow实现高性能更新,通过Channel处理用户交互命令,性能优化确保60fps流畅运行,
createFirework
:开始产生烟花粒子,对外提供两方法:执行烟花启动开始的launch(position: Offset)
方法和 清除烟花fun clear()
方法和 停止方法fun stop()
kotlin
private val scope = CoroutineScope(Dispatchers.Default)
private val _fireworks = mutableStateListOf<Firework>()
val fireworks: List<Firework> get() = _fireworks
private val commandChannel = Channel<FireworkCommand>()
fun start() {
scope.launch {
commandChannel.consumeAsFlow().collect { command ->
when (command) {
is FireworkCommand.Launch -> createFirework(command.position)//
FireworkCommand.Clear -> _fireworks.clear()
}
}
}
scope.launch {
while (true) {
updateFireworks()
delay(16) // ~60fps
}
}
}
//执行烟花启动开始
fun launch(position: Offset) {
scope.launch {
commandChannel.send(FireworkCommand.Launch(position))
}
}
//清除烟花
fun clear() {
scope.launch {
commandChannel.send(FireworkCommand.Clear)
}
}
//停止
fun stop() {
scope.cancel()
}
- 3、每个烟花爆炸生成 80-130 个随机运动轨迹的粒子,通过
Color.hsl(色调, 饱和度%, 亮度%)``模拟每个粒子颜色渐变
,这样就可以模拟出真实物理效果:
scss
private fun createFirework(position: Offset) {
val particleCount = 80 + Random.nextInt(50)
val color = Color.hsl(
Random.nextFloat() * 360f, 1f, 0.7f
)
_fireworks.add(
Firework(
particles = List(particleCount) {
val angle = Random.nextFloat() * 2f * PI.toFloat()
val speed = 2f + Random.nextFloat() * 5f
Particle(
position = position, velocity = Offset(
cos(angle) * speed, sin(angle) * speed
), size = 3f + Random.nextFloat() * 5f, alpha = 0.9f + Random.nextFloat() * 0.1f
)
}, color = color
)
)
}
- 4、粒子包含生命周期衰减和速度衰减,实现自然消失效果,其中:
采用了物理模拟包含速度衰减(0.98系数)和重力影响
,粒子生命周期线性衰减(1.0→0.0)
,通过System.currentTimeMillis()管理烟花存活时间(3秒)
ini
private fun updateFireworks() {
val currentTime = System.currentTimeMillis()
val updatedFireworks = _fireworks.map { firework ->
val updatedParticles = firework.particles.map { particle ->
if (particle.life > 0) {
val newVelocity = particle.velocity * 0.98f
particle.copy(
position = particle.position + newVelocity, velocity = newVelocity, life = particle.life - 0.01f
)
} else particle
}
firework.copy(particles = updatedParticles)
}
_fireworks.clear()
_fireworks.addAll(updatedFireworks.filter {
currentTime - it.launchTime <= 3000 && it.particles.any { p -> p.life > 0 }
})
}
四、烟花展示UI Compose 设计
通过 Compose
的 Canvas
的drawCircle
绘制圆圈点来展示烟花微粒,采用混合模式(BlendMode)增强视觉效果,包含粒子光晕和拖尾
,烟花颜色通过基础颜色,外加微粒子的透明度alpha
和微粒子的衰减life
,组合成渐变的烟花效果,即: color = firework.color.copy(alpha = particle.alpha * particle.life)
ini
@Composable
fun FireworkDisplay(
modifier: Modifier = Modifier,
controller: FireworkController = remember { FireworkController().apply { start() } }
) {
Canvas(
modifier = modifier
.fillMaxSize()
.pointerInput(Unit) {
detectTapGestures { offset ->
controller.launch(offset)//点击屏幕任意位置发送烟花效果
}
}
) {
controller.fireworks.forEach { firework ->
firework.particles.forEach { particle ->
if (particle.life > 0) {
drawCircle(
color = firework.color.copy(alpha = particle.alpha * particle.life),
radius = particle.size * particle.life,
center = particle.position,
blendMode = BlendMode.Plus
)
// 拖尾效果
drawCircle(
brush = Brush.radialGradient(
colors = listOf(
firework.color.copy(alpha = 0.3f * particle.life),
Color.Transparent
),
radius = particle.size * 2f
),
radius = particle.size * 4f,
center = particle.position,
blendMode = BlendMode.Screen
)
}
}
}
}
}
五、总结
本文重点介绍了:新一代烟花效果实现方式:Compose + 协程 + Flow + Channel + 实现 主要涉及到了:
- 烟花堆中的微粒子系统使用协程Flow实现高性能更新,通过Channel处理用户交互命令
- 每个烟花爆炸的生成主要是由80-130个随机运动轨迹的粒子,通过
Color.hsl(色调, 饱和度%, 亮度%)``模拟每个粒子颜色渐变
,模拟真实物理效果 - 烟花堆中的每个微粒子包含生命周期衰减和速度衰减,实现自然消失效果
- 为了达到更加逼真效果,采用混合模式(
BlendMode
)增强视觉效果,包含粒子光晕和拖尾 - 支持点击屏幕任意位置发射随机颜色烟花。
- UI方面主要通过
Compose
的Canvas
的drawCircle
绘制圆圈点来展示烟花微粒。