android 粒子爆炸特效

先上图:

在这里插入图片描述

这是一个高级UI特效,是个动画。

完成这个动画只要3步:

1、控件完成振动效果动画。
2、控件振动动画完成后消失,然后将控件转换成Bitmap.
3、Bitmap完成粒子爆炸特效。

其实完成粒子爆炸特效的并不是控件View本身,而是Bitmap,将Bitmap分割成多个小球,小球在x轴上随机地左右晃动,在y轴上径直下落就行了。

代码介绍:

Particle:

	public abstract class Particle {
	    float x;
	    float y;
	    int color;
	
	    public Particle(float x, float y, int color) {
	        this.x = x;
	        this.y = y;
	        this.color = color;
	    }
	
	    //计算
	    protected abstract void compute(float factor);
	
	    //绘制
	    protected abstract void draw(Canvas canvas,Paint paint);
	
	    //逐步绘制
	    protected void draw(Canvas canvas,Paint paint,float factor){
	        compute(factor);
	        draw(canvas,paint);
	    }
}

这是一个粒子的抽象类,用于定义粒子的x,y坐标,颜色,计算x,y坐标的方法,绘制方法以及一个将这2个方法封装起来的新方法.

FallingParticle

public class FallingParticle extends Particle {

    private static final String TAG = "FallingParticle";
    private float radius = FallingParticleFactory.PART_WH;   //粒子半径
    private float alpha = 1.0f;  //透明度
    private Rect mBound;

    public FallingParticle(float x, float y, int color,Rect bound) {
        super(x, y, color);
        mBound = bound;
    }

    @Override
    protected void compute(float factor) {
        x = x + factor * Utils.RANDOM.nextInt(mBound.width()) * (Utils.RANDOM.nextFloat() - 0.5f); 
        y = y + factor * Utils.RANDOM.nextInt(mBound.height() / 2); 

        radius = radius - factor * Utils.RANDOM.nextInt(2);  
        alpha = (1 - factor) * (1 + Utils.RANDOM.nextFloat());  
    }

    @Override
    protected void draw(Canvas canvas, Paint paint) {
        paint.setColor(color);
        paint.setAlpha((int) (Color.alpha(color) * alpha));
        canvas.drawCircle(x,y,radius,paint);
    }
}

继承抽象方法Particle,主要具体计算粒子的x、y坐标,半径,透明度,具体算法如下:

x = x +(0-1↑) × [-0.5width,0.5width] ():表示从从0到1逐步上升的数,[]:表示这个区间内的任意一个随机数(下同)

y = y + (0-1↑) × [0,0.5h]

radius = radius - (0-1↑) × [0,2]

alpha = [0-1↓] × (1 + [0,1])

粒子工厂抽象方法

public abstract class ParticleFactory {

    protected abstract Particle[][] generateParticles(Bitmap bitmap, Rect bound);
}

用于生成粒子矩阵,只有一个方法用来生成所有粒子

粒子工厂

public class FallingParticleFactory extends ParticleFactory {

    private static final String TAG = "FallingParticleFactory";
    public static final int PART_WH = 8;  //粒子默认宽高

    @Override
    protected Particle[][] generateParticles(Bitmap bitmap, Rect bound) {
        int w = bound.width();
        int h = bound.height();
        Log.d(TAG, "generateParticles: " + bound.left + "," + bound.top);

        int partW_count = w / PART_WH;  //横向个数
        int partH_count = h / PART_WH;  //竖向个数

        //判断个数是否小于1,这种情况是控件的大小 < 8
        partW_count = partW_count > 1 ? partW_count : 1;
        partH_count = partH_count > 1 ? partH_count : 1;

        int bitmap_part_w = bitmap.getWidth() / partW_count;
        int bitmap_part_h = bitmap.getHeight() / partH_count;

        Particle[][] particles = new Particle[partH_count][partW_count];
        for (int row = 0; row < partH_count; row++) {
            for (int column = 0; column < partW_count; column++) {
                //取得当前粒子所在位置颜色
                int color = bitmap.getPixel(column * bitmap_part_w,row * bitmap_part_h);
                float x = bound.left + column * PART_WH;
                float y = bound.top + row * PART_WH;
                particles[row][column] = new FallingParticle(x,y,color,bound);
            }
        }
        return particles;
    }
}

将一张Bitmap分割成多个粒子,每个粒子的宽、高为8(这个可以自己设定),Rect是包裹这个View的外围矩形,通过它的宽、高除以粒子的宽高后就可以得到每行有多少粒子,一共有多少行。

ExplosionField

public class ExplosionField extends View {

    private static final String TAG = "ExplosionField";
    private List<ExplosionAnimator> explosionAnimators;
    private OnClickListener onClickListener;

    public ExplosionField(Context context) {
        super(context);
        explosionAnimators = new ArrayList<>();
        //将动画区域添加到界面上
        attachToActivity();
    }

    private void attachToActivity() {
        //content是一个帧布局
        ViewGroup rootView = ((Activity) getContext()).getWindow().getDecorView().findViewById(android.R.id.content);
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        rootView.addView(this,params);
    }

    /**
     * 添加需要有粒子特效的View
     * @param view
     */
    public void addListener(View view){
        if(view instanceof ViewGroup){
            ViewGroup viewGroup = (ViewGroup) view;
            int viewCount = viewGroup.getChildCount();
            for (int i = 0; i < viewCount; i++) {
                addListener(viewGroup.getChildAt(i));
            }
        }else{
            view.setOnClickListener(getOnClickListener());
        }
    }

    public OnClickListener getOnClickListener(){
        if(onClickListener == null){
            onClickListener = new OnClickListener() {
                @Override
                public void onClick(View v) {
                    explode(v);
                }
            };
        }
        return onClickListener;
    }

    //执行爆炸特效
    public void explode(final View view){
        final Rect rect = new Rect();
        view.getGlobalVisibleRect(rect); //获取View相对整个屏幕的位置
        //标题栏高度
        int titleHeight = ((ViewGroup) getParent()).getTop();
        //状态栏高度
        Rect frame = new Rect();
        ((Activity) getContext()).getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
        int statusBarHeight = frame.top;
        //相对整个屏幕的位置-标题栏(actionBar)的高度-状态栏的高度
        rect.offset(0,-titleHeight-statusBarHeight);

        if(rect.width() == 0 || rect.height() == 0){
            return;
        }

        //震动动画
        ValueAnimator animator = ValueAnimator.ofFloat(0f,1f).setDuration(150);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                view.setTranslationX((Utils.RANDOM.nextFloat() - 0.5f) * view.getWidth() * 0.05f);
                view.setTranslationY((Utils.RANDOM.nextFloat() - 0.5f) * view.getHeight() * 0.05f);
            }
        });
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                explode(view,rect);
            }
        });
        animator.start();
    }

    private void explode(final View view,Rect bound){
       final  ExplosionAnimator explosionAnimator = new ExplosionAnimator(this,Utils.createBitmapFromView(view),bound);
        explosionAnimators.add(explosionAnimator);
        explosionAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                view.setClickable(false);
                //缩小透明
                view.animate().setDuration(150).scaleX(0f).scaleY(0f).alpha(0f).start();
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                view.setClickable(true);
                //放大
                view.animate().setDuration(150).scaleX(1f).scaleY(1f).alpha(1f).start();
                explosionAnimators.remove(explosionAnimator);
            }
        });
        explosionAnimator.start();
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (ExplosionAnimator explosionAnimator : explosionAnimators) {
            explosionAnimator.draw(canvas);
        }
    }
}

动画执行区域(其实是个View),首先将添加动画的控件设置点击监听器,如果这个控件是个ViewGroup,那么将它所有的子View设置点击监听器。紧接着执行振动动画,结束后执行粒子爆炸特效。

ExplosionAnimator

public class ExplosionAnimator extends ValueAnimator {

    private static final String TAG = "ExplosionAnimator";
    public static final int DEFAULT_DURATION = 1500;  //动画默认持续时间
    private Particle[][] mParticles;    //粒子们
    private ParticleFactory mParticleFactory;   //粒子工厂
    private View mContainer;   //动画执行区域
    private Paint mPaint;


    public ExplosionAnimator(View view, Bitmap bitmap, Rect bound) {
        mParticleFactory = new FallingParticleFactory();
        mPaint = new Paint();
        setFloatValues(0f,1f);
        setDuration(DEFAULT_DURATION);
        mParticles = mParticleFactory.generateParticles(bitmap,bound);
        mContainer = view;
    }

    public void draw(Canvas canvas){
        if(!isStarted()){
            //动画结束
            return;
        }
        //所有粒子开始运动
        for (Particle[] mParticle : mParticles) {
            for (Particle particle : mParticle) {
                particle.draw(canvas,mPaint,(float) getAnimatedValue());
            }
        }
        mContainer.invalidate();
    }

    @Override
    public void start() {
        super.start();
        mContainer.invalidate();
        Log.d(TAG, "start: ");
    }
}

粒子爆炸动画实现类,继承于ValueAnimator,在draw方法中,遍历所以粒子并调用他们的draw方法,完成下一帧的绘制,值得注意的是,下方的invalidate方法会强制ExplosionField重绘,如图:

在这里插入图片描述

首先在ExplosionField中调用ExplosionAnimator的start方法,start方法中会使用invalidate方法来使ExplosionField重绘(调用onDraw方法),onDraw方法调用draw方法,draw方法中也使用invalidate,每一次循环完成一次重绘,整个动画就慢慢完成了。

demo地址:https://github.com/lyx19970504/Particle_Effect

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Unity粒子特效爆炸可以通过使用特效包来实现。例如,可以使用Unity3D特效粒子中的墙体爆破爆炸特效包或者烟雾气特效来创建爆炸效果。另外,还可以使用绚丽魔法阵系列特效包来创建一个有魔法感的爆炸效果。 在实现爆炸效果时,可以在当前粒子系统下面创建一个新的粒子系统,并取消循环效果,以获得更加真实的爆炸效果。另外,可以通过调整粒子的大小随着生命周期的变化以及使用网格平面和圆形材质来实现冲击波效果。 通过结合这些方法和特效包,你可以创建出逼真的Unity粒子特效爆炸。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [10种Unity粒子特效包资源](https://download.csdn.net/download/huczyt/10387643)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Unity3D 粒子系统实现一个简单的爆炸效果](https://blog.csdn.net/six_sex/article/details/72857295)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Unity粒子特效系列-爆炸冲击波](https://blog.csdn.net/qq_27489007/article/details/122853415)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哒哒呵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值