Android 粒子喷泉动效

一、前言:

在学习open gl es实现动效的时候,打算回顾了一下用普通的2D坐标系实现粒子效果和 open gl 3d 坐标系的区别,以及难易程度,因此本篇以Canvas 2D坐标系实现了一个简单的demo。

粒子动效原理:

粒子动效本质上是一种知道起点和各个坐标轴方向速度的无规则运动,这种动效的实现的算法确实有规则的。

我们以物理学公式为例,本质上是一种匀加速矢量方程,至于为什么忽快忽慢,也是从该类方程延伸出来的新算法。

x = startX  +  (Vx*t + 1/2*aX*t * t)

y = startY + (Vy * t + 1/2*aY*t * t)

t: 时间  ,vY,vX 各个方向的速度,aX,aY各个方向的加速度

当然,用向量解释就是向量A到向量B各个分量的运动学公式。

粒子动效的特点:

  1. 具备起点位置

  2. 需要计算出速度和运动角度,当然,难点也是速度的计算和定义。

  3. 符合运动学方程,但与现实规律有区别,因为在手机中使用的单位和重力加速度都是有一定区别的。

二、代码实现

2.1 构建粒子对象,在open gl中由于没有对象化的概念,绘制时通过数组的偏移实现,当然后果是代码可读性差一些。

public class Particle {private float speedZ = 0;private float x;private float y;private float speedX;private float speedY;int color;long startTime;private float radius = 10;public Particle(float x, float y, float speedX, float speedY, int color,float speedZ,long clockTime) {this.x = x;this.y = y;this.speedX = speedX;this.speedY = speedY;this.speedZ = speedZ;this.color = color;this.startTime = clockTime;}public void draw(Canvas canvas, long clockTime, Paint paint) {long costTime = (clockTime - startTime)/2;float gravityY = costTime * costTime / 3000f;  //重力加速度float dx = costTime * speedX;float dy = costTime * speedY + gravityY;float v = costTime / 500f;float ty = y + dy;  // vt + t*t/2*gfloat tx = x + dx;int paintColor = paint.getColor();if(v > 1f && speedZ != 1) {//非z轴正半轴的降低透明度int argb = argb((int) (Color.alpha(color) /v), Color.red(color), Color.green(color), Color.blue(color));paint.setColor(argb);}else {paint.setColor(color);}float tRadius = radius;//这只Blend叠加效果,这个api版本较高        paint.setBlendMode(BlendMode.DIFFERENCE);  canvas.drawCircle(tx,ty,tRadius,paint);paint.setColor(paintColor);if(ty > radius){reset(clockTime);}}private void reset(long clockTime) {startTime = clockTime;}public static int argb(@IntRange(from = 0, to = 255) int alpha,@IntRange(from = 0, to = 255) int red,@IntRange(from = 0, to = 255) int green,@IntRange(from = 0, to = 255) int blue) {return (alpha << 24) | (red << 16) | (green << 8) | blue;}
} 

 

2.2 构建粒子系统

public class CanvasParticleSystem {private Particle[] particles;private int maxParticleCount = 500;private Random random = new Random();private final float angle = 30f;  //x轴的活动范围private int index = 0;private float radius = 60;  //x轴和y轴不能超过的边界public void addParticle(float centerX,float centerY,float maxWidth,float maxHeight,long clockTime){if(particles == null){particles = new Particle[maxParticleCount];}if(index >= particles.length) {return;}float degree = (float) Math.toRadians((270 - angle) + 2f * angle * random.nextFloat());float dx = (float) (radius * Math.cos(degree)) * 2f;  //计算初目标位置x的随机点float dy = -(float) ((maxHeight * 1f / 2 - radius * 2f) * random.nextFloat()) - maxHeight / 2f;//计算目标y的随机点float dt = 1000;  //时间按1s计算//    dx = speedx * dt + centerX;//    dy = speedy * dt + centerY;float sx = (dx - centerX) / dt;  // x轴方向的速度float sy = (dy - centerY) / dt;   //y轴方向的速度int num = (int) (random.nextFloat() * 100);float sz = 0;if(num % 5 == 0) {sz = random.nextBoolean() ? -1 : 1;}int argb = argb(random.nextFloat(), random.nextFloat(), random.nextFloat());// argb = argb(210, 110, 80);Particle p = new Particle(centerX,centerY,sx,sy, argb,sz,clockTime);particles[index++] = p;}public void drawFrame(Canvas canvas, Paint paint,long clockTime) {for (int i = 0; i < particles.length;i++) {Particle particle = particles[i];if(particle == null) continue;particle.draw(canvas,clockTime,paint);}}public  int argb( float red, float green, float blue) {return ((int) (1 * 255.0f + 0.5f) << 24) |((int) (red   * 255.0f + 0.5f) << 16) |((int) (green * 255.0f + 0.5f) <<  8) |(int) (blue  * 255.0f + 0.5f);}
}

2.3 粒子View实现

public class PracticeView extends View {Paint paint;CanvasParticleSystem particleSystem;private long clockTime = 0L; //自定义时钟,防止粒子堆积long startTimeout = 0;  public PracticeView(Context context) {super(context);init();}public PracticeView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);init();}public PracticeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}public void init(){paint = new Paint();paint.setAntiAlias(true);paint.setDither(false);paint.setStrokeWidth(2f);particleSystem = new CanvasParticleSystem();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);int width = getWidth();int height = getHeight();if (width <= 10 || height <= 10) {return;}int save = canvas.save();canvas.translate(width/2,height);fillParticles(5,width, height);particleSystem.drawFrame(canvas,paint,getClockTime());canvas.restoreToCount(save);clockTime += 32;postInvalidateDelayed(16);}private void fillParticles(int size,int width, int height) {if(SystemClock.uptimeMillis() - startTimeout > 60) {for (int i = 0; i < size; i++) {particleSystem.addParticle(0, 0, width, height,getClockTime());}startTimeout = SystemClock.uptimeMillis();}}private long getClockTime() {return clockTime;}
}

三、总结

总体上使用Canvas 绘制高帧率的粒子动效,其对比open gl肯定有很多差距,甚至有一些天然缺陷比如Z轴的处理。当然,易用性肯定是Canvas 2D的优势了。

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

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

相关文章

创新指南|企业实施Gen AI面临的10大挑战

文章列出了实现生成式人工智能&#xff08;Gen AI&#xff09;成功的十大挑战。这些挑战涵盖了从数据管理和法律法规到处理能力、解释能力、准确性问题等多个方面。文章强调&#xff0c;尽管Gen AI具有巨大的潜力&#xff0c;但要克服这些挑战以实现其在业务中的有效应用。这些…

macOS Sonoma 14.3.1(23D60)发布

系统介绍 黑果魏叔2 月 9 日消息&#xff0c;苹果今日向 Mac 电脑用户推送了 macOS 14.3.1 更新&#xff08;内部版本号&#xff1a;23D60&#xff09;&#xff0c;本次更新距离上次发布隔了 17 天。 魏叔 查询苹果官方更新日志&#xff0c;macOS Sonoma 14.3.1 修复内容和 …

Web Services 服务 是不是过时了?创建 Web Services 服务实例

Web Services 是不是过时了&#xff1f; 今天是兔年最后一天&#xff0c;先给大家拜个早年 。 昨天上午视频面试一家公司需要开发Web Services 服务&#xff0c;这个也没有什么&#xff0c;但还需要用 VB.net 开发。这个是多古老的语言了&#xff0c;让我想起来了 10年 前 写 …

剑指offer——替换空格

目录 1. 题目描述与背景1.1 题目描述1.2 背景 2. 一般思路 &#xff08;时间复杂度为O(n)&#xff09;3. 分析4. 完整代码4.1 标准答案 1. 题目描述与背景 1.1 题目描述 请实现一个函数&#xff0c;把字符串中的每个空格替换成 “ %20 ” 。例如&#xff1a;输入“ we are hap…

1 scala集合-数组

1 定长数组 定长数组&#xff0c;是指数组长度不可变。定义定长数组的方法有如下两种&#xff1a; 方法1&#xff1a; var/val variable_name new Array[元素类型](数组长度) // 通过制定长度定义例如&#xff0c;定义一个长度为20的Int 类型数组。 scala> val a new …

Flask实现文件下载服务的优雅实现

Flask 是一个轻量级的 Web 框架,通过其简洁的API和灵活性,可以轻松地实现各种Web应用。在本文中,我们将探讨如何在 Flask 中实现一个文件下载服务,通过一个简单的例子来演示如何在浏览器中触发文件下载。 1. 准备工作 首先,我们需要创建一个 Flask 应用,并引入所需的模…

云原生之基石-容器Docker

1. 云原生应用程序部署需求 云原生应用程序采用微服务架构来开发&#xff0c;势必产生大量的子系统&#xff0c;发布大量的程序包&#xff0c;部署起来工作量不小。 程序运行是有依赖的&#xff0c;C/C程序依赖各种动态库&#xff0c;Java程序依赖JDK和各种Jar库&#xff0c;Py…

[office] excel求乘积的公式和方法 #媒体#笔记#经验分享

excel求乘积的公式和方法 本文首先给出两个常规的excel求乘积的链接&#xff0c;然后再例举了一个文字和数字在同一单元格里面的excel求乘积的公式写法。 excel求乘积的方法分为两种&#xff0c;第一种是直接用四则运算的*来求乘积&#xff0c;另外一种就是使用PRODUCT乘积函数…

AJAX——认识URL

1 什么是URL&#xff1f; 统一资源定位符&#xff08;英语&#xff1a;Uniform Resource Locator&#xff0c;缩写&#xff1a;URL&#xff0c;或称统一资源定位器、定位地址、URL地址&#xff09;俗称网页地址&#xff0c;简称网址&#xff0c;是因特网上标准的资源的地址&…

2024年【氧化工艺】新版试题及氧化工艺操作证考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 氧化工艺新版试题是安全生产模拟考试一点通生成的&#xff0c;氧化工艺证模拟考试题库是根据氧化工艺最新版教材汇编出氧化工艺仿真模拟考试。2024年【氧化工艺】新版试题及氧化工艺操作证考试 1、【单选题】 对现场窨…

Python入门:常用模块—os模块及sys模块

os模块 sys模块 import sys print(sys.argv) # 命令参数list&#xff0c;第一个元素是程序本身路径 print(sys.exit()) # 退出程序&#xff0c;正常退出是exit(0) print(sys.version) # 获取python解释程序的版本信息 print(sys.maxint()) # 最大…

02.01_111期_C++_构造函数初始化列表笔记

运算符重载对 1. 操作数的个数 2. 操作数出现的顺序都有确定要求 所以如果 对 << 这个操作符进行重载&#xff0c; <<这个操作符有两个操作数&#xff0c;而且左右操作数有顺序要求 那么d1将成为this指针指向的对象&#xff0c;也将会 <&l…

SpringCloud-微服务概述、SpringCloud入门概述、服务提供与消费

1.学习前言 1.1 学习前提 熟练使用SpringBoot 微服务快速开发框架了解过Dubbo Zookeeper 分布式基础电脑配置内存不低于8G 1.2 文章大纲 Spring Cloud 五大组件 服务注册与发现——Netflix Eureka负载均衡&#xff1a; ​ 客户端负载均衡——Netflix Ribbon ​ 服务端负载…

KVM和JVM的虚拟化技术有何区别?

随着虚拟化技术的不断发展&#xff0c;KVM和JVM已成为两种主流的虚拟化技术。尽管它们都提供了虚拟化的解决方案&#xff0c;但它们在实现方式、功能和性能方面存在一些重要的差异。本文将深入探讨KVM和JVM的虚拟化技术之间的区别。 KVM&#xff08;Kernel-based Virtual Mac…

hive 创建表 字段类型

hive 创建表 字段类型 在Hive中创建表时可以指定不同的字段类型。常见的字段类型包括&#xff1a; 数值类型&#xff08;Numeric Types&#xff09;&#xff1a; TINYINT&#xff1a;8位有符号整数 SMALLINT&#xff1a;16位有符号整数 INT&#xff1a;32位有符号整数 BIG…

Select 选择器 el-option 回显错误 value

离谱 回显的内容不是 label 而是 value 的值 返回官方看说明&#xff1a; v-model的值为当前被选中的el-option的 value 属性值 value / v-model 绑定值有3种类型 boolean / string / number 根据自身代码猜测是&#xff1a;tableData.bookId 与 item.id 类型不一致导致 &…

H5/CSS 笔试面试考题(61-70)

简述下面语法中,哪个可以定义一个带正方形的列表? () A:list-style-image: square B:list-style-color: square C:list-type: square D:list-style-type: square 面试通过率:76.0% 推荐指数: ★★★★ 试题难度: 初级 试题类型: 选择题 答案:d 简述在 HTML 中,样…

问题:3【单选题】实现职业理想的一般步骤是()。 #媒体#媒体

问题&#xff1a;3【单选题】实现职业理想的一般步骤是()。 A、创业-立业-择业 B、择业-创业-立业 C、择业-立业-创业 D、立业-择业-创业 参考答案如图所示

【几分钟】快速熟悉torch.save()、torch.load()、torch.nn.Module.load_state_dict()

【几分钟】快速熟悉torch.save()、torch.load()、torch.nn.Module.load_state_dict() &#x1f335;文章目录&#x1f335; &#x1f333;引言&#x1f333;&#x1f333;torch.save()详解&#x1f333;&#x1f333;torch.load()详解&#x1f333;&#x1f333;torch.nn.Modul…

php文件请求

/** Common File Request Method */ $file $request->file(‘file’); $file->getClientOriginalName(); // Returns the original file name $file->getClientOriginalExtension(); // Returns the original file extension $file->getClientMimeType(); // Ret…