作者 | Eason

来源 | 程序员巴士

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

作品演示

代码分析

首先看看项目结构

└─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);}}

写在最后

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

往期推荐

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

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

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

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

点分享

点收藏

点点赞

点在看

春节快到了,来写个烟花动效吧相关推荐

  1. 前端canvas动效实战,PIXI+GSAP仿写vanmoof刹车动效 | 猿创营

    前言 事情是这样的,上个月接了一个活儿.客户要我们模仿一个国外的网站 https://www.vanmoof.com/en-NL/s3?color=dark 为他们做几个展示动效. 确实很酷!这个项目 ...

  2. css3实现烟花效果,CSS3 带颤动效果的简易烟花动效

    CSS 语言: CSSSCSS 确定 body { margin: 0; padding: 0; background: #000; overflow: hidden; } .pyro > .b ...

  3. 马上春节,快来跟我学习做烟花,包教包会(html+css+js)

    雷迪森安的乡亲们,欢迎来到老实人的前端课堂,上次写了一个新春小盲盒,这大过年的,我把烟花都给你们准备好了,今天我们来写个小烟花吧. 正片 注意看有两种模式哦,可以自由切换,鼠标点哪里哪里有烟花,还可以 ...

  4. 快来试试Python写的游戏《我的世界》

    <我的世界 Minecraft>大家应该都听说过,但你有没有想过自己用Python写一个这样的游戏呢?太难.太复杂了?也许吧,但是不试一试你怎么知道能不能成呢? 国外有位叫fogleman ...

  5. 随笔转载:母亲节快到了,写下对妈妈的祝福~

    母亲节在希腊 母亲节起源于希腊,古希腊人在这一天向希腊神话中的众神之母赫拉致敬.在17世纪中叶,母亲节流传到英国,英国人把封斋期的第四个星期天作为母亲节.在这一天里,出门在外的年青人将回到家中, 给他 ...

  6. 如何利用Citespace和vosviewer既快又好地写出高质量的论文及快速锁定热点和重点文献进行可视化分析?

    基于Citespace和vosviewer文献计量学可视化SCI论文高效写作方法 CiteSpace是什么? 简单来说,它一款通过将国内外文献进行可视化分析来帮助你了解一门学科前世今生的软件. 面对成 ...

  7. 仿抖音短视频系统源码烟花爆炸动效

    越来越多的地方都会用到烟花效果了,而且很多游戏都会有类似通关之后的爆炸特效,今天来分享一下烟花爆炸的动效.升空的动画就不用写了,主要就写个view的位移,重点就是四散开来的爆炸. 下面就来看如何处理的 ...

  8. 自己去年用intraweb写的模仿动网论坛的原程序,用的是动网论坛的数据库

    自己去年用intraweb写的模仿动网论坛的原程序,用的是动网论坛的数据库 动网个人服务器系统1.0 可以在不安装iis的情况下,在win98,win2000,winxp跑动网论坛 使用时,只需将动网 ...

  9. (四)代码优化 (快来看看怎样写出真正高性能的代码)

    代码优化 JS开销和如何缩短解析时间[为什么我的JS运行慢] js开销在哪里 解决方案 减少主线程工作量 Progressive Bootstrapping(渐进式启动) 配合V8 有效优化代码[路走 ...

最新文章

  1. Ubuntu Tensorflow object_detection API 目标检测环境搭建
  2. 「Apollo」Cyber RT 学习笔记
  3. delete后加 limit是个好习惯么 ?
  4. 算法之排序算法-shell排序(移位法)
  5. ccf魔数c语言,ccf 201609-4 交通规划
  6. faker.js 登 GitHub 趋势榜标星 27.1k,可大批量生成假数据!
  7. Discuz X2 模块模板代码详解,DIY更容易!
  8. C++ 动态开辟二维数组的的方法
  9. AutoVBA调用AddCricle方法绘制圆
  10. 20155330 第十一周课堂练习(20170503)
  11. 【Maya】移动、父子关系、轴心点、分组关系
  12. .netcore下使用Chloe.ORM框架
  13. iOS8高清壁纸 - 专为iOS8量身定做,每日更新
  14. 名帖33 赵孟頫 隶书《千字文》
  15. 0005 键盘打字如何练成像黑客一样的飞速
  16. python统计word页码_python 实现 Word Count
  17. LCA 最近公共祖先 详解
  18. vue中拿到接口,并获取数据,渲染到页面
  19. 2022双十一喵果Autojs脚本
  20. 一文看懂GFS如何搭建

热门文章

  1. aws php mysql,AWS快速搭建nginx+php+mysql
  2. 安卓 图像清晰度识别_螺柱焊位置识别算法初稿
  3. dnf如何快速拾取物品_DNF手游泰拉该如何获取,游戏蜂窝辅助托管快速获取泰拉...
  4. bootstraptable导出excel独立使用_使用 EasyPOI 优雅导出Excel模板数据(含图片)
  5. 倒计时css和js html代码,手把手教你利用CSS和JS创建一个倒数计时器
  6. java乘法表_Java中四种9*9乘法表的实现方式(附代码)
  7. python 爬取贝壳网小区名称_Python爬虫实战:爬取贝壳网二手房40000条数据
  8. 美国计算机协会ACM子刊中国特辑:中国的人工智能初创企业
  9. AI修复技术为何这么强?原来背后的技术是……
  10. 大学用编程每月多赚2000块,是种什么体验?