完整烟花效果,Compose + 协程 + Flow + Channel 轻松实现

动画特效里面,烟花是比较常见的一种,特别是在做夜间背景或者节日活动的时候。

一、前言:

新一代烟花效果实现方式:Compose + 协程 + Flow + Channel + 实现

  • 核心逻辑设计:
  1. 采用三层设计结构来完成:数据层即:粒子模型、逻辑层即:协程更新、视图层即:Compose渲染
  2. 采用响应式编程:通过State和Flow实现数据驱动UI
  3. 采用新一代声明式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 设计

通过 ComposeCanvasdrawCircle绘制圆圈点来展示烟花微粒,采用混合模式(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 + 实现 主要涉及到了:

  1. 烟花堆中的微粒子系统使用协程Flow实现高性能更新,通过Channel处理用户交互命令
  2. 每个烟花爆炸的生成主要是由80-130个随机运动轨迹的粒子,通过 Color.hsl(色调, 饱和度%, 亮度%)``模拟每个粒子颜色渐变,模拟真实物理效果
  3. 烟花堆中的每个微粒子包含生命周期衰减和速度衰减,实现自然消失效果
  4. 为了达到更加逼真效果,采用混合模式(BlendMode)增强视觉效果,包含粒子光晕和拖尾
  5. 支持点击屏幕任意位置发射随机颜色烟花。
  6. UI方面主要通过 ComposeCanvasdrawCircle绘制圆圈点来展示烟花微粒。

感谢阅读:

欢迎用你发财的小手 关注,点赞、收藏

这里你会学到不一样的东西

相关推荐
天空属于哈夫克313 小时前
企业微信二次开发:精准实现关键词自动回复
架构·企业微信
千里马学框架14 小时前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台14 小时前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone14 小时前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
晨米酱15 小时前
AGENTS.md:Agent 的上下文策略层
面试·架构·agent
这个DBA有点耶15 小时前
MVCC深入:Read View、版本链与快照读——InnoDB并发控制的内核
数据库·mysql·架构
致远ccc15 小时前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
码流子16 小时前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
ttyyttemo17 小时前
Kotlin 协程中的 Job 结构化并发与取消
android
moMo17 小时前
从固定流程到问题路由:让 LangGraph RAG 按需检索
架构