如何在android上创建烟花粒子图形效果

发布于 2024-10-25 23:25:31 字数 144 浏览 3 评论 0原文

有人知道如何通过在画布上绘画来制作烟花效果吗? 线材动态壁纸(免费应用程序)中有一个很好的例子。

在那里,许多点移动并在星状爆炸中留下痕迹,然后逐渐消失。我认为每个移动点都有某种运动​​模糊,我不知道如何创建。

欢迎任何想法或相关示例的链接。

Anybody has any idea how to make a fireworks effect by drawing on canvas?
There is one nice example in wireworks live wallpaper (free app).

There, many points move and leave trails in a star like explosion and gradually disappear. I think that there is some kind of motion blur on each point moving, which I am not sure how to create.

Any ideas or links to relevant examples are welcome.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

看春风乍起 2024-11-01 23:25:31

我刚刚发布了一个为普通 Android 视图提供粒子系统的库的 v1.1:https://github.com/plattysoft/Leonids

我知道这个问题很老了,你可能自己实现了它,但如果你仍然对使用库感兴趣,请检查一下。

I just released the v1.1 of a library that does particle system for normal android views: https://github.com/plattysoft/Leonids

I know the question is quite old, and you probably had implemented it yourself, but in case you are still interested on using a library, check it out.

相守太难 2024-11-01 23:25:31
import java.util.Random;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

enum AnimateState
{
    asReady, asRunning, asPause;
}

class Rocket
{
    public boolean sleep = true;

    private float energy, length, mx, my, gravity, ox, oy, x, y, t;
    private float vx[], vy[];
    private int patch, red, green, blue;
    private Random random;

    public Rocket( int a, int b, int g )
    {
        mx = a;
        my = b;
        gravity = g;
    }

    public void init( int e, int p, int l, long seed )
    {
        energy = e;
        patch = p + 20;
        length = l;

        random = new Random( seed );

        vx = new float[patch];
        vy = new float[patch];

        red = ( int )( random.nextFloat() * 128 ) + 128;
        blue = ( int )( random.nextFloat() * 128 ) + 128;
        green = ( int )( random.nextFloat() * 128 ) + 128;

        ox = ( random.nextFloat() * mx / 2 ) + mx / 4;
        oy = ( random.nextFloat() * my / 2 ) + my / 4;

        for( int i = 0; i < patch; ++i )
        {
            vx[i] = ( ( random.nextFloat() + random.nextFloat() / 2 ) * energy ) - energy / ( random.nextInt( 2 ) + 1 );
            vy[i] = ( ( random.nextFloat() + random.nextFloat() / 2 ) * energy * 7 / 8 ) - energy / ( random.nextInt( 5 ) + 4 );
        }
    }

    public void start()
    {
        t = 0;
        sleep = false;
    }

    public void doDraw( Canvas canvas, Paint paint )
    {
        if ( ! sleep )
        {
            if ( t < length )
            {
                int i, cr, cg, cb;
                double s;

                cr = ( int )( random.nextDouble() * 64 ) - 32 + red;
                cg = ( int )( random.nextDouble() * 64 ) - 32 + green;
                cb = ( int )( random.nextDouble() * 64 ) - 32 + blue;

                if ( cr >= 0 && cr <= 256 )
                    red = cr;
                if ( cg >= 0 && cg <= 256 )
                    green = cg;
                if ( cb >= 0 && cb <= 256 )
                    blue = cb;

                int _red = red == 256 ? 255 : red;
                int _green = green == 256 ? 255 : green;
                int _blue = blue == 256 ? 255 : blue;

                int color = Color.rgb( _red, _green, _blue );

                paint.setColor( color );

                for ( i = 0; i < patch; ++i )
                {
                    s = ( double )t / 100;
                    x = ( int )( vx[i] * s );
                    y = ( int )( vy[i] * s - gravity * s * s );

                    canvas.drawCircle( ox + x, oy - y, 2f, paint );
                }

                paint.setColor( Color.BLACK );

                for ( i = 0; i < patch; ++i )
                {
                    if ( t >= length / 2 )
                    {
                        for ( int j = 0; j < 2; ++j )
                        {
                            s = ( double ) ( ( t - length / 2 ) * 2 + j ) / 100;
                            x = ( int )( vx[i] * s );
                            y = ( int )( vy[i] * s - gravity * s * s );

                            canvas.drawCircle( ox + x, oy - y, 2f, paint );
                        }
                    }
                }

                ++t;
            }
            else
                sleep = true;
        }
    }
}

class Fireworks
{
    /**
     * Maximum number of rockets.
     */
    public int MaxRocketNumber = 9;
    /**
     * Controls "energy" of firwork explosion. Default value 850.
     */
    public int MaxRocketExplosionEnergy = 950;
    /**
     * Controls the density of the firework burst. Larger numbers give higher density.
     * Default value 90.
     */
    public int MaxRocketPatchNumber = 90;
    /**
     * Controls the radius of the firework burst. Larger numbers give larger radius.
     * Default value 68.
     */
    public int MaxRocketPatchLength = 68;

    /**
     * Controls gravity of the firework simulation.
     * Default value 400.
     */
    public int Gravity = 400;

    transient private Rocket rocket[];
    transient private boolean rocketsCreated = false;

    private int width;
    private int height;

    Fireworks( int width, int height )
    {
        this.width = width;
        this.height = height;
    }

    void createRockets()
    {
        rocketsCreated = true;

        Rocket tempRocket[] = new Rocket[MaxRocketNumber];

        for ( int i = 0; i < MaxRocketNumber; i++ )
            tempRocket[i] = new Rocket( width, height, Gravity );

        rocket = tempRocket;
    }

    public synchronized void reshape( int width, int height )
    {
        this.width = width;
        this.height = height;

        rocketsCreated = false;
    }

    public void doDraw( Canvas canvas, Paint paint )
    {
        canvas.drawColor( Color.BLACK );

        int i, e, p, l;
        long s;

        boolean sleep;

        if ( ! rocketsCreated )
        {
            createRockets();
        }

        if ( rocketsCreated )
        {
            sleep = true;

            for ( i = 0; i < MaxRocketNumber; i++ )
                sleep = sleep && rocket[i].sleep;

            for ( i = 0; i < MaxRocketNumber; ++i )
            {
                e = ( int )( Math.random() * MaxRocketExplosionEnergy * 3 / 4 ) + MaxRocketExplosionEnergy / 4 + 1;
                p = ( int )( Math.random() * MaxRocketPatchNumber * 3 / 4 ) + MaxRocketPatchNumber / 4 + 1;
                l = ( int )( Math.random() * MaxRocketPatchLength * 3 / 4 ) + MaxRocketPatchLength / 4 + 1;
                s = ( long )( Math.random() * 10000 );

                Rocket r = rocket[i];
                if ( r.sleep && Math.random() * MaxRocketNumber * l < 2 ) 
                {
                    r.init( e, p, l, s );
                    r.start();
                }

                if ( rocketsCreated )
                    r.doDraw( canvas, paint );
            }
        }
    }
}

public class FireworkLayout extends SurfaceView implements SurfaceHolder.Callback
{

    class GameThread extends Thread
    {
        private boolean mRun = false;

        private SurfaceHolder surfaceHolder;
        private AnimateState state;
        private Context context;
        private Handler handler;
        private Paint paint;
        Fireworks fireworks;

        GameThread( SurfaceHolder surfaceHolder, Context context, Handler handler )
        {
            this.surfaceHolder = surfaceHolder;
            this.context = context;
            this.handler = handler;

            fireworks = new Fireworks( getWidth(), getHeight() );

            paint = new Paint();
            paint.setStrokeWidth( 2 / getResources().getDisplayMetrics().density );
            paint.setColor( Color.BLACK );
            paint.setAntiAlias( true );
        }

        public void doStart()
        {
            synchronized ( surfaceHolder )
            {
                setState( AnimateState.asRunning );
            }
        }

        public void pause()
        {
            synchronized ( surfaceHolder )
            {
                if ( state == AnimateState.asRunning )
                    setState( AnimateState.asPause );
            }
        }

        public void unpause()
        {
            setState( AnimateState.asRunning );
        }

        @Override
        public void run()
        {
            while ( mRun )
            {
                Canvas c = null;
                try
                {
                    c = surfaceHolder.lockCanvas( null );

                    synchronized ( surfaceHolder )
                    {
                        if ( state == AnimateState.asRunning )
                            doDraw( c );
                    }
                }
                finally
                {
                    if ( c != null )
                    {
                        surfaceHolder.unlockCanvasAndPost( c );
                    }
                }
            }
        }

        public void setRunning( boolean b )
        {
            mRun = b;
        }

        public void setState( AnimateState state )
        {
            synchronized ( surfaceHolder )
            {
                this.state = state;
            }
        }

        public void doDraw( Canvas canvas )
        {
            fireworks.doDraw( canvas, paint );
        }

        public void setSurfaceSize( int width, int height )
        {
            synchronized ( surfaceHolder )
            {
                fireworks.reshape( width, height );
            }
        }
    }

    private GameThread thread;

    @SuppressLint( "HandlerLeak" )
    public FireworkLayout( Context context )
    {
        super( context );

        SurfaceHolder holder = getHolder();
        holder.addCallback( this );

        getHolder().addCallback( this );

        thread = new GameThread( holder, context, new Handler() {
            @Override
            public void handleMessage( Message m ) {

            }} );

        setFocusable( true );
    }

    @Override
    public void surfaceChanged( SurfaceHolder holder, int format, int width, int height )
    {
        thread.setSurfaceSize( width, height );
    }

    @Override
    public void surfaceCreated( SurfaceHolder holder )
    {
        thread.setRunning( true );
        thread.doStart();
        thread.start();
    }

    @Override
    public void surfaceDestroyed( SurfaceHolder holder )
    {
        boolean retry = true;
        thread.setRunning( false );

        while ( retry )
        {
            try
            {
                thread.join();
                retry = false;
            }
            catch ( InterruptedException e )
            {
            }
        }
    }
}

使用:

    firework = new FireworkView( this );
    LinearLayout surface = (LinearLayout) findViewById( R.id.surface );
    surface.addView( firework );
import java.util.Random;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

enum AnimateState
{
    asReady, asRunning, asPause;
}

class Rocket
{
    public boolean sleep = true;

    private float energy, length, mx, my, gravity, ox, oy, x, y, t;
    private float vx[], vy[];
    private int patch, red, green, blue;
    private Random random;

    public Rocket( int a, int b, int g )
    {
        mx = a;
        my = b;
        gravity = g;
    }

    public void init( int e, int p, int l, long seed )
    {
        energy = e;
        patch = p + 20;
        length = l;

        random = new Random( seed );

        vx = new float[patch];
        vy = new float[patch];

        red = ( int )( random.nextFloat() * 128 ) + 128;
        blue = ( int )( random.nextFloat() * 128 ) + 128;
        green = ( int )( random.nextFloat() * 128 ) + 128;

        ox = ( random.nextFloat() * mx / 2 ) + mx / 4;
        oy = ( random.nextFloat() * my / 2 ) + my / 4;

        for( int i = 0; i < patch; ++i )
        {
            vx[i] = ( ( random.nextFloat() + random.nextFloat() / 2 ) * energy ) - energy / ( random.nextInt( 2 ) + 1 );
            vy[i] = ( ( random.nextFloat() + random.nextFloat() / 2 ) * energy * 7 / 8 ) - energy / ( random.nextInt( 5 ) + 4 );
        }
    }

    public void start()
    {
        t = 0;
        sleep = false;
    }

    public void doDraw( Canvas canvas, Paint paint )
    {
        if ( ! sleep )
        {
            if ( t < length )
            {
                int i, cr, cg, cb;
                double s;

                cr = ( int )( random.nextDouble() * 64 ) - 32 + red;
                cg = ( int )( random.nextDouble() * 64 ) - 32 + green;
                cb = ( int )( random.nextDouble() * 64 ) - 32 + blue;

                if ( cr >= 0 && cr <= 256 )
                    red = cr;
                if ( cg >= 0 && cg <= 256 )
                    green = cg;
                if ( cb >= 0 && cb <= 256 )
                    blue = cb;

                int _red = red == 256 ? 255 : red;
                int _green = green == 256 ? 255 : green;
                int _blue = blue == 256 ? 255 : blue;

                int color = Color.rgb( _red, _green, _blue );

                paint.setColor( color );

                for ( i = 0; i < patch; ++i )
                {
                    s = ( double )t / 100;
                    x = ( int )( vx[i] * s );
                    y = ( int )( vy[i] * s - gravity * s * s );

                    canvas.drawCircle( ox + x, oy - y, 2f, paint );
                }

                paint.setColor( Color.BLACK );

                for ( i = 0; i < patch; ++i )
                {
                    if ( t >= length / 2 )
                    {
                        for ( int j = 0; j < 2; ++j )
                        {
                            s = ( double ) ( ( t - length / 2 ) * 2 + j ) / 100;
                            x = ( int )( vx[i] * s );
                            y = ( int )( vy[i] * s - gravity * s * s );

                            canvas.drawCircle( ox + x, oy - y, 2f, paint );
                        }
                    }
                }

                ++t;
            }
            else
                sleep = true;
        }
    }
}

class Fireworks
{
    /**
     * Maximum number of rockets.
     */
    public int MaxRocketNumber = 9;
    /**
     * Controls "energy" of firwork explosion. Default value 850.
     */
    public int MaxRocketExplosionEnergy = 950;
    /**
     * Controls the density of the firework burst. Larger numbers give higher density.
     * Default value 90.
     */
    public int MaxRocketPatchNumber = 90;
    /**
     * Controls the radius of the firework burst. Larger numbers give larger radius.
     * Default value 68.
     */
    public int MaxRocketPatchLength = 68;

    /**
     * Controls gravity of the firework simulation.
     * Default value 400.
     */
    public int Gravity = 400;

    transient private Rocket rocket[];
    transient private boolean rocketsCreated = false;

    private int width;
    private int height;

    Fireworks( int width, int height )
    {
        this.width = width;
        this.height = height;
    }

    void createRockets()
    {
        rocketsCreated = true;

        Rocket tempRocket[] = new Rocket[MaxRocketNumber];

        for ( int i = 0; i < MaxRocketNumber; i++ )
            tempRocket[i] = new Rocket( width, height, Gravity );

        rocket = tempRocket;
    }

    public synchronized void reshape( int width, int height )
    {
        this.width = width;
        this.height = height;

        rocketsCreated = false;
    }

    public void doDraw( Canvas canvas, Paint paint )
    {
        canvas.drawColor( Color.BLACK );

        int i, e, p, l;
        long s;

        boolean sleep;

        if ( ! rocketsCreated )
        {
            createRockets();
        }

        if ( rocketsCreated )
        {
            sleep = true;

            for ( i = 0; i < MaxRocketNumber; i++ )
                sleep = sleep && rocket[i].sleep;

            for ( i = 0; i < MaxRocketNumber; ++i )
            {
                e = ( int )( Math.random() * MaxRocketExplosionEnergy * 3 / 4 ) + MaxRocketExplosionEnergy / 4 + 1;
                p = ( int )( Math.random() * MaxRocketPatchNumber * 3 / 4 ) + MaxRocketPatchNumber / 4 + 1;
                l = ( int )( Math.random() * MaxRocketPatchLength * 3 / 4 ) + MaxRocketPatchLength / 4 + 1;
                s = ( long )( Math.random() * 10000 );

                Rocket r = rocket[i];
                if ( r.sleep && Math.random() * MaxRocketNumber * l < 2 ) 
                {
                    r.init( e, p, l, s );
                    r.start();
                }

                if ( rocketsCreated )
                    r.doDraw( canvas, paint );
            }
        }
    }
}

public class FireworkLayout extends SurfaceView implements SurfaceHolder.Callback
{

    class GameThread extends Thread
    {
        private boolean mRun = false;

        private SurfaceHolder surfaceHolder;
        private AnimateState state;
        private Context context;
        private Handler handler;
        private Paint paint;
        Fireworks fireworks;

        GameThread( SurfaceHolder surfaceHolder, Context context, Handler handler )
        {
            this.surfaceHolder = surfaceHolder;
            this.context = context;
            this.handler = handler;

            fireworks = new Fireworks( getWidth(), getHeight() );

            paint = new Paint();
            paint.setStrokeWidth( 2 / getResources().getDisplayMetrics().density );
            paint.setColor( Color.BLACK );
            paint.setAntiAlias( true );
        }

        public void doStart()
        {
            synchronized ( surfaceHolder )
            {
                setState( AnimateState.asRunning );
            }
        }

        public void pause()
        {
            synchronized ( surfaceHolder )
            {
                if ( state == AnimateState.asRunning )
                    setState( AnimateState.asPause );
            }
        }

        public void unpause()
        {
            setState( AnimateState.asRunning );
        }

        @Override
        public void run()
        {
            while ( mRun )
            {
                Canvas c = null;
                try
                {
                    c = surfaceHolder.lockCanvas( null );

                    synchronized ( surfaceHolder )
                    {
                        if ( state == AnimateState.asRunning )
                            doDraw( c );
                    }
                }
                finally
                {
                    if ( c != null )
                    {
                        surfaceHolder.unlockCanvasAndPost( c );
                    }
                }
            }
        }

        public void setRunning( boolean b )
        {
            mRun = b;
        }

        public void setState( AnimateState state )
        {
            synchronized ( surfaceHolder )
            {
                this.state = state;
            }
        }

        public void doDraw( Canvas canvas )
        {
            fireworks.doDraw( canvas, paint );
        }

        public void setSurfaceSize( int width, int height )
        {
            synchronized ( surfaceHolder )
            {
                fireworks.reshape( width, height );
            }
        }
    }

    private GameThread thread;

    @SuppressLint( "HandlerLeak" )
    public FireworkLayout( Context context )
    {
        super( context );

        SurfaceHolder holder = getHolder();
        holder.addCallback( this );

        getHolder().addCallback( this );

        thread = new GameThread( holder, context, new Handler() {
            @Override
            public void handleMessage( Message m ) {

            }} );

        setFocusable( true );
    }

    @Override
    public void surfaceChanged( SurfaceHolder holder, int format, int width, int height )
    {
        thread.setSurfaceSize( width, height );
    }

    @Override
    public void surfaceCreated( SurfaceHolder holder )
    {
        thread.setRunning( true );
        thread.doStart();
        thread.start();
    }

    @Override
    public void surfaceDestroyed( SurfaceHolder holder )
    {
        boolean retry = true;
        thread.setRunning( false );

        while ( retry )
        {
            try
            {
                thread.join();
                retry = false;
            }
            catch ( InterruptedException e )
            {
            }
        }
    }
}

use:

    firework = new FireworkView( this );
    LinearLayout surface = (LinearLayout) findViewById( R.id.surface );
    surface.addView( firework );
百善笑为先 2024-11-01 23:25:31

这是一个非常抽象(且有趣)的问题,但过于复杂,无法详细回答。

您真正寻找的可能是一种经过修改的粒子系统。粒子系统基本上是一个包含物理引擎的粒子引擎。

但是,您应该关注的是:

一旦您构建了它(或了解了它),您就可以轻松地将其转换为 Canvas 系统,尽管 OpenGL 是更好的选择。

That's a very abstract (and interesting) question but far too complex to answer in details.

What you're really looking for is probably a sort of a modified particle system. A particle system is basically an engine for particles that includes a physics engine.

However, what you should focus on are these:

Once you built it (or gotten an understanding about it) you can easily convert it to the Canvas system, although OpenGL is the preferable alternative.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文