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*g
        float 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();
    }

    @Override
    protected 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的优势了。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Springboot 整合 Elasticsearch(二):使用HTTP请求来操作ES

&#x1f4c1;前情提要&#xff1a;Springboot整合Elasticsearch&#xff08;一&#xff09;&#xff1a;Linux下安装 Elasticsearch 8.x 目录 一、使用 elasticsearch-head 插件连接 1、下载压缩包 2、在 chrome 浏览器中添加扩展程序 3、修改IP地址&#xff0c;点击连接 …

Excel+VBA处理高斯光束

文章目录 1 图片导入与裁剪2 获取图片数据3 数据拟合 1 图片导入与裁剪 插入图片没什么好说的&#xff0c;新建Excel&#xff0c;【插入】->【图片】。 由于图像比较大&#xff0c;所以要对数据进行截取&#xff0c;选中图片之后&#xff0c;点击选项卡右端的【图片格式】…

Postgresql 的编译安装与包管理安装, 全发行版 Linux 通用

博客原文 文章目录 实验环境信息编译安装获取安装包环境依赖编译安装安装 contrib 下工具代码 创建用户创建数据目录设置开机自启动启动数据库常用运维操作 apt 安装更新源安装 postgresql开机自启修改配置修改密码 实验环境信息 Ubuntu 20.04Postgre 16.1 编译安装 获取安装…

HiveSQL——不使用union all的情况下进行列转行

参考文章&#xff1a; HiveSql一天一个小技巧&#xff1a;如何不使用union all 进行列转行_不 union all-CSDN博客文章浏览阅读881次&#xff0c;点赞5次&#xff0c;收藏10次。本文给出一种不使用传统UNION ALL方法进行 行转列的方法,其中方法一采用了concat_wsposexplode()方…

[经验] 喉咙沙哑的原因及应对方法是什么 #学习方法#其他#媒体

喉咙沙哑的原因及应对方法是什么 生活中&#xff0c;喉咙不舒服是很常见的情况&#xff0c;尤其是喉咙沙哑&#xff0c;让人感到特别难受&#xff0c;影响睡眠和生活质量。那么喉咙沙哑怎么办呢&#xff1f;接下来我会分享一些简单易行的方法&#xff0c;帮助你缓解这种不适感…

搭建yum仓库服务器

安装 1.安装linux 1.1安装依赖 yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel 1.2下载 cd /opt/nginx wget http://nginx.org/download/nginx-1.25.3.tar.gz 1.3解压 tar -xvf nginx-1.25.3.tar.gz 1.4配置 cd nginx-1.25.3 ./configure --pre…

【Larry】英语学习笔记语法篇——从句=连词+简单句

目录 三、从句连词简单句 1、必须有连词 主从结构 疑问词的词性 2、名词性从句 同位语从句 形式主语 形式宾语 that的省略 3、形容词性从句&#xff08;上&#xff09; 关系代词 关系词的作用 介词前置问题 4、形容词性从句&#xff08;中&#xff09; 定语关系…

程序的内存模型

内存分区模型 C程序在执行时&#xff0c;将内存大方向分为4个区域 1.代码区&#xff1a;存放函数体的二进制代码&#xff0c;有操作系统进行管理 2.全局区&#xff1a;存放全局变量和静态变量以及常量 3.栈区&#xff1a;由编译器自动分配及释放&#xff0c;存放函数的参数…

开源微服务平台框架的特点是什么?

借助什么平台的力量&#xff0c;可以让企业实现高效率的流程化办公&#xff1f;低代码技术平台是近些年来较为流行的平台产品&#xff0c;可以帮助很多行业进入流程化办公新时代&#xff0c;做好数据管理工作&#xff0c;从而提升企业市场竞争力。流辰信息专业研发低代码技术平…

InternLM大模型实战-2.浦语大模型趣味demo

文章目录 前言笔记正文3个Demo的简要介绍InternLM模型简介Lagent介绍书生灵笔多模态大模型 Demo动手实践模型的下载更多 前言 本文是对于InternLM全链路开源体系系列课程的学习笔记。视频教程&#xff1a;【轻松玩转书生浦语大模型趣味Demo】 https://www.bilibili.com/video/…

appears to be hung in Auto SQL Tuning task

appears to be hung in Auto SQL Tuning task Oracle 自动定时优化任务执行失败分析 错误现象&#xff1a; Sat Feb 10 03:10:57 2024 Process 0x0x00007FFB81BE44A8 appears to be hung in Auto SQL Tuning task Current time 1707505857, process death time 1707505803 …

【医学大模型 尘肺病】PneumoLLM:少样本大模型诊断尘肺病新方法

PneumoLLM&#xff1a;少样本大模型诊断尘肺病新方法 提出背景PneumoLLM 框架效果 提出背景 论文&#xff1a;https://arxiv.org/pdf/2312.03490.pdf 代码&#xff1a;https://github.com/CodeMonsterPHD/PneumoLLM/tree/main 历史问题及其背景&#xff1a; 数据稀缺性问题&a…

DevOps落地笔记-13|自动化测试:提高测试效率的不二之选

上一课时主要介绍了通过 API 管理平台来管理企业内部的 API。持续集成是能够保证软件处于可工作状态的实践&#xff0c;但实施持续集成有一个必不可少的步骤——测试。只有尽可能全面的测试覆盖&#xff0c;才能降低软件出错的概率。但是&#xff0c;大多数企业里还是基于人工来…

第二十六回 母夜叉孟州道卖人肉 武都头十字坡遇张青-Ubuntu 防火墙ufw配置

武松到县里投案&#xff0c;县官看武松是个汉子&#xff0c;就把诉状改成&#xff1a;武松与嫂一时斗殴杀死&#xff0c;后西门庆前来&#xff0c;两人互殴&#xff0c;打死西门庆。上报东平府。东平府尹也可怜武松&#xff0c;从轻发落&#xff0c;最后判了个&#xff1a;脊杖…

2024 年 12 款最佳录屏软件【录屏必备指南】

在数字时代&#xff0c;共享屏幕就像发送短信一样常见。 无论是工作、创建教程还是流媒体游戏&#xff0c;找到合适的截屏软件可以决定您的在线形象。 我们测试并整理了一系列最佳的截屏和屏幕录制工具&#xff0c;可将您的内容提升到一个新的水平。 从功能丰富的选项到用户…

RM电控--机械入门

SW常用的快捷键&#xff1a; 多种视角观看&#xff1a; 左侧为自攻螺丝&#xff0c;右侧为钻尾螺丝 钻尾螺丝可以依靠自身进行钻孔操作&#xff0c;而自攻螺丝打之前必须先打好小孔。 螺钉; 这些螺钉大家认得全吗&#xff1f;你还知道哪些呢&#xff1f;_哔哩哔哩_bilibili …

今年春节联欢晚会中的扑克魔术到底是咋变的?

今年的刘谦给全国观众带来了俩魔术&#xff0c;一个是洗牌一个是撕牌&#xff0c;前面第一个魔术看不出来太神奇了&#xff0c;但是第二魔术感觉挺有趣的我可以简单分析分析。 然后我们列出这个魔术的关键步骤&#xff1a; 打乱四张牌 1 2 3 4 对折、撕开、面向同一个方向重…

机器学习系列——(二十二)结语

随着我们的机器学习系列的探索画上句号&#xff0c;我们不禁感慨于这一领域的广阔和深邃。从最初的基础概念到复杂的算法&#xff0c;从理论的探讨到实际应用的示例&#xff0c;我们一起经历了一段非凡的旅程。机器学习不仅是当前技术创新的核心驱动力之一&#xff0c;也是塑造…

【MySQL进阶之路】MySQL 中表空间和数据区的概念以及预读机制

欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术的推送&#xff01; 在我后台回复 「资料」 可领取编程高频电子书&#xff01; 在我后台回复「面试」可领取硬核面试笔记&#xff01; 文章导读地址…

ssm+vue的医药垃圾分类管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。

演示视频&#xff1a; ssmvue的医药垃圾分类管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;ssm vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结…