完整烟花效果,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绘制圆圈点来展示烟花微粒。

感谢阅读:

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

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

相关推荐
眠りたいです4 小时前
基于脚手架微服务的视频点播系统-脚手架开发部分-brpc中间件介绍与使用及二次封装
c++·微服务·中间件·rpc·架构·brpc
Broken Arrows5 小时前
k8s学习(二)——kubernetes整体架构及组件解析
学习·架构·kubernetes
BD_Marathon6 小时前
【MySQL】函数
android·数据库·mysql
西西学代码7 小时前
安卓开发---耳机的按键设置的UI实例
android·ui
唐僧洗头爱飘柔95278 小时前
【SpringCloud(1)】初识微服务架构:创建一个简单的微服务;java与Spring与微服务;初入RestTemplate
java·spring·spring cloud·微服务·架构·resttemplate·java微服务技术栈
可触的未来,发芽的智生10 小时前
触摸未来2025.10.05:悟神经网络符号之伤,拥抱声音的宇宙
人工智能·python·神经网络·算法·架构
maki07711 小时前
虚幻版Pico大空间VR入门教程 05 —— 原点坐标和项目优化技巧整理
android·游戏引擎·vr·虚幻·pico·htc vive·大空间
yunmi_11 小时前
微服务,Spring Cloud 和 Eureka:服务发现工具
java·spring boot·spring cloud·微服务·eureka·架构·服务发现
一叶飘零_sweeeet11 小时前
从 0 到 PB 级存储:MinIO 分布式文件系统实战指南与架构解密
java·架构·大文件存储
千里马学框架11 小时前
音频焦点学习之AudioFocusRequest.Builder类剖析
android·面试·智能手机·车载系统·音视频·安卓framework开发·audio