Android粒子系统

来源:互联网 发布:风险评价指数矩阵法 编辑:程序博客网 时间:2024/06/08 06:21
一、粒子属性
粒子图片,粒子大小,粒子缩放比例,粒子位置(X,Y),粒子移动方向与速度(X,Y坐标与时间t的关系)
计算粒子所处位置,绘制渲染

粒子系统,是大量基础图元构成的具有一定规律的不规律渲染图像。即要够成粒子系统,需要有基本图元,保持基本图元的一定规律性,并细化不规律性。
一个基本图元即是粒子系统中展示的一个粒子,有以下基本属性:粒子纹理【图片】,粒子的大小,粒子缩放,粒子的位置【平面坐标系中只有X,Y】,粒子移动方向与速度(X,Y坐标与时间T的关系)。
粒子属性基本信息保持一致,在各个变量细化时加入随机变量震动,从而实现统一大规律下不统一。
准备好所有粒子信息后,先检查粒子当前所处的位置,超出范围部分强制修改,然后绘制渲染粒子。

二、控件实现
构造方法,初始化基本数据:
    public ParticleView(Context context) {        super(context);    }    public ParticleView(Context context, AttributeSet attrs) {        super(context, attrs);        initData(context);        initBitmapInfo();        initPaint();    }    public ParticleView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }

 /**     * 初始化绘制笔     */    private void initPaint() {        paint = new Paint(Paint.ANTI_ALIAS_FLAG);        // 防抖动        paint.setDither(true);        // 开启图像过滤        paint.setFilterBitmap(true);    }    /**     * 初始化粒子纹理     */    private void initBitmapInfo() {        mStarOne = ((BitmapDrawable) mResources.getDrawable(R.drawable.star2)).getBitmap();//        mStarOne = ((BitmapDrawable) mResources.getDrawable(R.drawable.snow1)).getBitmap();        mStarOneWidth = mStarOne.getWidth();        mStarOneHeight = mStarOne.getHeight();//        mStarTwo = ((BitmapDrawable) mResources.getDrawable(R.drawable.star1)).getBitmap();        mStarTwo = ((BitmapDrawable) mResources.getDrawable(R.drawable.snow2)).getBitmap();        mStarTwoWidth = mStarTwo.getWidth();        mStarTwoHeight = mStarTwo.getHeight();//        mStarThree = ((BitmapDrawable) mResources.getDrawable(R.drawable.star3)).getBitmap();        mStarThree = ((BitmapDrawable) mResources.getDrawable(R.drawable.snow3)).getBitmap();        mStarThreeWidth = mStarThree.getWidth();        mStarThreeHeight = mStarThree.getHeight();    }    /**     * 初始化数据     *     * @param context     */    private void initData(Context context) {        mResources = getResources();        DisplayMetrics dm = context.getApplicationContext().getResources().getDisplayMetrics();        mTotalWidth = dm.widthPixels;        mTotalHeight = dm.heightPixels;        Log.i(TAG, "mTotalWidth=" + mTotalWidth + "--1--mTotalHeight=" + mTotalHeight);        //设置三个不同大小的速度值        mFloatTransLowSpeed = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0.5f,                mResources.getDisplayMetrics());        mFloatTransMidSpeed = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0.75f,                mResources.getDisplayMetrics());        mFloatTransFastSpeed = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1f,                mResources.getDisplayMetrics());    }

控件在展示中,生命周期变化,影响控件展示效果,重新计算控件的基本属性。
    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        mCenterX = mTotalWidth / 2;        mCenterY = mTotalHeight / 2;        mSrcRect = new Rect();        mDestRect = new Rect(0, 0, mTotalWidth, mTotalHeight);        mStarOneSrcRect = new Rect(0, 0, mStarOneWidth, mStarOneHeight);        mStarTwoSrcRect = new Rect(0, 0, mStarTwoWidth, mStarTwoHeight);        mStarThreeSrcRect = new Rect(0, 0, mStarThreeWidth, mStarThreeHeight);        Log.i(TAG, "mTotalWidth=" + mTotalWidth + "---2-mTotalHeight=" + mTotalHeight);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        initParticleInfo();    }

  /**     * 初始化所有粒子数据     */    private void initParticleInfo() {        Particle starInfo = null;        Random random = new Random();        for (int i = 0; i < mFloatCount; i++) {            // 获取星星大小比例            float starSize = initParticleSize(0.4f, 0.8f);            //小球的坐标            float[] starLocation = STAR_LOCATION[i];            starInfo = new Particle();            // 初始化星星大小            starInfo.sizePercent = starSize;            // 初始化漂浮速度            int randomSpeed = random.nextInt(3);            switch (randomSpeed) {                case 0:                    starInfo.speed = mFloatTransLowSpeed;                    break;                case 1:                    starInfo.speed = mFloatTransMidSpeed;                    break;                case 2:                    starInfo.speed = mFloatTransFastSpeed;                    break;                default:                    starInfo.speed = mFloatTransMidSpeed;                    break;            }            // 初始化星星透明度            starInfo.alpha = initParticleSize(0.3f, 0.8f);            // 初始化星星位置            starInfo.xLocation = (int) (starLocation[0] * mTotalWidth);            starInfo.yLocation = (int) (starLocation[1] * mTotalHeight);            Log.i(TAG, "xLocation = " + starInfo.xLocation + "--yLocation = "                    + starInfo.yLocation);            Log.i(TAG, "stoneSize = " + starSize + "---stoneAlpha = "                    + starInfo.alpha);            // 初始化星星位置            starInfo.direction = getParticleDirection();            mStarInfos.add(starInfo);        }    }

  /**     * 获取粒子当前运动方向     *     * @return     */    private int getParticleDirection() {        int randomInt;        Random random = new Random();        if (floatTyep == 100) {            randomInt = random.nextInt(3);        } else {            randomInt = floatTyep;        }        int direction = 0;        switch (randomInt) {            case 0:                direction = LEFT;                break;            case 1:                direction = RIGHT;                break;            case 2:                direction = TOP;                break;            case 3:                direction = BOTTOM;                break;            case 4:                direction = FREE_POINT;                break;            default:                break;        }        return direction;    }    /**     * 对粒子进行缩放     *     * @param start 缩放最小值     * @param end   缩放最大值     * @return     */    private float initParticleSize(float start, float end) {        float nextFloat = (float) Math.random();        if (start < nextFloat && nextFloat < end) {            return nextFloat;        } else {            // 如果不处于想要的数据段,则再随机一次,因为不断递归有风险            return (float) Math.random();        }    }

绘制粒子系统:【先检查粒子位置,再渲染】
    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        for (int i = 0; i < mStarInfos.size(); i++) {            Particle starInfo = mStarInfos.get(i);            drawParticleDynamic(i, starInfo, canvas, paint);        }    }

  private void drawParticleDynamic(int count, Particle starInfo,                                     Canvas canvas, Paint paint) {        //绘制前重置区域        resetParticleFloat(starInfo);        float starAlpha = starInfo.alpha;        int xLocation = starInfo.xLocation;        int yLocation = starInfo.yLocation;        float sizePercent = starInfo.sizePercent;        xLocation = (int) (xLocation / sizePercent);        yLocation = (int) (yLocation / sizePercent);        Bitmap bitmap = null;        Rect srcRect = null;        Rect destRect = new Rect();        mStarOneSrcRect = new Rect(0, 0, mStarOneWidth, mStarOneHeight);        if (count % 3 == 0) {            bitmap = mStarOne;            srcRect = mStarOneSrcRect;            destRect.set(xLocation, yLocation,                    xLocation + mStarOneWidth, yLocation                            + mStarOneHeight);        } else if (count % 2 == 0) {            bitmap = mStarThree;            srcRect = mStarThreeSrcRect;            destRect.set(xLocation, yLocation, xLocation                    + mStarThreeWidth, yLocation + mStarThreeHeight);        } else {            bitmap = mStarTwo;            srcRect = mStarTwoSrcRect;            destRect.set(xLocation, yLocation, xLocation                    + mStarTwoWidth, yLocation + mStarTwoHeight);        }        paint.setAlpha((int) (starAlpha * 255));        canvas.save();        canvas.scale(sizePercent, sizePercent);        canvas.drawBitmap(bitmap, srcRect, destRect, paint);        canvas.restore();    }    /**     * 区域外检测     *     * @param starInfo     */    private void resetParticleFloat(Particle starInfo) {        switch (starInfo.direction) {            case LEFT:                if (starInfo.xLocation < -20) {                    starInfo.xLocation = mTotalWidth;                } else {                    starInfo.xLocation -= starInfo.speed;                }                break;            case RIGHT:                if (starInfo.xLocation > mTotalWidth + 20) {                    starInfo.xLocation = 0;                } else {                    starInfo.xLocation += starInfo.speed;                }                break;            case TOP:                if (starInfo.yLocation < -20) {                    starInfo.yLocation = mTotalHeight;                } else {                    starInfo.yLocation -= starInfo.speed;                }                break;            case BOTTOM:                if (starInfo.yLocation > mTotalHeight + 30) {                    starInfo.yLocation = 0;                } else {                    starInfo.yLocation += starInfo.speed;                }                break;            case FREE_POINT://斜线运动,可扩展成为曲线运动                if (starInfo.yLocation > mTotalHeight + 30) {                    starInfo.yLocation = 0;                } else {                    starInfo.yLocation += starInfo.speed;                }                if (starInfo.xLocation < -20) {                    starInfo.xLocation = mTotalWidth;                } else {                    starInfo.xLocation -= starInfo.speed;                }                break;            default:                break;        }    }

管理控制动画的开始结束:
    Handler handler = new Handler() {        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            if (isRuning) {                postInvalidate();                handler.sendMessageDelayed(Message.obtain(), 50);            }        }    };

    public void startAnimationFloat() {        isRuning = true;        handler.sendMessage(Message.obtain());    }    public void stopAnimationFloat() {        isRuning = false;    }    public void restartAnimationFloat() {        startAnimationFloat();    }    public void setFloatType(int floatType) {        this.floatTyep = floatType;    }

三、展示效果
叠加效果【扩展背景】
使用:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="@mipmap/phone_bg"    android:orientation="vertical">    <com.future.particlesystemdemo.view.ParticleView        android:id="@+id/particle_view"        android:layout_width="match_parent"        android:layout_height="match_parent" /></LinearLayout>

public class ShowActivity extends Activity {    /**     * 粒子系统     */    private ParticleView particleView;    /**     * 粒子系统运动类型     */    private int type = 100;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_show);        particleView = (ParticleView) findViewById(R.id.particle_view);        try {//防止无传参跳入            type = getIntent().getIntExtra("type", 100);        } catch (Exception e) {            e.printStackTrace();        }        particleView.setFloatType(ParticleView.DEFAULT_TYPE);        switch (type) {            case 1:                particleView.setFloatType(ParticleView.DEFAULT_TYPE);                break;            case 2:                particleView.setFloatType(ParticleView.FREE_POINT);                break;            case 3:                particleView.setFloatType(ParticleView.TOP);                break;            case 4:                particleView.setFloatType(ParticleView.BOTTOM);                break;            case 5:                particleView.setFloatType(ParticleView.LEFT);                break;            case 6:                particleView.setFloatType(ParticleView.RIGHT);                break;        }        particleView.startAnimationFloat();    }}


源码


百花开时我不开,我若开时百花杀,若与西风战一场,满城尽带黄金甲! 
0 0
原创粉丝点击