android实现粒子漩涡动画-kb88凯时官网登录

来自:网络
时间:2024-06-09
阅读:
免费资源网,https://freexyz.cn/

前言

粒子动画经常用于大画幅的渲染效果,实际上难度并不高,但是在使用粒子动画时,必须要遵循的一些要素,主要是:

  • 起点
  • 矢量速度
  • 符合运动学公式

起点之所以重要是因为其实位置决定粒子出现的位置,矢量速度则决定了快慢和方向,运动学公式属于粒子动画的一部分,当然不是物理性的,毕竟平面尺寸也就那么长,这里的物理学公式使得画面更加丝滑而无跳动感觉。

本篇将实现下面的效果

android实现粒子漩涡动画

注意:gif图有些卡,实际上流畅很多

本篇效果实现

本篇效果是无数圆随机产生然后渐渐变大并外旋,另外也有雨滴,这里的雨滴相对简单一些。

首先定义粒子对象

定义粒子对象是非常重要的,绝大部分倾下粒子本身就是需要单独控制的,因为每个粒子的轨迹都是有所差别的。

定义圆圈粒子

private static class circle {
    float x;
    float y;
    int color;
    float radius;
    circle(float x, float y, float radius) {
        reset(x, y, radius);
    }
    private void reset(float x, float y, float radius) {
        this.x = x;
        this.y = y;
        this.radius = radius;
        this.color = color.rgb((int) (math.random() * 256), (int) (math.random() * 256), (int) (math.random() * 256));
    }
}

定义雨滴

private static class raindrop {
    float x;
    float y;
    raindrop(float x, float y) {
        this.x = x;
        this.y = y;
    }
}

定义粒子管理集合

private arraylist mparticles;
private arraylist mraindrops;
private long mlastupdatetime; //记录执行时间

生成粒子对象

  • 生成雨滴是从顶部屏幕意外开始,而y = -50f值是雨滴的高度决定。
  • 圆圈是随机产生,在中心位置圆圈内。
// 创建新的雨滴
if (mraindrops.size() < 80) {
    int num = getwidth() / padding;
    double nth = num * math.random() * padding;
    double x = nth   padding / 2f * math.random();
    raindrop drop = new raindrop((float) x, -50f);
    mraindrops.add(drop);
}
// 创建新的粒子
if (mparticles.size() < 100) {
    float x = (float) (getwidth() / 2f - radius   2*radius * math.random());
    float y = (float) (getheight()/2f - radius   2*radius * math.random() );
    circle particle = new circle(x, y,5);
    mparticles.add(particle);
}

绘制雨滴

雨滴的绘制非常简单,调用相应的canvas方法即可

// 绘制雨滴
mpaint.setcolor(color.white);
for (raindrop drop : mraindrops) {
    canvas.drawline(drop.x, drop.y, drop.x, drop.y   20, mpaint);
}
// 绘制粒子
for (circle particle : mparticles) {
    mpaint.setcolor(particle.color);
    canvas.drawcircle(particle.x, particle.y, particle.radius, mpaint);
}

更新粒子位置

雨滴的更新相对简单,但是圆圈的旋转是一个难点,一个重要的问题是如何旋转粒子的,其实有很多方法,其中最笨的方法是旋转canvas坐标系,底层有很多矩阵计算,但是这个似乎使用math.atan2(y,x)显然更加方便,我们只需要在当前角度加上偏移量就能旋转。

float angle = (float) math.atan2(dy, dx)   deltatime * 0.65f;

下面是完整的更新逻辑

// 更新雨滴位置
iterator rainiterator = mraindrops.iterator();
while (rainiterator.hasnext()) {
    raindrop drop = rainiterator.next();
    if (drop.y > getheight()   50) {
        int num = getwidth() / padding;
        double nth = num * math.random() * padding;
        double x = nth   padding * math.random();
        drop.x = (float) (x);
        drop.y = -50;
    } else {
        drop.y  = 20;
    }
}
// 更新粒子位置
long currenttime = system.currenttimemillis();
float deltatime = (currenttime - mlastupdatetime) / 1000f;
mlastupdatetime = currenttime;
float centerx = getwidth() / 2f;
float centery = getheight() / 2f;
iterator iterator = mparticles.iterator();
while (iterator.hasnext()) {
    circle particle = iterator.next();
    float dx = particle.x - centerx;
    float dy = particle.y - centery;
    float distance = (float) math.sqrt(dx * dx   dy * dy)   4.5f;//  增加偏移
    float angle = (float) math.atan2(dy, dx)   deltatime * 0.5f;
    particle.radius  = 1f;
    particle.x = centerx   (float) math.cos(angle) * distance;
    particle.y = centery   (float) math.sin(angle) * distance;
    if (particle.radius > 10) {
        int maxradius = 100;
        float fraction = (particle.radius - 10) / (maxradius - 10);
        if (fraction >= 1) {
            fraction = 1;
        }
        particle.color = argb((int) (255 * (1 - fraction)), color.red(particle.color), color.green(particle.color), color.blue(particle.color));
    }
    if (color.alpha(particle.color) == 0) {
        float x = (float) (getwidth() / 2f - radius   2* radius * math.random());
        float y = (float) (getheight()/2f - radius   2*radius * math.random() );
        particle.reset(x,y, 5);
    }
}

粒子刷新

其实刷新机制我们以前经常使用,调用postinvalidate即可,本身就是view自身的方法。

总结

本篇主要内容总体上就是这些,下面是全部代码逻辑

public class vortexview extends view {
    private paint mpaint;
    private arraylist mparticles;
    private arraylist mraindrops;
    private long mlastupdatetime;
    private int padding = 20;
    public vortexview(context context) {
        super(context);
        mpaint = new paint();
        mparticles = new arraylist<>();
        mraindrops = new arraylist<>();
        mlastupdatetime = system.currenttimemillis();
    }
    @override
    protected void ondraw(canvas canvas) {
        super.ondraw(canvas);
        float radius = math.min(getwidth(), getheight()) / 3f;
        // 创建新的雨滴
        if (mraindrops.size() < 80) {
            int num = getwidth() / padding;
            double nth = num * math.random() * padding;
            double x = nth   padding / 2f * math.random();
            raindrop drop = new raindrop((float) x, -50f);
            mraindrops.add(drop);
        }
        // 创建新的粒子
        if (mparticles.size() < 100) {
            float x = (float) (getwidth() / 2f - radius   2*radius * math.random());
            float y = (float) (getheight()/2f - radius   2*radius * math.random() );
            circle particle = new circle(x, y,5);
            mparticles.add(particle);
        }
        // 绘制雨滴
        mpaint.setcolor(color.white);
        for (raindrop drop : mraindrops) {
            canvas.drawline(drop.x, drop.y, drop.x, drop.y   20, mpaint);
        }
        // 绘制粒子
        for (circle particle : mparticles) {
            mpaint.setcolor(particle.color);
            canvas.drawcircle(particle.x, particle.y, particle.radius, mpaint);
        }
        // 更新雨滴位置
        iterator rainiterator = mraindrops.iterator();
        while (rainiterator.hasnext()) {
            raindrop drop = rainiterator.next();
            if (drop.y > getheight()   50) {
                int num = getwidth() / padding;
                double nth = num * math.random() * padding;
                double x = nth   padding * math.random();
                drop.x = (float) (x);
                drop.y = -50;
            } else {
                drop.y  = 20;
            }
        }
        // 更新粒子位置
        long currenttime = system.currenttimemillis();
        float deltatime = (currenttime - mlastupdatetime) / 1000f;
        mlastupdatetime = currenttime;
        float centerx = getwidth() / 2f;
        float centery = getheight() / 2f;
        iterator iterator = mparticles.iterator();
        while (iterator.hasnext()) {
            circle particle = iterator.next();
            float dx = particle.x - centerx;
            float dy = particle.y - centery;
            float distance = (float) math.sqrt(dx * dx   dy * dy)   3.5f;//  增加偏移
            float angle = (float) math.atan2(dy, dx)   deltatime * 0.65f;
            particle.radius  = 1f;
            particle.x = centerx   (float) math.cos(angle) * distance;
            particle.y = centery   (float) math.sin(angle) * distance;
            if (particle.radius > 10) {
                int maxradius = 100;
                float fraction = (particle.radius - 10) / (maxradius - 10);
                if (fraction >= 1) {
                    fraction = 1;
                }
                particle.color = argb((int) (255 * (1 - fraction)), color.red(particle.color), color.green(particle.color), color.blue(particle.color));
            }
            if (color.alpha(particle.color) == 0) {
                float x = (float) (getwidth() / 2f - radius   2* radius * math.random());
                float y = (float) (getheight()/2f - radius   2*radius * math.random() );
                particle.reset(x,y, 5);
            }
        }
        collections.sort(mparticles, comparator);
        // 使view无效从而重新绘制,实现动画效果
        invalidate();
    }
    comparator comparator = new comparator() {
        @override
        public int compare(circle left, circle right) {
            return (int) (left.radius - right.radius);
        }
    };
    public static int argb(
            int alpha,
            int red,
            int green,
            int blue) {
        return (alpha << 24) | (red << 16) | (green << 8) | blue;
    }
    private static class circle {
        float x;
        float y;
        int color;
        float radius;
        circle(float x, float y, float radius) {
            reset(x, y, radius);
        }
        private void reset(float x, float y, float radius) {
            this.x = x;
            this.y = y;
            this.radius = radius;
            this.color = color.rgb((int) (math.random() * 256), (int) (math.random() * 256), (int) (math.random() * 256));
        }
    }
    private static class raindrop {
        float x;
        float y;
        raindrop(float x, float y) {
            this.x = x;
            this.y = y;
        }
    }
}

以上就是android实现粒子漩涡动画的详细内容,更多关于android粒子漩涡的资料请关注其它相关文章!

免费资源网,https://freexyz.cn/
返回顶部
顶部
网站地图