先贴几个文档链接:
https://github.com/libgdx/libgdx/wiki/2d-particle-effects
https://github.com/libgdx/libgdx/wiki/2D-Particle-Editor
http://www.java-gaming.org/topics/particle-effects-in-libgdx/29484/view.html
先贴个官网GitHub上的测试代码,代码和资源都可以去下。这里不能传附件??
1 public class ParticleEmitterTest extends GdxTest { 2 private SpriteBatch spriteBatch; 3 ParticleEffect effect; 4 int emitterIndex; 5 Array<ParticleEmitter> emitters; 6 int particleCount = 10; 7 float fpsCounter; 8 InputProcessor inputProcessor; 9 10 @Override 11 public void create () { 12 spriteBatch = new SpriteBatch(); 13 14 effect = new ParticleEffect(); 15 effect.load(Gdx.files.internal("data/test.p"), Gdx.files.internal("data"));//第一个参数是粒子效果文件,第二个参数是图片basepath 16 effect.setPosition(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2); 17 // Of course, a ParticleEffect is normally just used, without messing around with its emitters. 18 emitters = new Array(effect.getEmitters());//原笔者把多个效果都放在一个文件里了,为了显示需要,这里特殊处理了,如果注释掉这三行,可以看出,几个效果一起显示了 19 effect.getEmitters().clear(); 20 effect.getEmitters().add(emitters.get(0)); 21 22 inputProcessor = new InputProcessor() { 23 public boolean touchUp (int x, int y, int pointer, int button) { 24 return false; 25 } 26 27 public boolean touchDragged (int x, int y, int pointer) { 28 effect.setPosition(x, Gdx.graphics.getHeight() - y); 29 return false; 30 } 31 32 public boolean touchDown (int x, int y, int pointer, int newParam) {//改变粒子的个数,重新显示 33 // effect.setPosition(x, Gdx.graphics.getHeight() - y); 34 ParticleEmitter emitter = emitters.get(emitterIndex); 35 particleCount += 100; 36 System.out.println(particleCount); 37 particleCount = Math.max(0, particleCount); 38 if (particleCount > emitter.getMaxParticleCount()) emitter.setMaxParticleCount(particleCount * 2); 39 emitter.getEmission().setHigh(particleCount / emitter.getLife().getHighMax() * 1000); 40 effect.getEmitters().clear(); 41 effect.getEmitters().add(emitter); 42 return false; 43 } 44 45 public boolean keyUp (int keycode) { 46 return false; 47 } 48 49 public boolean keyTyped (char character) { 50 return false; 51 } 52 53 public boolean keyDown (int keycode) { 54 ParticleEmitter emitter = emitters.get(emitterIndex); 55 if (keycode == Input.Keys.W)//我没找到原始的键,我改成W 56 particleCount += 5; 57 else if (keycode == Input.Keys.S)////我没找到原始的键,我改成S 58 particleCount -= 5; 59 else if (keycode == Input.Keys.SPACE) { 60 emitterIndex = (emitterIndex + 1) % emitters.size; 61 emitter = emitters.get(emitterIndex); 62 63 // if we've previously stopped the emitter reset it 64 if (emitter.isComplete()) emitter.reset(); 65 particleCount = (int)(emitter.getEmission().getHighMax() * emitter.getLife().getHighMax() / 1000f); 66 } else if (keycode == Input.Keys.ENTER) { 67 emitter = emitters.get(emitterIndex); 68 if (emitter.isComplete()) 69 emitter.reset(); 70 else 71 emitter.allowCompletion(); 72 } else 73 return false; 74 particleCount = Math.max(0, particleCount); 75 if (particleCount > emitter.getMaxParticleCount()) emitter.setMaxParticleCount(particleCount * 2); 76 emitter.getEmission().setHigh(particleCount / emitter.getLife().getHighMax() * 1000); 77 effect.getEmitters().clear(); 78 effect.getEmitters().add(emitter); 79 return false; 80 } 81 82 @Override 83 public boolean mouseMoved (int x, int y) { 84 return false; 85 } 86 87 @Override 88 public boolean scrolled (int amount) { 89 return false; 90 } 91 }; 92 93 Gdx.input.setInputProcessor(inputProcessor); 94 } 95 96 @Override 97 public void dispose () { 98 spriteBatch.dispose(); 99 effect.dispose();//注意 100 } 101 102 public void render () { 103 spriteBatch.getProjectionMatrix().setToOrtho2D(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); 104 float delta = Gdx.graphics.getDeltaTime(); 105 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); 106 spriteBatch.begin(); 107 effect.draw(spriteBatch, delta);//这里绘制粒子效果 108 spriteBatch.end(); 109 fpsCounter += delta; 110 if (fpsCounter > 3) { 111 fpsCounter = 0; 112 int activeCount = emitters.get(emitterIndex).getActiveCount(); 113 Gdx.app.log("libgdx", activeCount + "/" + particleCount + " particles, FPS: " + Gdx.graphics.getFramesPerSecond()); 114 } 115 } 116 117 public boolean needsGL20 () { 118 return false; 119 } 120 }
这只是测试代码,我们平时在使用的时候,几乎不这么用。
1. 大多数情况下我们都是用stage/actor结构的,不会在Screen里专门去draw粒子效果,或者说是很少情况下。
2. 效果文件在使用的时候大多数都是调好了的,不需要我们代码去调节那些参数。
3. ParticleEffectPool我还没看呢....
好,我们先在stage中尝试绘制一个粒子效果
其实只是自定义包装一个Actor类,在draw的时候,draw里面的effect就好了。
见代码:
1 public class ParticleEffectActor extends Actor { 2 ParticleEffect particleEffect; 3 Vector2 acc = new Vector2(); 4 private static final Logger LOGGER = new Logger(ParticleEffectActor.class.getName(), Application.LOG_DEBUG); 5 public ParticleEffectActor(ParticleEffect particleEffect) { 6 super(); 7 this.particleEffect = particleEffect; 8 } 9 10 @Override 11 public void draw(Batch batch, float parentAlpha) { 12 particleEffect.draw(batch); 13 //LOGGER.debug("draw"); 14 } 15 16 @Override 17 public void act(float delta) { 18 super.act(delta); 19 acc.set(getWidth() / 2, getHeight() / 2); 20 localToStageCoordinates(acc); 21 //LOGGER.debug(acc.toString()); 22 particleEffect.setPosition(acc.x, acc.y); 23 particleEffect.update(delta); 24 25 } 26 27 public void start(){ 28 particleEffect.start(); 29 } 30 }
1 public class ParticleTest extends ApplicationAdapter implements InputProcessor { 2 private Stage stage; 3 private ParticleEffect effect; 4 private static final Logger LOGGER = new Logger(ParticleTest.class.getName(),Application.LOG_DEBUG); 5 6 @Override 7 public void create () { 8 Gdx.app.setLogLevel(Application.LOG_DEBUG); 9 stage = new Stage(); 10 Gdx.input.setInputProcessor(this); 11 effect = new ParticleEffect(); 12 effect.load(Gdx.files.internal("data/abc.p"), Gdx.files.internal("data"));//第一个参数是粒子效果文件,第二个参数是图片basepath(这里应该有一个默认的particle.png别忘了) 13 14 } 15 16 @Override 17 public void render () { 18 Gdx.gl.glClearColor(0.2f, 0.2f, 0.2f, 1); 19 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); 20 stage.act(); 21 stage.draw(); 22 } 23 24 @Override 25 public void dispose() { 26 effect.dispose(); 27 stage.dispose(); 28 super.dispose(); 29 } 30 31 @Override 32 public void resize(int width, int height) { 33 stage.getViewport().update(width,height); 34 super.resize(width, height); 35 } 36 37 private void addEffect(){ 38 final ParticleEffectActor actor = new ParticleEffectActor(effect); 39 40 actor.setPosition(0,0); 41 42 MoveToAction action = Actions.moveTo(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), 4.0f); 43 44 RunnableAction run = Actions.run(new Runnable() { 45 @Override 46 public void run() { 47 stage.getActors().removeValue(actor, true); 48 } 49 }); 50 actor.addAction(Actions.sequence(action,run)); 51 actor.start(); 52 stage.addActor(actor); 53 } 54 55 @Override 56 public boolean keyDown(int keycode) { 57 if(keycode == Input.Keys.J){ 58 addEffect(); 59 } 60 return false; 61 } 62 63 @Override 64 public boolean keyUp(int keycode) { 65 return false; 66 } 67 68 @Override 69 public boolean keyTyped(char character) { 70 return false; 71 } 72 73 @Override 74 public boolean touchDown(int screenX, int screenY, int pointer, int button) { 75 return false; 76 } 77 78 @Override 79 public boolean touchUp(int screenX, int screenY, int pointer, int button) { 80 return false; 81 } 82 83 @Override 84 public boolean touchDragged(int screenX, int screenY, int pointer) { 85 return false; 86 } 87 88 @Override 89 public boolean mouseMoved(int screenX, int screenY) { 90 return false; 91 } 92 93 @Override 94 public boolean scrolled(int amount) { 95 return false; 96 } 97 }
以上代码中,我们在按下J键的时候,在stage中添加一个粒子效果actor,这个actor从左下角开始向右上角移动,4秒。
注意actor的start方法,官方粒子的素材不需要就可以显示,如果是粒子编辑器默认例子没改过,则需要这个。可能跟life什么的设置有关吧。
至于快速连续按下J键看到的情况,还有待研究,可能是共用同一个effect的缘故,particleEffect的update每个都调用了。
那倒不如把particleEffect直接放到actor中去构造,释放也放在里面,待研究吧。