Android小程序--模拟焰火粒子和瀑布粒子

   需要注意的是,粒子系统和前面开发的物理小球之间有类似的地方,其都是通过数学方法和物理公式模拟客观世界中物体的运动轨迹。不同的是物理小球更强调个体运动,而焰火粒子系统更注重整体感觉,这点区别在代码中也能体现。
   1、开发粒子对象Particle类:

package xiao.fuyan.particle;

/**
 * Created by xiao on 2017/2/10.
 */
public class Particle {
    //粒子半径
    int r;
    //粒子颜色
    int color;
    //垂直速度
    double v_v;
    //水平速度
    double h_v;
    //初始坐标
    int startX;
    int startY;
    //实时坐标
    int x, y;
    //起始时间
    double startTime;

    //构造器
    public Particle(int color, int r, double v_v, double h_v, int x, int y, double startTime){
        //初始化各个变量
        this.color = color;
        this.r = r;
        this.v_v = v_v;
        this.h_v = h_v;
        this.startX = x;
        this.startY = y;
        this.x = x;
        this.y = y;
        this.startTime = startTime;
    }
}
   2、开发粒子集合ParticleSet类:
package xiao.fuyan.particle;

import android.graphics.Color;

import java.util.ArrayList;

/**
 * Created by xiao on 2017/2/10.
 */
public class ParticleSet {
    //用于存放Particle对象的集合
    ArrayList<Particle> particleSet;
    //构造器,
    public ParticleSet(){
        particleSet = new ArrayList<Particle>();
    }

    //向粒子集合中添加指定个数的粒子对象
    public void add(int count, double startTime){
        for(int i =0; i < count; i++){
            
            //该段代码是开发焰火粒子
            //获取粒子对象的颜色
            int tempColor = this.getColor(i);
            //设置粒子半径
            int tempR = 3;
            //随机产生粒子竖直方向上的速度
            double tempv_v = -30 + 10 * (Math.random());
            //同上获取水平方向上的速度
            double temph_v = 10 - 20 * (Math.random());

            //粒子的X坐标是固定的
            int tempX = 160;
            //随机产生Y坐标,90 - 100之间
            int tempY = (int) (100 - 10 * (Math.random()));

            Particle particle = new Particle(tempColor, tempR, tempv_v, temph_v, tempX, tempY, startTime);
            //将创建好的Particle对象添加到列表中
            particleSet.add(particle);

            //下面代码是将焰火粒子变为瀑布粒子
//            int tempColor = this.getColor(i);
//            //粒子半径
//            int tempR = 3;
//            //竖直方向速度为零
//            double tempv_v = 0;
//            double temph_v = 20 + 10 * (Math.random());
//
//            int tempX = 50;
//            int tempY = (int) (50 - 10 * (Math.random()));
//
//            //创建Particle对象
//            Particle particle = new Particle(tempColor, tempR, tempv_v, temph_v, tempX, tempY, startTime);
//            //将创建好的Particle对象加入列表
//            particleSet.add(particle);
        }
    }

    //获取指定索引的颜色
    public int getColor(int i){
        int color = Color.RED;
        switch (i % 8){
            case 0:
                color = Color.RED;
                break;
            case 1:
                color = Color.BLUE;
                break;
            case 2:
                color = Color.GRAY;
                break;
            case 3:
                color = Color.GREEN;
                break;
            case 4:
                color = Color.CYAN;
                break;
            case 5:
                color = Color.YELLOW;
                break;
            case 6:
                color = Color.MAGENTA;
                break;
            case 7:
                color = Color.LTGRAY;
                break;
        }
        return color;
    }
}
   3、开发物理引擎ParticleThread类:
package xiao.fuyan.particle;

import java.util.ArrayList;

/**
 * Created by xiao on 2017/2/10.
 */
public class ParticleThread extends Thread {

    //线程执行标志位
    boolean flag;
    //ParticleView对象的引用
    ParticleView father;
    //线程休眠的时间
    int sleepSpan = 80;
    //物理引擎的时间轴
    double time = 0;
    //每次计算粒子的位移时采用的时间间隔
    double span = 0.15;

    //构造器
    public ParticleThread(ParticleView father){
        this.father = father;
        this.flag = true;
    }

    //线程执行的方法
    @Override
    public void run() {
        while(flag){
            //每次添加五个粒子
            father.ps.add(15, time);
            //获取粒子集合
            ArrayList<Particle> tempSet = father.ps.particleSet;
            //记录粒子集合的大小
            int count = tempSet.size();
            for(int i = 0; i < count; i++){   //遍历粒子集合,修改其轨迹
                Particle particle = tempSet.get(i);
                //计算从程序开始到现在的时间
                double timeSpan = time - particle.startTime;
                //计算出粒子的X坐标
                int tempX = (int) (particle.startX + particle.h_v * timeSpan);
                //计算Y坐标
                int tempY = (int) (particle.startY + 4.9 * timeSpan * timeSpan + particle.v_v * timeSpan);

                //如果粒子超出屏幕下边沿
                if(tempY > 1920){
                    tempSet.remove(particle);
                    //重新设置粒子的个数
                    count = tempSet.size();
                }

                //修改粒子的坐标
                particle.x = tempX;
                particle.y = tempY;
            }

            //将时间延长
            time += span;
            try{
                Thread.sleep(sleepSpan);//休眠一段时间
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}
   4、开发视图ParticleView类:
package xiao.fuyan.particle;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.util.ArrayList;

/**
 * Created by xiao on 2017/2/10.
 */
public class ParticleView extends SurfaceView implements SurfaceHolder.Callback {
    //粒子的Y坐标超过该值就会从粒子集合中移出
    public static final int DIE_OUT_LINE = 1920;
    //后台刷新屏幕的线程
    DrawThread dt = null;
    //ParticleSet对象的引用
    ParticleSet ps;
    //ParticleThread对象的引用
    ParticleThread pt;
    //声明帧速率字符串
    String fps = "FPS:N/A";

    //构造器
    public ParticleView(Context context){
        super(context);
        //添加callback接口
        this.getHolder().addCallback(this);
        //创建DrawThread对象
        dt = new DrawThread(this, getHolder());
        //创建ParticleSet对象
        ps = new ParticleSet();
        //创建ParticleThread对象
        pt = new ParticleThread(this);
    }

    //绘制屏幕
    public void doDraw(Canvas canvas){
        //清除屏幕
        canvas.drawColor(Color.BLACK);
        //获取ParticleSet对象中的粒子
        ArrayList<Particle> particleSet = ps.particleSet;

        Paint paint = new Paint();
        for(int i = 0; i < particleSet.size(); i++){
            Particle p = particleSet.get(i);
            paint.setColor(p.color);
            //获取粒子坐标和半径
            int tempX = p.x;
            int tempY = p.y;
            int tempR = p.r;
            //绘制该粒子
            RectF oval = new RectF(tempX, tempY, tempX + 2 * tempR, tempY + 2 * tempR);
            canvas.drawOval(oval, paint);
        }

        //设置画笔颜色
        paint.setColor(Color.WHITE);
        paint.setTextSize(60);
        paint.setAntiAlias(true);
        //画出帧速率字符串
        canvas.drawText(fps, 900, 80, paint);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        //启动线程
        if(!dt.isAlive()){
            dt.start();
        }
        if(!pt.isAlive()){
            pt.start();
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        //停止线程
        dt.flag = false;
        dt = null;
        pt.flag = false;
        pt = null;
    }
}
   5、开发DrawThread类:
package xiao.fuyan.particle;

import android.graphics.Canvas;
import android.view.SurfaceHolder;

/**
 * Created by xiao on 2017/2/10.
 */
public class DrawThread extends Thread {
    //ParticleView对象
    ParticleView particleView;
    //SurfaceHolder对象的引用
    SurfaceHolder surfaceHolder;
    //线程执行的标志位
    boolean flag = false;
    //休眠时间
    int sleepSpan = 30;
    //记录起始时间,用于计算帧速率
    long start = System.nanoTime();
    //记录帧数,
    int count = 0;

    //构造器
    public DrawThread(ParticleView particleView, SurfaceHolder surfaceHolder){
        this.particleView = particleView;
        this.surfaceHolder = surfaceHolder;
        this.flag = true;
    }

    @Override
    //线程执行的方法,用于重绘屏幕和计算帧速率
    public void run() {
        Canvas canvas = null;
        while(flag){
            try{
                //获取ParticleView的画布
                canvas = surfaceHolder.lockCanvas(null);
                //加锁并且绘制
                synchronized (surfaceHolder){
                    particleView.doDraw(canvas);
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                if(canvas != null){   //如果canvas不为空
                    //surfaceHolder解锁,并将画布对象传回
                    surfaceHolder.unlockCanvasAndPost(canvas);
                }
            }

            //如果计满20帧,计算帧速率
            this.count++;
            if(count == 20){
                count = 0;
                //获取当前时间
                long tempStamp = System.nanoTime();
                //获取时间间隔
                long span = tempStamp - start;;
                //为start重新赋值
                start = tempStamp;
                //计算帧速率
                double fps = Math.round(10000000000.0 / span * 20) / 100.0;
                //设置实时帧速率
                particleView.fps = "FPS" + fps;
            }
        }

        try{
            Thread.sleep(sleepSpan);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
   6、开发程序MainActivity类:
package xiao.fuyan.particle;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;


public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //设置不显示标题
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        //设置全屏显示模式
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        //创建一个ParticleView对象
        ParticleView particleView = new ParticleView(this);
        setContentView(particleView);

    }
}

猜你喜欢

转载自xiaofuyan.iteye.com/blog/2357368