站内搜索:
网站首页化境产品软件资讯手机开发应用开发手机软件下载源代码下载编程工具开发资料博客
方式:
关键字:
 
  相关内容
  · MIDP中尝试粒子系统
· MIDP2.0的新增特性
 
当前位置: 化境编程网 >> J2ME
MIDP中尝试粒子系统
[时间: 2006-5-15 1:32:49 作者:favoyang ]

来源: J2MEDev


  粒子系统在图形学上的应用十分广泛。最常见的,是通过控制大量的、具有相似行为的点元素,来描绘自然现象。例如下雨、下雪、火焰、水、雾等等。在家用控制台或PC上的2D、3D游戏中,粒子特效代替了更为传统的精灵绘图,并取得了更灵活多变的视觉效果。但在手机设备上,因为机能和API的诸多限制,对于这一技术的应用并不常见。本文试图尝试一下如何在这些设备上实现简单的例子系统。这仅仅是一次试验,并不能保证一定能用于你的实际开发。

粒子系统简介
粒子系统,即粒子群系统。在自然界中,微粒以各种各样的方式聚集在一起形成,拥有了自身的属性和运动规律,构成了复杂的世界。对这种微粒的研究过于宽泛,我们仅仅关注微粒系统在图形学上应用的一小部分应用。一个常见的微粒系统由两部分组成:微粒群和微粒管理器。微粒包括了一系列的属性:速度、颜色、贴图等和一系列的行为。微粒管理器则负责创建微粒群,调用微粒群的行为、以及将微粒群表现出来(显示)。
JAVA手机网[www.cnjm.net]





JAVA手机网[www.cnjm.net]
例子系统常见的应用有:描述群体(一个子弹群)、描述自然现象(下雨、下雪、火焰、水、雾)。此文关注的是后者。

JAVA手机网[www.cnjm.net]
实现粒子系统的成本
实现通用粒子系统的前提:
JAVA手机网[www.cnjm.net]
1,要有足够的内存空间保存粒子系统本身
2,可以对屏幕上的点进行控制

对于第1条,我的建议是,不要为每一个粒子系统建立类对象,仅仅保存一个多维数组用作描述状态信息。行为可以抽象到粒子管理器去处理。尽管这样,当粒子数目很多时其消耗也是非常惊人的。
对于第2条,MIDP2.0提供了对屏幕上的点进行访问的能力。这一能力是通过Graphics的

JAVA手机网[www.cnjm.net]
void drawRGB(int[] rgbData, int offset, int scanlength, int x, int y, int width, int height, boolean processAlpha)
         Renders a series of device-independent RGB+transparency values in a specified region.
JAVA手机网[www.cnjm.net]

方法实现的。此方法不是直接取得对缓冲区的操作能力,而是通过对一个rgbData进行各种操作,然后将它绘画出来,从而实现点的控制。换句话说,对屏幕的点的控制,转换为了对数组的控制。不开放对缓冲区的直接操作,优点是:不去限制硬件厂商的实现;缺点是:一旦要对整个屏幕进行像素操作,就不得不开辟一个足够大的数组,则对普通的手机来说显得负担承重。以sek700为例,176*221=38896像素,每个像素一个int(占2Byte),则总共需要77792B约76KB的连续空间。正如后面看到的,大量的例子算法需要使用到Blur技术用于提高画面效果。此技术需要上次的屏幕的点信息,因此需要两个76KB的连续空间。这还不算粒子群本身需要的空间。如果仅仅作为屏幕特效,就吃掉两个76KB的连续空间似乎有些得不偿失。另外,标准没有对数组进行操作的绘图指令,因此如何对数组进行简单的画圆、输出字符等操作都很棘手。所以可以预见,因为标准API的限制,我们仅能有限的利用粒子系统。

试验一:模拟瀑布
基本思路:将粒子群的出生地定于一点,随机产生一个小范围的水平速度。让粒子按照自然规律自由落体。在接触地的时候发生碰撞,产生很小的向上动力(能量衰减)。




     
以下是代码,其中blur是一种简单的模糊算法,它可以上画面更见好看,这里使用的是算法是取一个点为其周围四个点的平均值。这个例子使用了调色板技术实现了瀑布由白向蓝再向黑的过渡(查表法)。通过这个例子,你可了解到例子系统的基本实现、简单的物理模型模拟和调色板的使用技巧。在模拟器上运行很慢,但在Nokia3310上有13fps。
public class Waterfall {
JAVA手机网[www.cnjm.net]

public static final int X = 0;

public static final int Y = 1;

public static final int VX = 2;

public static final int VY = 3;

public static final int XACC = 4;

public static final int YACC = 5;

public static final int LIFE = 6;

public static final int DECAY = 7;

int[][] particle;

private int max;

private int last;

JAVA手机网[www.cnjm.net]
public Palette pal;

/*
 * [...][X] :x-coordinates, [...][Y] :y-coordinates, [...][VX] :x-velocity,
 * [...][VY] :y-velocity, [...][XACC] :x-acceleration,
 * [...][YACC]:y-acceleration, [...][LIFE] :life cycle, [...][DECAY] :decay
 */

/**
 *  
 */
public Waterfall(int max) {
 this.max = max;
 particle = new int[max][8];
 pal = new Palette();
 initPal();
}

private void initPal() {//初始化调色板
 for (int i = 0; i < pal.data.length; i++) {//black-->blue-->white
  pal.setColor(i, i >= 128 ? (i - 128) * 2 : 0, i, i * 2 >= 255 ? 255
JAVA手机网[www.cnjm.net]
    : i * 2);
 }
//  for(int i=0;i<64;i++)
//   pal.setColor(i,i,i/3,0);
//  for(int i=64;i<192;i++)
//   pal.setColor(i,63,21+(i-64)/3,0);
//  for(int i=192;i<256;i++)
//   pal.setColor(i,63,63,(i-192)*4);
}

public void init(int x, int y, int high) {//初始化
 for (int i = 0; i < max; i++) {
  particle[i][LIFE] = 0;//kill all particle first
 }
 refreshState(x, y);
 last = (y + high) << 10;
JAVA手机网[www.cnjm.net]
}

public void refreshState(int x, int y) {//更新
 int xx = x << 10;
JAVA手机网[www.cnjm.net]
 int yy = y << 10;
 for (int i = 0; i < max; i++) {
JAVA手机网[www.cnjm.net]
  if (particle[i][LIFE] <= 0) {
   particle[i][X] = xx;
   particle[i][Y] = yy;
   particle[i][VX] = CoreUtilities.rand(500, 500);
   particle[i][VY] = CoreUtilities.rand(500, 1500);
   particle[i][XACC] = 0;
   particle[i][YACC] = 50;
   particle[i][LIFE] = 1000;
   particle[i][DECAY] = CoreUtilities.rand(0, 125);
  }
 }
}

public void move() {//移动
 for (int i = 0; i < max; i++) {
  if (particle[i][LIFE] > 0) {
   particle[i][X] += particle[i][VX];
   particle[i][Y] += particle[i][VY];
   //    particle[i][VX]+=particle[i][XACC];//not need this time
   particle[i][VY] += particle[i][YACC];
   particle[i][LIFE] -= particle[i][DECAY];
  }
  if (particle[i][Y] > last) {
//    System.out.println("before: "+particle[i][VY]);
//    particle[i][VY] = -particle[i][VY];
   //        particle[i][DECAY]+=50;
   particle[i][LIFE] -= 500;//模拟能量衰减
//    particle[i][VY] += 3500;//manual speed-down
   particle[i][VY] = CoreUtilities.rand(-1000,400);//模拟能量衰减
//    System.out.println("after "+particle[i][VY]);
//    particle[i][VX] ;
   //    particle[i][LIFE] = 0;
//    System.out.println("particle[i][LIFE]: "+particle[i][LIFE]);
JAVA手机网[www.cnjm.net]
  }
 }
}

public void paint(byte[] buffer, int scanlength) {//绘画
 int i = 0;
 int col = 0, row = 0;
 int lastrow = buffer.length / scanlength - 1;
 int lastcol = scanlength - 1;
 try {
  for (i = 0; i < max; i++) {
   col = particle[i][X] >> 10;
   row = particle[i][Y] >> 10;
   if(row > lastrow||row<0||col<0||col>lastcol)
    continue;
   buffer[scanlength * (row > lastrow ? lastrow : row)
     + (col > lastcol ? lastcol : col)] = 127;
  }
 } catch (Exception e) {
JAVA手机网[www.cnjm.net]
  System.out.println(e);
  System.out.println("particle[i][X] : " + particle[i][X]);
  System.out.println("particle[i][Y] : " + particle[i][Y]);
JAVA手机网[www.cnjm.net]
  System.out
    .println("particle[i][X]>>10 : " + (particle[i][X] >>10));
  System.out
    .println("particle[i][Y]>>10 : " + (particle[i][Y] >>10));
  System.out.println("scanlength * (row > lastrow ? lastrow : row)+ (col > lastcol ? lastcol : col) :"
    + (scanlength * (row > lastrow ? lastrow : row)
      + (col > lastcol ? lastcol : col)));
  }
}

public void blur(byte[] inBuffer, byte[] outBuffer, int scanlength) {//模糊算法

 int k = scanlength;
 int backheight = inBuffer.length / scanlength;
 for (int i = 1; i < backheight - 1; i++) {
  for (int j = 0; j < scanlength; j++) {
   outBuffer[k] = (byte) ((inBuffer[k - 1] + inBuffer[k + 1]
     + inBuffer[k - scanlength] + inBuffer[k + scanlength]) >> 2);
   //    if (outBuffer[k] > -126)
   //     outBuffer[k] -= 2;
   //    else
   //     outBuffer[k] = -128;
JAVA手机网[www.cnjm.net]
   k++;
JAVA手机网[www.cnjm.net]
  }
 }
 //  for (k = 0; k < scanlength; k++) {
 //   outBuffer[k] = inBuffer[k];
 //  }
 //  for (k = (backheight - 1) * scanlength; k < inBuffer.length; k++) {
 //   outBuffer[k] = inBuffer[k];
 //  }
JAVA手机网[www.cnjm.net]
}

public String toString() {//调试信息
 StringBuffer sb = new StringBuffer();
 for (int i = 0; i < max; i++) {
  sb.append(particle[i][X] + " " + particle[i][Y] + " "
    + particle[i][VX] + " " + particle[i][VY] + " "
    + particle[i][XACC] + " " + particle[i][YACC] + " "
    + particle[i][LIFE] + " " + particle[i][DECAY] + "\n");
 }

 return sb.toString();
}
}

JAVA手机网[www.cnjm.net]

JAVA手机网[www.cnjm.net]
试验二:模拟定点火
有了上面的基础,我们这次就驾轻就熟了。只要准备好调色板,确定好粒子的状态:出生位置,选择适当的blur算法就可以了。
火焰这个例子有些特殊的地方是,并不需要很多的粒子属性。仅仅将粒子出生于屏幕底端(火焰的定点位置),再通过一个特殊的blur算法,就可实现了。这个blur算法就是取一点为自身和自身正下方、左下方、右下方四点的平均值。这样一来,火焰就诞生了。这个例子在Nokia3310上有13fps。因为选取的调色板不是很好,所以颜色很黯淡,你也可以使用更高的调色板达到更好的效果。


JAVA手机网[www.cnjm.net]

   
试验三:模拟爆炸
和火焰大同小异,blur算法换回了标准的算法。主要是物理模型变动,加速度很重要,因为它可以改变物体的运动方向。这个例子在Nokia3310上有13fps。


 

试验四:模拟水波
JAVA手机网[www.cnjm.net]
算法来自一片经典文章,是某位前辈很早之前贡献出来的,有兴趣可以google一下。为表尊重,图片依旧用的原来的图片。算法大意是通过势能计算物体位移。这个例子在Nokia3310上有12fps。
JAVA手机网[www.cnjm.net]




试验五:模拟星空
最后这个例子并没有用到blur算法,所以速度很快,效果也不错。只要是利用颜色速度区分远近达到视觉上的层次感效果。这个例子在Nokia3310上有36fps。
JAVA手机网[www.cnjm.net]

JAVA手机网[www.cnjm.net]

 
JAVA手机网[www.cnjm.net]

总结
机能和标准API的双重限制,让我们使用粒子系统遇到了不少的障碍。但在高端手机设备上,内存堆比较大,可以尝试利用粒子系统进行一些特效(菜单使用火焰等),在支持Alpha合成的机器上,还可以引入一个单纯的特性层,来进行特效合成,这对于高档手机的机能是个开发。本文仅仅泛泛而谈,几个实例也很简单,都有优化的余地。感兴趣读者可自行实现。
--- 文章结束 ---

 
| 关于我们 | 联系方法 | 网络广告 | 解决方案 | 产品服务 |

©Copyright by 中晟科技 2003 - 2006 QQ:142907 稻香老农