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

下面将构造一个简单的焰火粒子系统。整个系统由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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值