游戏中经常使用到爆炸特效,爆炸可以使用单纯的图片回放,也可以用程序仿真爆炸的物理过程,这样爆炸效果更加逼真
使用粒子系统对爆炸进行摸摸你的基本原理是用大量粒子对爆炸的流体力学原理进行模拟
在爆炸的效果的运动过程中,一开始它是将各种块状物体在一瞬间有一个圆心向外围圆周的任意方向拓展,形成一个爆炸最初期的现象
要营造爆炸粒子系统,可以在上面的焰火喷射的基础上加以改动,将粒子向单一方向发射改为四面八方喷射,这点可以通过改变
粒子在x方向和y方向上的增量实现。
几个类和上个例子差别不大,只是在ParticleSystem类的构造方法中,将根据粒子的数量360°圆周角进行划分。
ParticleSystem类的代码:
public class ParticleSystem{ // 构造粒子 private ExplosionEffect effect = null; //粒子数组 Particle[] parts = null;
public ParticleSystem(ExplosionEffect effect, int num) { setEffect(effect);
// 初始化粒子 parts = new Particle[num]; for(int i = 0; i < num; i++) { parts[i] = new Particle(); effect.init(parts[i],360*i/num); } } 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(ExplosionEffect effect) { this.effect = effect; }
public ExplosionEffect getEffect() { return effect; }}
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; private int color_index; public Particle() { } public Particle(float[] velocity, float[] position, int color) { setVel(velocity); setPos(position); this.setColor(color); }
void setLife(float life) { this.life = life; } void setColorIndex(int index){ this.color_index = index; } int getColorIndex(){ return color_index; }
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; }}
ExplosionEffect类代码如下:
public class ExplosionEffect { // 喷射角度 private int angle = 90; // 角度的正弦值 private float[] trig = {1.0f, 0.0f}; private int[] color = {0x000000,0x100000,0x2C0000,0x480000,0x650000,0x810000,0xA10000,0xC20000, 0xE20000,0xFF0000,0xFF6500,0xFF9500,0xFFC600,0xFFFF00,0xFFFF7D,0xFFFFFF}; // 发散根源 private float[] pos = {0.0f, 0.0f, 0.0f}; // 随机数 Random rand = null; // 四边形 Mesh mesh = null; // 转换矩阵 Transform trans = new Transform(); // 比例 float scale = 1.0f; public ExplosionEffect() { mesh = createAlphaPlane("/particle.png"); this.scale = 0.1f; rand = new Random(); }
public void init(Particle p,int angle) { setAngle(angle); p.setLife(1.0f); p.setPos(pos); p.setColorIndex(15); float[] vel = new float[3]; float xyvel = rand.nextFloat() * 0.8f + 0.2f; p.setDegradation(xyvel / 18); vel[0] = xyvel * trig[1] + rand.nextFloat() * 0.125f - 0.0625f; vel[1] = xyvel * trig[0] + rand.nextFloat() * 0.125f - 0.0625f; vel[2] = 0.0f; p.setVel(vel);
p.setColor(0xFFFFFF); }
public void update(Particle p) { float[] ppos = p.getPos(); float[] vel = p.getVel(); ppos[0] += vel[0]; ppos[1] += vel[1]; ppos[2] += vel[2]; ppos[1] -= 0.5; p.setLife(p.getLife() - p.getDegradation());
int color_index = p.getColorIndex(); if(p.getLife()>0)p.setColor(color[color_index]);
color_index -= 1; if(color_index<=0)color_index=0; p.setColorIndex(color_index); }
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) { int alpha = (int)(255 * p.getLife()); 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; }}
画布类M3GCanvas类代码如下:
public class M3GCanvas extends GameCanvas implements Runnable {
boolean[] key = new boolean[5]; boolean isReleased = true; 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(); Graphics3D g3d ; Graphics g2d; Background back = null; Camera camera = null; ParticleSystem ps = null; ExplosionEffect effect = null; public M3GCanvas() { super(true); setFullScreenMode(false); 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(); }
MIDlet类代码如下:
public class M3GMIDlet extends MIDlet implements CommandListener{
private Command exitCommand = new Command("Exit", Command.EXIT, 1); private M3GCanvas mCanvas; public void startApp() { 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(); } }}