欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android實(shí)現(xiàn)粒子漩渦動(dòng)畫

 更新時(shí)間:2024年01月03日 09:40:25   作者:時(shí)光少年  
粒子動(dòng)畫經(jīng)常用于大畫幅的渲染效果,實(shí)際上難度并不高,但是在使用粒子動(dòng)畫時(shí),必須要遵循的一些要素,起點(diǎn),矢量速度和符合運(yùn)動(dòng)學(xué)公式等,文中有詳細(xì)的代碼示例供大家參考,具有一定的參考價(jià)值,需要的朋友可以參考下

前言

粒子動(dòng)畫經(jīng)常用于大畫幅的渲染效果,實(shí)際上難度并不高,但是在使用粒子動(dòng)畫時(shí),必須要遵循的一些要素,主要是:

  • 起點(diǎn)
  • 矢量速度
  • 符合運(yùn)動(dòng)學(xué)公式

起點(diǎn)之所以重要是因?yàn)槠鋵?shí)位置決定粒子出現(xiàn)的位置,矢量速度則決定了快慢和方向,運(yùn)動(dòng)學(xué)公式屬于粒子動(dòng)畫的一部分,當(dāng)然不是物理性的,畢竟平面尺寸也就那么長(zhǎng),這里的物理學(xué)公式使得畫面更加絲滑而無跳動(dòng)感覺。

本篇將實(shí)現(xiàn)下面的效果

注意:gif圖有些卡,實(shí)際上流暢很多

本篇效果實(shí)現(xiàn)

本篇效果是無數(shù)圓隨機(jī)產(chǎn)生然后漸漸變大并外旋,另外也有雨滴,這里的雨滴相對(duì)簡(jiǎn)單一些。

首先定義粒子對(duì)象

定義粒子對(duì)象是非常重要的,絕大部分傾下粒子本身就是需要單獨(dú)控制的,因?yàn)槊總€(gè)粒子的軌跡都是有所差別的。

定義圓圈粒子

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<Circle> mParticles;
private ArrayList<RainDrop> mRainDrops;
private long mLastUpdateTime; //記錄執(zhí)行時(shí)間

生成粒子對(duì)象

  • 生成雨滴是從頂部屏幕意外開始,而y = -50f值是雨滴的高度決定。
  • 圓圈是隨機(jī)產(chǎn)生,在中心位置圓圈內(nèi)。
// 創(chuàng)建新的雨滴
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);
}

// 創(chuàng)建新的粒子
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);
}

繪制雨滴

雨滴的繪制非常簡(jiǎn)單,調(diào)用相應(yīng)的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);
}

更新粒子位置

雨滴的更新相對(duì)簡(jiǎn)單,但是圓圈的旋轉(zhuǎn)是一個(gè)難點(diǎn),一個(gè)重要的問題是如何旋轉(zhuǎn)粒子的,其實(shí)有很多方法,其中最笨的方法是旋轉(zhuǎn)Canvas坐標(biāo)系,底層有很多矩陣計(jì)算,但是這個(gè)似乎使用Math.atan2(y,x)顯然更加方便,我們只需要在當(dāng)前角度加上偏移量就能旋轉(zhuǎn)。

float angle = (float) Math.atan2(dy, dx) + deltaTime * 0.65f;

下面是完整的更新邏輯

// 更新雨滴位置
Iterator<RainDrop> 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<Circle> 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);
    }

}

粒子刷新

其實(shí)刷新機(jī)制我們以前經(jīng)常使用,調(diào)用postInvalidate即可,本身就是View自身的方法。

總結(jié)

本篇主要內(nèi)容總體上就是這些,下面是全部代碼邏輯

public class VortexView extends View {

    private Paint mPaint;
    private ArrayList<Circle> mParticles;
    private ArrayList<RainDrop> 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;

        // 創(chuàng)建新的雨滴
        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);
        }

        // 創(chuàng)建新的粒子
        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<RainDrop> 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<Circle> 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無效從而重新繪制,實(shí)現(xiàn)動(dòng)畫效果
        invalidate();
    }
    Comparator comparator = new Comparator<Circle>() {
        @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實(shí)現(xiàn)粒子漩渦動(dòng)畫的詳細(xì)內(nèi)容,更多關(guān)于Android粒子漩渦的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論