您的位置:首页 > 其它

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

2011-04-15 22:18 239 查看
下面将构造一个简单的焰火粒子系统。整个系统由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();
}

}

下面是该例子程序的演示效果以及用例用到的图片:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: