J2ME 3D粒子系统技术(2)焰火粒子系统例子

    技术2022-05-20  38

    下面将构造一个简单的焰火粒子系统。整个系统由3个类组成:Particle、FireworksEffect和ParticleSystem.

     

    Particle类存储了每个粒子的基本属性,包括生命,衰减,速度,位置和颜色,对于复杂的粒子还包含其他更多的

    属性。Particle类代码如下:

     

    public class Particle{    //生命属性    private float life = 1.0f;        // 衰减属性    private float degradation = 0.1f;        // 速度属性    private float[] vel = {0.0f, 0.0f, 0.0f};        // 位置属性    private float[] pos = {0.0f, 0.0f, 0.0f};        //颜色属性    private int color = 0xffffff;        /** 空构造函数 */    public Particle()    {            }      //设置速度,初始位置,初始颜色的方法    public Particle(float[] velocity, float[] position, int color)    {        setVel(velocity);     //设置初始速度        setPos(position);       //设置初始位置        this.setColor(color);     //设置初始颜色    }

        //设置生命方法    void setLife(float life) {        this.life = life;    }

        //获取生命    float getLife() {        return life;    }

        //设置速度    void setVel(float[] tvel) {        System.arraycopy(tvel, 0, vel, 0, vel.length);    }

        //获取速度    float[] getVel() {        return vel;    }

        //设置位置    void setPos(float[] tpos) {        System.arraycopy(tpos, 0, pos, 0, pos.length);    }

        //获取位置    float[] getPos() {        return pos;    }

        //设置颜色    void setColor(int color) {        this.color = color;    }

       //获取颜色    int getColor() {        return color;    }

       //设置衰减    public void setDegradation(float degradation) {        this.degradation = degradation;    }

        //获取衰减    public float getDegradation() {        return degradation;    }}

     

     

    Particle类提供了粒子的数据结构,还需要有粒子实体。FireworksEffect类提供了init方法对粒子参数进行初始化,并且创建四边形Mesh对象。Mesh对象包含了顶点缓冲,索引缓冲和外观属性。FireworksEffect类的createAlphaPlane方法创建四边形,该四边形只有位置数组和纹理坐标数组,设置外观属性只显示正面,并且纹理和色彩进行颜色融合

     

    FireworksEffect类代码如下:

    public class FireworksEffect {    // 发射角度    private int angle = 90;        // 三角函数    private float[] trig = {1.0f, 0.0f};        // 喷发源    private float[] pos = {0.0f, 0.0f, 0.0f};        // 随机数    Random rand = null;           Mesh mesh = null;        // 矩阵转换    Transform trans = new Transform();        // 缩放值    float scale = 1.0f;       //构造函数    public FireworksEffect(int angle)    {                 // 设置发射角度        setAngle(angle);        // 创建四边形        mesh = createAlphaPlane("/particle.png");                // 缩放值        this.scale = 0.1f;                // 获得随机数        rand = new Random();    }

            //对粒子的参数进行初始化    public void init(Particle p)    {        // 设置生命        p.setLife(1.0f);                // 设置位置        p.setPos(pos);                // 速度        float[] vel = new float[3];                // rand.nextFloat()随机产生0-1的数        float xyvel = rand.nextFloat() * 0.8f + 0.2f;                // 设置衰减速度        p.setDegradation(xyvel / 18);                // 设置x,y方向速度        vel[0] = xyvel * trig[1] + rand.nextFloat() * 0.125f - 0.0625f;        vel[1] = xyvel * trig[0] + rand.nextFloat() * 0.125f - 0.0625f;                // z方向速度        vel[2] = 0.0f;                // 设置粒子的速度数组        p.setVel(vel);                       int r = (int)(120 * rand.nextFloat()) + 120;    // 随机生成Red颜色        int g = (int)(120 * rand.nextFloat()) + 120;    //随机生成Green颜色        int b = (int)(120 * rand.nextFloat()) + 120;    //随机生成Blue颜色        int col = (r << 16) | (g << 8) | b;              //融合RGB        p.setColor(col);                                 //设置粒子的颜色    }    

        //已经消失的粒子则重新初始化    public void update(Particle p)    {                float[] ppos = p.getPos();    //获取当前位置        float[] vel = p.getVel();      //获取速度        ppos[0] += vel[0];             //x方向上移动        ppos[1] += vel[1];             //y方向上移动        ppos[2] += vel[2];             //z方向上不移动                // 更新生命值        p.setLife(p.getLife() - p.getDegradation());                // 判断粒子是否存活        if(p.getLife() < -0.001f)        {            init(p);        }    }

        //设置发射角度    public void setAngle(int angle) {        this.angle = angle;          //设置发射角度        trig[0] = (float)Math.sin(Math.toRadians(angle));   //正弦        trig[1] = (float)Math.cos(Math.toRadians(angle));   //余弦    }

        //获取发射角度    public int getAngle() {        return angle;    }

     

        //缩放粒子并平移    public void render(Particle p, Graphics3D g3d)    {        // Alpha值        int alpha = (int)(255 * p.getLife());                // RGBA颜色        int color = p.getColor() | (alpha << 24);                // 设置四边形的颜色        mesh.getVertexBuffer().setDefaultColor(color);               trans.setIdentity();        trans.postScale(scale, scale, scale);        float[] pos = p.getPos();        trans.postTranslate(pos[0], pos[1], pos[2]); //平移                // 根据变换矩阵绘制四边形        g3d.render(mesh, trans);    }        //创建四边形的方法       private Mesh createAlphaPlane(String texFilename)    {                // 顶点缓冲        short POINTS[] = new short[] {-1, -1, 0,                                       1, -1, 0,                                       1, 1, 0,                                       -1, 1, 0};        // 定点数组        short TEXCOORDS[] = new short[] {0, 255,                                         255, 255,                                         255, 0,                                         0, 0};        // 位置数组        VertexArray POSITION_ARRAY = new VertexArray(POINTS.length/3, 3, 2);        POSITION_ARRAY.set(0, POINTS.length/3, POINTS);        //纹理数组        VertexArray TEXCOORD_ARRAY = new VertexArray(TEXCOORDS.length / 2, 2, 2);        TEXCOORD_ARRAY.set(0, TEXCOORDS.length / 2, TEXCOORDS);        // 顶点缓冲        VertexBuffer vertexBuffer = new VertexBuffer();        vertexBuffer.setPositions(POSITION_ARRAY, 1.0f, null);    //设置位置数组        vertexBuffer.setTexCoords(0, TEXCOORD_ARRAY, 1.0f/255.0f, null);  //设置纹理数组        vertexBuffer.setDefaultColor(0xffffffff);                  //设置默认颜色        // 索引缓冲        int INDICES[] = new int[] {0, 1, 3, 2};        int[] LENGTHS = new int[] {4};                // 索引缓冲        IndexBuffer indexBuffer = new TriangleStripArray(INDICES, LENGTHS);

            // 外观属性        Appearance appearance = new Appearance();        PolygonMode polygonmode = new PolygonMode();        polygonmode.setCulling(PolygonMode.CULL_BACK);   //剔除背面        appearance.setPolygonMode(polygonmode);        CompositingMode compositingmode = new CompositingMode();        compositingmode.setBlending(CompositingMode.ALPHA);   //透明融合        appearance.setCompositingMode(compositingmode);                      try        {            //加载纹理图片            Image texImage = Image.createImage(texFilename);            Texture2D texture = new Texture2D(new Image2D(Image2D.RGBA, texImage));                        // 支持透明颜色            texture.setBlending(Texture2D.FUNC_REPLACE);                                    texture.setWrapping(Texture2D.WRAP_CLAMP, Texture2D.WRAP_CLAMP);            texture.setFiltering(Texture2D.FILTER_BASE_LEVEL, Texture2D.FILTER_NEAREST);            texture.setBlending(Texture2D.FUNC_BLEND);                        appearance.setTexture(0, texture);

            }        catch(Exception e)        {            // 捕捉异常            System.out.println("Failed to create texture");            System.out.println(e);        }                // 创建四边形对象        Mesh mesh = new Mesh(vertexBuffer, indexBuffer, appearance);

            return mesh;    }}

     

    Particle类保存了粒子的方位速度等抽象信息,FireworksEffect类用来创建,更新粒子,ParticleSystem类

    将两者连接并进行管理。代码如下:

     

    public class ParticleSystem{    //粒子效果    private FireworksEffect effect = null;        // 粒子数组    Particle[] parts = null;   

        public ParticleSystem(FireworksEffect effect, int num)    {        // 设置粒子效果        setEffect(effect);                // 根据数量创建粒子数组        parts = new Particle[num];        for(int i = 0; i < num; i++)        {            parts[i] = new Particle();            effect.init(parts[i]);    //根据粒子效果的内容初始化粒子数组,部分数据采用随机生成        }    }            public void emit(Graphics3D g3d)    {        for(int i = 0; i < parts.length; i++)        {            getEffect().update(parts[i]);         //更新粒子信息            getEffect().render(parts[i], g3d);    //绘制粒子        }    }

            public void setEffect(FireworksEffect effect) {        this.effect = effect;    }

            public FireworksEffect getEffect() {        return effect;    }}

     

    下面是游戏画布类M3GCanvas类的代码:

     

    public class M3GCanvas extends GameCanvas implements Runnable {

       

                boolean[] key = new boolean[5];        //获取按键改变发射角度    public static final int FIRE = 0;    public static final int UP = FIRE + 1;    public static final int DOWN = UP + 1;    public static final int LEFT = DOWN + 1;    public static final int RIGHT = LEFT + 1;        // 矩阵    Transform identity = new Transform();        //3D画笔对象    Graphics3D g3d = null;        //背景    Background back = null;        // 场景摄像机    Camera camera = null;        // 粒子系统    ParticleSystem ps = null;    FireworksEffect effect = null;        //初始化    public M3GCanvas()    {                super(true);                // 设置全屏        setFullScreenMode(true);                // 加载摄像机        camera = new Camera();                // 创建背景        back = new Background();        back.setColor(0);

            // 获取实例        g3d = Graphics3D.getInstance();        Light light = new Light();        light.setMode(Light.AMBIENT);        light.setIntensity(1.0f);        // 增加灯光        g3d.addLight(light, identity);        Thread t = new Thread(this);

            t.start();    }   

     

        //绘制屏幕       private void draw(Graphics g)    {                try        {                                g3d.bindTarget(g, true, Graphics3D.ANTIALIAS | Graphics3D.TRUE_COLOR | Graphics3D.DITHER);                  //清屏         g3d.clear(back);                           g3d.setCamera(camera, identity);                  // 初始化粒子         if(ps == null)         {             effect = new FireworksEffect(90);             ps = new ParticleSystem(effect, 30);         }                  // 发射粒子         ps.emit(g3d);                  // 获取角度         if(key[LEFT])             effect.setAngle(effect.getAngle() + 5);         if(key[RIGHT])             effect.setAngle(effect.getAngle() - 5);

            }        catch(Exception e)        {

                      e.printStackTrace();        }        finally        {            // 记得释放            g3d.releaseTarget();        }    }

            //线程    public void run() {        while(true) {            try {                                // 获取键盘输入                process();                                // 画                draw(getGraphics());                flushGraphics();                                //等待时间                try{ Thread.sleep(30); } catch(Exception e) {}            }            catch(Exception e) {

                    e.printStackTrace();            }        }

        }   

            //获取键盘输入方法    protected void process()    {        int keys = getKeyStates();

                    if((keys & GameCanvas.LEFT_PRESSED) != 0)            key[LEFT] = true;        else            key[LEFT] = false;                if((keys & GameCanvas.RIGHT_PRESSED) != 0)            key[RIGHT] = true;        else            key[RIGHT] = false;    } }

     

    下面是M3GMIDlet类的代码:

    public class M3GMIDlet extends MIDlet implements CommandListener{

      

     

      private Command exitCommand = new Command("Exit", Command.EXIT, 1);      public void startApp()  {       M3GCanvas mCanvas = new M3GCanvas();    mCanvas.addCommand(exitCommand);    mCanvas.setCommandListener(this);    Display.getDisplay(this).setCurrent(mCanvas);  }     public void pauseApp()  {  } 

      public void destroyApp(boolean unconditional)  {  }     public void commandAction(Command command, Displayable displayable)  {    if (command == exitCommand)    {           destroyApp(true);      notifyDestroyed();    }     }

     

     

    下面是该例子程序的演示效果以及用例用到的图片:

     

     

     


    最新回复(0)