【问题标题】:How to create fireworks particle graphics effect on android如何在android上创建烟花粒子图形效果
【发布时间】:2011-07-21 11:04:08
【问题描述】:

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

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

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

【问题讨论】:

    标签: android graphics effects


    【解决方案1】:

    我刚刚发布了一个库的 v1.1,它为普通的 android 视图执行粒子系统:https://github.com/plattysoft/Leonids

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

    【讨论】:

    • 感谢您的辛勤工作,只是一个简短的问题 - 我希望粒子在随机位置弹出,然后在 2 秒内淡出。我一直在寻找如何使用您的库来实现随机粒子放置。
    • 理论上,你可以有一个和屏幕一样大的视图,并确保重力没有设置为 CENTER,应该这样做。
    • 我试过你的方法。但它一次生成一颗星。我真正想要的是。假设 20/30 小粒子(星)在随机位置以随机大小生成,然后在随机时间开始淡出,随着每一个淡出,另一颗星在随机位置淡入。
    • 你可以使用 2 个粒子系统来完成。一个有 20 个,一个有 10 个。我尝试了 Gravity.NO_GRAVITY 并按预期工作。但是,我们应该将此讨论移至 github 中的一张票。
    【解决方案2】:
    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 );
    

    【讨论】:

    • 谢谢,我想下一步是让它留下痕迹,不要这么快消失。
    • 有人可以帮忙编辑这个答案,为调用者/使用提供示例代码吗?我什至不知道哪种方法是起点。
    【解决方案3】:

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

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

    但是,你应该关注的是这些:

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

    【讨论】:

    • 感谢 Victor 提供了一个有用的答案(而不是另一个)。我正在尝试在 SurfaceView 上创建它。如果您查看此动态壁纸market.android.com/details?id=com.aoi.livewallpaper.Fireworks,您会发现一个点会使尾巴变得模糊。我所需要的只是做一个像彗星一样的运动,然后剩下的就是数学。我认为油漆过滤器会有所帮助。
    • Particle system tutorial,从 Internet Wayback Machine 备份。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多