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

感谢阅读:

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

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

相关推荐
程序视点3 分钟前
Escrcpy 3.0投屏控制软件使用教程:无线/有线连接+虚拟显示功能等
android
什么都想学的阿超10 分钟前
【大语言模型 17】高效Transformer架构革命:Reformer、Linformer、Performer性能突破解析
语言模型·架构·transformer
布列瑟农的星空2 小时前
大话设计模式——关注点分离原则下的事件处理
前端·后端·架构
东京老树根3 小时前
Android - 用Scrcpy 将手机投屏到Windows电脑上
android
Aileen_0v03 小时前
【分布式系统架构全解析:从单机到微服务,Redis如何成为性能加速器?】
redis·微服务·云原生·架构
扛麻袋的少年4 小时前
6.Kotlin的Duration类
android·开发语言·kotlin
独自破碎E4 小时前
得物25年春招-安卓部分笔试题1
android
程序猿阿伟4 小时前
《支付回调状态异常的溯源与架构级修复》
后端·架构
雨白5 小时前
Android 自定义 View:精通文字的测量与高级排版
android