春节快到了,来写个烟花动效吧

843501e2f2e7334aa6448e045d3b3190.gif

作者 | Eason

来源 | 程序员巴士

2022虎年大吉,预祝各位小伙伴们新年快乐,这篇文章教大家如何在 Canvas 中实现高性能的烟花粒子特效,通过使用 Canvas + BitmapShader + GestureDetector技术栈,实现趣味 2D 春节烟花特效页面,采用 velocity 和 acceleration 展示模型速度变化及PVector 2D简单动画效果等,每点击一下屏幕会产生一枚烟花,烟花飞到最上空会炸裂成60~100个碎片,同屏可能有上千个粒子在不停更新它的位置,希望给大家带来一些好玩有趣的东西!

作品演示

918814fa828bfd098891c3bc8f763718.gif

代码分析

首先看看项目结构

└─fireworksColorfullView.java -自定义的viewFirework.java -对烟花建立模型MainActivity.javaParticle.java -粒子PContext.java -工具类PVector.java  -向量类

XML代码

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#ffffff"tools:context="com.example.MainActivity"><RelativeLayoutandroid:layout_width="200dp"android:layout_height="200dp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"><ImageViewandroid:id="@+id/iv_text"android:layout_width="130dp"android:layout_height="130dp"android:layout_centerInParent="true"android:background="#EE4D1E" /><TextViewandroid:id="@+id/text"android:layout_width="200dp"android:layout_height="200dp"android:gravity="center"android:text="福"android:textSize="120sp" /></RelativeLayout><com.example.ColorfullViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent" /></android.support.constraint.ConstraintLayout>

Java代码

  • 自定义 ColorfullView 中使用 GestureDetector 处理用户输入,每点击一次在当前位置创建一枚烟花

mGesture = new GestureDetectorCompat(getContext(), new GestureDetector.SimpleOnGestureListener() {@Overridepublic boolean onDown(MotionEvent e) {fireworks.add(new Firework(e.getX(), e.getY()));ViewCompat.postInvalidateOnAnimation(ColorfullView.this);return true;}});
  • FireWork类包含两个属性,分别包含了炸开前 “种子” 的信息,和炸开后所发散的粒子,由于爆炸后的每个粒子也有对应的位置和速度信息,因此把这些粒子又当成 “种子” 来归属到一束烟花里,这些粒子信息都统一被封装成 Particle 这个Bean类;

ArrayList<Particle> particles;    // 炸开后的粒子Particle firework;                // 炸开前的粒子
  • Particle类具有随机的颜色、大小、速度以接近真实,同时设定了烟花种子的初始位置坐标和半径等信息,每个烟花种子发散出来的粒子位置会根据种子最终爆炸位置进行确定

class Particle {PVector location;PVector velocity;PVector acceleration;float radius;//烟花种子Particle(float x, float y, float hue) {this.hu = hue;acceleration = new PVector(0, 0);velocity = new PVector(0, PContext.random(-20, -10));location = new PVector(x, y);seed = true;life = PContext.random(350.0f, 555.0f);this.radius = PContext.random(10, 20);}//烟花粒子Particle(PVector loc, float hue) {this.hu = hue;acceleration = new PVector(0, 0);velocity = PVector.random2D();velocity.mult(PContext.random(4, 8));location = loc.get();life = PContext.random(350.0f, 555.0f);this.radius = PContext.random(10, 20);}
  • 每绘制一帧会调用FireWork的run方法,该方法中会在 view 的 onDraw 回调中去不断调用当前粒子的update和display方法;update方法用于更新每个粒子的速度、加速度和位置坐标,display方法用于根据粒子位置进行绘制;

void run(Canvas canvas, Paint paint) {if (firework != null) {//炸裂前firework.applyForce(gravity);firework.update();firework.display(canvas, paint);if (firework.explode()) {int fragments = (int) random(60, 100);//碎片个数for (int i = 0; i < fragments; i++) {particles.add(new Particle(firework.location, hu));}firework = null;firstExplode = true;}} else {//炸裂后if (firstExplode) {//屏幕一闪firstExplode = false;canvas.drawColor(Color.HSVToColor(new float[]{hu, 0.6f, 0.6f}));}for (int i = particles.size() - 1; i >= 0; i--) {Particle p = particles.get(i);p.applyForce(gravity);p.update();p.display(canvas, paint);if (p.isDead()) {particles.remove(i);}}}}

性能优化

这时候功能基本实现了,剩下的就是将每一个烟花绘制在canvas上,通常我们会这样写

@Overrideprotected void onDraw(Canvas canvas) {canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);for (int i = fireworks.size() - 1; i >= 0; i--) {Firework f = fireworks.get(i);f.run(canvas, mParticlePaint);if (f.done()) {fireworks.remove(i);}}//canvas.drawBitmap(canvasBitmap,0, 0, mBitmapPaint);if (!fireworks.isEmpty()) {ViewCompat.postInvalidateOnAnimation(this);}}

然而你会发现性能很糟糕,帧数随着粒子数的增加直线下降直到个位数,优化如下:

@Overrideprotected void onDraw(Canvas canvas) {if (canvasBitmap == null || canvasBitmap.isRecycled()) {canvasBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);bitmapCanvas = new Canvas(canvasBitmap);mBitmapShader = new BitmapShader(canvasBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);mBitmapPaint.setShader(mBitmapShader);mBitmapPaint.setDither(false);}bitmapCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);for (int i = fireworks.size() - 1; i >= 0; i--) {Firework f = fireworks.get(i);f.run(bitmapCanvas, mParticlePaint);if (f.done()) {fireworks.remove(i);}}canvas.drawPaint(mBitmapPaint);if (!fireworks.isEmpty()) {ViewCompat.postInvalidateOnAnimation(this);}}

写在最后

到这里整个烟花动效就完成了,在这里提前给各位拜年了!祝大家工作顺利,身体健康,全家和和美美,万事如意!

7dc6d87cbf5f52464b2efe0e6fbc1474.png

c13f85fe2d0bf609eee44f4f05e2b95a.gif

往期推荐

好难啊……一个 try-catch 问出这么多花样

k8s集群居然可以图形化安装了?

恶意流量威胁新趋势,揭秘网络黑产3大核心本质

将 k8s 制作成 3D 射击游戏,好玩到停不下来

8d93fe2da4209d03ac3813c8f12580e7.gif

点分享

9cf64f9dbfc9e63770f8916916e614fa.gif

点收藏

b9803f33c61bc04129e455005595cdf0.gif

点点赞

d877d445a5d143c5f60831b1f10d6a4a.gif

点在看

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/512370.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

商用服务器系统比较好,商用服务器操作系统都用哪种

商用服务器操作系统都用哪种 内容精选换一换切换弹性云服务器操作系统。支持弹性云服务器数据盘不变的情况下&#xff0c;使用新镜像重装系统盘。调用该接口后&#xff0c;系统将卸载系统盘&#xff0c;然后使用新镜像重新创建系统盘&#xff0c;并挂载至弹性云服务器&#xff…

边缘使用 K8s 门槛太高?OpenYurt 这个功能帮你快速搭建集群!

简介&#xff1a; 为了降低 OpenYurt 的使用门槛&#xff0c;帮助更多地开发者快速上手 OpenYurt&#xff0c;社区提供了 OpenYurt 易用性工具 yurtctl。该工具致力于屏蔽 OpenYurt 集群创建的复杂性&#xff0c;帮助开发者在本地快速地搭建 OpenYurt 开发测试集群。 OpenYurt…

Effective Java 在工作中的应用总结

简介&#xff1a; 《Effective Java》是一本经典的 Java 学习宝典&#xff0c;值得每位 Java 开发者阅读。笔者将书中和平日工作较密切的知识点做了部分总结。 作者 | 宜秋 来源 | 阿里技术公众号 《Effective Java》是一本经典的 Java 学习宝典&#xff0c;值得每位 Java 开发…

harfbuzz安装位置 linux_最新Ubuntu 20.04 LTS已发布,在Win10中该如何进行安装和使用?...

最近Ubuntu发布最新的20.04 LTS长期支持版本&#xff0c;官方提供为期5年的更新升级、安全修复等服务。国内的优麒麟团队也同步放出了优麒麟20.04 LTS&#xff0c;加入了全新的UKUI 3.0桌面环境。那么如何在微软的Windows系统中安装体验最新的Ubuntu系统呢&#xff1f;实际上相…

如何查看华为服务器配置信息,查看服务器网络配置信息

查看服务器网络配置信息 内容精选换一换ECS的网卡绑定虚拟IP地址后&#xff0c;该虚拟IP地址无法ping通。以下排查思路根据原因的出现概率进行排序&#xff0c;建议您从高频率原因往低频率原因排查&#xff0c;从而帮助您快速找到问题的原因。如果解决完某个可能原因仍未解决问…

通过Kubernetes监控探索应用架构,发现预期外的流量

简介&#xff1a; Kubernetes 监控立足于应用监控之下的 Kubernetes 容器界面和底层操作系统&#xff0c;是 Kubernetes 集群软件栈端到端可观测性的一体化解决方案&#xff0c;在 Kubernetes 监控中可以同时看到关联的所有层的观测数据。我们希望通过 Kubernetes 监控的一系列…

追踪 Kubernetes 中的网络流量

作者 | Addo Zhang来源 | 云原生指北译者注&#xff1a;这篇文章很全面的罗列出了 Kubernetes 中涉及的网络知识&#xff0c;从 Linux 内核的网络内容&#xff0c;到容器、Kubernetes&#xff0c;一一进行了详细的说明。文章篇幅有点长&#xff0c;不得不说&#xff0c;网络是很…

Go 语言网络库 getty 的那些事

简介&#xff1a; Getty 维护团队不追求无意义的 benchmark 数据&#xff0c;不做无意义的炫技式优化&#xff0c;只根据生产环境需求来进行自身改进。只要维护团队在&#xff0c;Getty 稳定性和性能定会越来越优秀。 个人从事互联网基础架构系统研发十年余&#xff0c;包括我…

std中稳定排序算法_源代码库已开放 | 哈工大硕士生用 Python 实现了 11 种经典数据降维算法...

转自&#xff1a;AI开发者网上关于各种降维算法的资料参差不齐&#xff0c;同时大部分不提供源代码。这里有个 GitHub 项目整理了使用 Python 实现了 11 种经典的数据抽取(数据降维)算法&#xff0c;包括&#xff1a;PCA、LDA、MDS、LLE、TSNE 等&#xff0c;并附有相关资料、展…

曲师大教务系统服务器,曲师大教务处信息门户入口地址

为了规范财务行为&#xff0c;加强财务管理&#xff0c;提高代管经费使用效益&#xff0c;提高项目建设质量&#xff0c;根据上级和学校有关财务规定&#xff0c;结合我校实际情况&#xff0c;特制定本办法。一、教务处代管的项目经费品牌特色专业建设经费、精品课程建设经费、…

云网管—云上构建网络自动化体系

简介&#xff1a; 云网管是基于阿里云网络多年技术和经验沉淀打造的云上智能网络管理运维平台&#xff0c;提供企业网络全生命周期管理运维的能力&#xff0c;让部署更快捷、运维更高效、网络更透明。 1.背景 云网管是基于阿里云网络多年技术和经验沉淀打造的云上智能网络管理…

【C++练级之路】【Lv.5】动态内存管理(都2023年了,不会有人还不知道new吧?)

目录 一、C/C内存分布二、new和delete的使用方式2.1 C语言内存管理2.2 C内存管理2.2.1 new和delete操作内置类型2.2.2 new和delete操作自定义类型 三、new和delete的底层原理3.1 operator new与operator delete函数3.2 原理总结3.2.1 内置类型3.2.2 自定义类型 四、定位new表达…

开工啦~Spring 完美导入 IDEA

作者 | 阿Q来源 | 阿Q说代码有小伙伴私信我说想要研究下Spring的源码&#xff0c;想让我出一期教程来实现IDEA导入Spring源码&#xff0c;今天它来了~版本 &#xff1a;IDEA 2020.2.3 &#xff1b;Spring 5.0.x &#xff1b;gradle 4.4.1 &#xff1b;先从github上面把 spring …

基于MaxCompute分布式Python能力的大规模数据科学分析

简介&#xff1a; 如何利用云上分布式 Python 加速数据科学。 如果你熟悉 numpy、pandas 或者 sklearn 这样的数据科学技术栈&#xff0c;同时又受限于平台的计算性能无法处理&#xff0c;本文介绍的 MaxCompute 可以让您利用并行和分布式技术来加速数据科学。也就是说只要会用…

5新建没有头文件_开垦绿茵版图迎来“真金白银”保障,新建足球场地可获财政补贴...

本周二&#xff0c;国家发改委、体育总局、国务院足球改革发展部际联席会议办公室共同制定了《全国社会足球场地设施建设专项行动实施方案(试行)》。《方案》指出&#xff0c;对新建11人制标准足球场&#xff0c;每个球场补助200万元&#xff1b;对新建5人制、7人制(8人制)足球…

网站免费空间和服务器的区别,网站空间和服务器的区别

网站空间和服务器的区别 内容精选换一换汇总对象存储服务OBS的各项功能&#xff0c;并对其进行简单的介绍&#xff0c;帮助您从整体上了解OBS的功能特性。CCE Turbo集群是基于云原生基础设施构建的云原生2.0容器引擎服务&#xff0c;具备软硬协同、网络无损、安全可靠、调度智能…

基于 MaxCompute + Hologres 的人群圈选和数据服务实践

简介&#xff1a; 本文主要介绍如何通过 MaxCompute 进行海量人群的标签加工&#xff0c;通过 Hologres 进行分析建模&#xff0c;从而支持大规模人群复杂圈选场景下的交互式体验&#xff0c;以及基于API的数据服务最佳实践。 本文作者 刘一鸣 阿里云智能 高级产品专家 人群圈…

一款强大的 Kubernetes API 流量查看神器

作者 | 小碗汤来源 | 我的小碗汤mizu 是为 Kubernetes 提供的一个简单而强大的 API 流量查看器&#xff0c;可以查看微服务之间的所有 API 通信&#xff0c;以帮助调试和排除故障。相当于 Kubernetes 的 TCPDump 和 Wireshark。简单而强大的 CLI丰富的过滤规则API 调用实时监控…

Redis 巧用数据类型实现亿级数据统计

作者 | 码哥字节来源 | 码哥字节在移动应用的业务场景中&#xff0c;我们需要保存这样的信息&#xff1a;一个 key 关联了一个数据集合&#xff0c;同时还要对集合中的数据进行统计排序。常见的场景如下&#xff1a;给一个 userId &#xff0c;判断用户登陆状态&#xff1b;两亿…

2021杭州·云栖大会来了!门票免费预约!

2021杭州云栖大会&#xff0c;定了&#xff01; 10月19日-22日&#xff0c;就在杭州云栖小镇 2场重磅主论坛上百场分论坛 超4万平米科技展 今年&#xff0c;云栖大会将首次免费开放 门票可在官网免费预约 入口现已开启 戳此预约&#xff0c;我们不见不散&#xff01; ​ …