我们在试用andengine编写游戏应用的时候,如果想在游戏中增加丰富多彩绚丽的元素,可是尝试下试用粒子发射器,
andengine examples中提供了三个例子来演示两种动态火焰的形成,效果很逼真,粒子发射器能够形成火焰,其原理可以理解成跟示波器形成图形有点相似,粒子发射器发射的是自定义的效果元素,示波器发射的是电子,都是通过大量的元素进行刷新,绘制等操作形成的图形,所不同的是,粒子发射器发射的粒子有范围的限制,而且需要自己手动的将过期的粒子杀死来形成动态的效果,而示波器是电子不断打在屏幕上形成的印记。
下面我尝试从源码来解释火焰效果的形成。
一,圆盘型粒子发射器,先看效果图:
a. b.
c. d.
onLoadResources()方法:
@Override public void onLoadResources() { this.mTexture = new Texture(32, 32, TextureOptions.BILINEAR_PREMULTIPLYALPHA); this.mParticleTextureRegion = TextureRegionFactory.createFromAsset(this.mTexture, this, "gfx/particle_point.png", 0, 0); this.mEngine.getTextureManager().loadTexture(this.mTexture); }
onLoadScene()方法:
@Override public Scene onLoadScene() { this.mEngine.registerUpdateHandler(new FPSLogger()); final Scene scene = new Scene(1); //CircleOutlineParticleEmitter为圆形的例子发射器,其构造方法中的参数:第一第二个为圆心的位置,第三个为半径 final CircleOutlineParticleEmitter particleEmitter = new CircleOutlineParticleEmitter(CAMERA_WIDTH * 0.5f, CAMERA_HEIGHT * 0.5f + 20, 80); //ParticleSystem为粒子系统,屏幕上的所有粒子都归这个类统一管理 final ParticleSystem particleSystem = new ParticleSystem(particleEmitter, 60, 60, 360, this.mParticleTextureRegion); //备注1 scene.setOnSceneTouchListener(new IOnSceneTouchListener() { @Override public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) { particleEmitter.setCenter(pSceneTouchEvent.getX(), pSceneTouchEvent.getY()); return true; } }); //初始化粒子的状态 //ColorInitializer中的参数为RGB颜色,(1,0,0)就代表红色 //AlphaInitializer中的参数为透明值 //setBlendFunction这个是颜色的混合方式,这里有详细的介绍:http://www.cnblogs.com/yujunyong/archive/2011/04/13/2015467.html //VelocityInitializer中的参数:第一个为x轴最小的速度,第二个为x轴最大的速度,第三个为y轴最小的速度,第四个为y轴最大的速度 //RotationInitializer中的参数:第一个是最小的角度,第二个是最大的角度 particleSystem.addParticleInitializer(new ColorInitializer(1, 0, 0)); particleSystem.addParticleInitializer(new AlphaInitializer(0)); particleSystem.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE); particleSystem.addParticleInitializer(new VelocityInitializer(-2, 2, -20, -10)); particleSystem.addParticleInitializer(new RotationInitializer(0.0f, 360.0f)); //修改粒子的状态 //ScaleModifier中的参数:第一个为from状态,第二个为to状态,第三个为开始的时间,第四个为结束的时间; //ScaleModifier(1.0f, 2.0f, 0, 5)代表是在0-5秒,粒子放大一倍; //------------------------------------------------------------------------------------------------- //ColorModifier中的参数:第一第三第五代表开始的颜色RBG值,第二第四第六代表最终的颜色RGB值,第七第八个参数为时间范围 //ColorModifier(1, 1, 0, 0.5f, 0, 0, 0, 3)代表0-3秒,颜色(1,0,0)变为(1,0.5f,0); //------------------------------------------------------------------------------------------------- //AlphaModifier中的参数:第一个代表from的透明值,第二个代表to的透明值,第三第四个为时间的范围 //AlphaModifier(0, 1, 0, 1)代表在0-1秒,粒子由不透明变成透明状态 //------------------------------------------------------------------------------------------------- //ExpireModifier中的参数:第一个参数为粒子的最小存活时间,第二个参数为粒子最长的存活时间; //ExpireModifier(6, 6)代表粒子可以存活6秒 particleSystem.addParticleModifier(new ScaleModifier(1.0f, 2.0f, 0, 5)); particleSystem.addParticleModifier(new ColorModifier(1, 1, 0, 0.5f, 0, 0, 0, 3)); particleSystem.addParticleModifier(new ColorModifier(1, 1, 0.5f, 1, 0, 1, 4, 6)); particleSystem.addParticleModifier(new AlphaModifier(0, 1, 0, 1)); particleSystem.addParticleModifier(new AlphaModifier(1, 0, 5, 6)); particleSystem.addParticleModifier(new ExpireModifier(6, 6)); //备注2 scene.getTopLayer().addEntity(particleSystem); return scene; }
备注2:这里是形成效果动态最关键的代码,将过期的粒子杀死,粒子系统则会发布新的粒子来凑足自己所规定的最大的粒子数,此处规定6秒钟为过期的时间,于是当到了第6秒的时候,第一个发射出来的粒子便被杀死了。
可以看到ParticleSystem类中更新的源码:
final int particlesToSpawnThisFrame = Math.min(this.mMaxParticles - this.mParticlesAlive, (int)FloatMath.floor(this.mParticlesDueToSpawn)); this.mParticlesDueToSpawn -= particlesToSpawnThisFrame; for(int i = 0; i < particlesToSpawnThisFrame; i++){ this.spawnParticle(); }mMaxParticles便是我们上面规定的最大的粒子数360,而mParticlesAlive则为屏幕上还存活的粒子的数量,这条代码就是得到粒子系统根据屏幕上的粒子存活的数量以及必须要达到多少数量来确定还需要发射多少数量,于是知道了自己还需要发射多少数量,便用了一个for循环来进行发射。
其中的更新的方法:
@Override protected void onManagedUpdate(final float pSecondsElapsed) { if(this.mParticlesSpawnEnabled) { this.spawnParticles(pSecondsElapsed); } final Particle[] particles = this.mParticles; final ArrayList<IParticleModifier> particleModifiers = this.mParticleModifiers; final int particleModifierCountMinusOne = this.mParticleModifierCount - 1; for(int i = this.mParticlesAlive - 1; i >= 0; i--) { final Particle particle = particles[i]; /* Apply all particleModifiers */ for(int j = particleModifierCountMinusOne; j >= 0; j--) { particleModifiers.get(j).onUpdateParticle(particle); } particle.onUpdate(pSecondsElapsed); if(particle.mDead){ this.mParticlesAlive--; final int particlesAlive = this.mParticlesAlive; particles[i] = particles[particlesAlive]; particles[particlesAlive] = particle; } } }可以看到,最后if判断,如果粒子已经被杀死,那么屏幕上存活的粒子数将会减少一个,并且重新赋值。我们杀死的语句便是在备注2处。上面写了当我们第6秒的时候,第一个发射出来的粒子便被杀死,那么屏幕上存活的数量便减少了一个,由于数量减少了一个,那么粒子系统发现数量没有达到自己所规定的最大的数量,于是便会又发射出粒子来满足自己最大的数量。这样杀掉,然后又产生,又杀掉,又产生,因此看起来便有了动态的感觉。
二,点粒子发射器,其原理跟上面是一样的,先看效果图:
1. 2.
3. 4.
看到效果是不是很炫呢,我们看看代码,跟上面的差不多:
onLoadResources()方法:
@Override public void onLoadResources() { this.mTexture = new Texture(32, 32, TextureOptions.BILINEAR_PREMULTIPLYALPHA); this.mParticleTextureRegion = TextureRegionFactory.createFromAsset(this.mTexture, this, "gfx/particle_fire.png", 0, 0); this.mEngine.getTextureManager().loadTexture(this.mTexture); }
public Scene onLoadScene() { this.mEngine.registerUpdateHandler(new FPSLogger()); final Scene scene = new Scene(1); scene.setBackground(new ColorBackground(0.0f, 0.0f, 0.0f)); /* Left to right Particle System. */ { final ParticleSystem particleSystem = new ParticleSystem(new PointParticleEmitter(0, CAMERA_HEIGHT), 6, 10, 200, this.mParticleTextureRegion); particleSystem.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE); particleSystem.addParticleInitializer(new VelocityInitializer(15, 22, -60, -90)); particleSystem.addParticleInitializer(new AccelerationInitializer(5, 15)); particleSystem.addParticleInitializer(new RotationInitializer(0.0f, 360.0f)); particleSystem.addParticleInitializer(new ColorInitializer(1.0f, 0.0f, 0.0f)); particleSystem.addParticleModifier(new ScaleModifier(0.5f, 2.0f, 0, 5)); particleSystem.addParticleModifier(new ExpireModifier(11.5f)); particleSystem.addParticleModifier(new AlphaModifier(1.0f, 0.0f, 2.5f, 3.5f)); particleSystem.addParticleModifier(new AlphaModifier(0.0f, 1.0f, 3.5f, 4.5f)); particleSystem.addParticleModifier(new ColorModifier(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 11.5f)); particleSystem.addParticleModifier(new AlphaModifier(1.0f, 0.0f, 4.5f, 11.5f)); scene.getTopLayer().addEntity(particleSystem); } /* Right to left Particle System. */ { final ParticleSystem particleSystem = new ParticleSystem(new PointParticleEmitter(CAMERA_WIDTH - 32, CAMERA_HEIGHT), 8, 12, 200, this.mParticleTextureRegion); particleSystem.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE); particleSystem.addParticleInitializer(new VelocityInitializer(-15, -22, -60, -90)); particleSystem.addParticleInitializer(new AccelerationInitializer(-5, 15)); particleSystem.addParticleInitializer(new RotationInitializer(0.0f, 360.0f)); particleSystem.addParticleInitializer(new ColorInitializer(0.0f, 0.0f, 1.0f)); particleSystem.addParticleModifier(new ScaleModifier(0.5f, 2.0f, 0, 5)); particleSystem.addParticleModifier(new ExpireModifier(11.5f)); particleSystem.addParticleModifier(new AlphaModifier(1.0f, 0.0f, 2.5f, 3.5f)); particleSystem.addParticleModifier(new AlphaModifier(0.0f, 1.0f, 3.5f, 4.5f)); particleSystem.addParticleModifier(new ColorModifier(0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 11.5f)); particleSystem.addParticleModifier(new AlphaModifier(1.0f, 0.0f, 4.5f, 11.5f)); scene.getTopLayer().addEntity(particleSystem); } return scene; }