+++ /dev/null
-/**\r
- * *****************************************************************************\r
- * Copyright 2011 See AUTHORS file.\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not\r
- * use this file except in compliance with the License. You may obtain a copy of\r
- * the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\r
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\r
- * License for the specific language governing permissions and limitations under\r
- * the License.\r
- * ****************************************************************************\r
- */\r
-package com.badlogic.gdx.graphics.g2d.particle;\r
-\r
-import java.io.*;\r
-import java.util.BitSet;\r
-\r
-import com.badlogic.gdx.graphics.GL10;\r
-import com.badlogic.gdx.graphics.Texture;\r
-import com.badlogic.gdx.graphics.g2d.Sprite;\r
-import com.badlogic.gdx.graphics.g2d.SpriteBatch;\r
-import com.badlogic.gdx.math.MathUtils;\r
-//TODO - Javadoc.\r
-//TODO - Add a duplicate emitter button.\r
-\r
-/**\r
- *\r
- * @author Daniel Heinrich <dannynullzwo@gmail.com>\r
- */\r
-public class ParticleEmitter implements Cloneable {\r
-\r
- private static class StandardParticleFactory implements ParticleFactory {\r
- @Override\r
- public Particle createParticle(Sprite sprite) {\r
- return new Particle(sprite);\r
- }\r
- }\r
- static private final int UPDATE_SCALE = 1 << 0;\r
- static private final int UPDATE_ANGLE = 1 << 1;\r
- static private final int UPDATE_ROTATION = 1 << 2;\r
- static private final int UPDATE_VELOCITY = 1 << 3;\r
- static private final int UPDATE_WIND = 1 << 4;\r
- static private final int UPDATE_GRAVITY = 1 << 5;\r
- static private final int UPDATE_TINT = 1 << 6;\r
- private RangedNumericValue delayValue = new RangedNumericValue();\r
- private ScaledNumericValue lifeOffsetValue = new ScaledNumericValue();\r
- private RangedNumericValue durationValue = new RangedNumericValue();\r
- private ScaledNumericValue lifeValue = new ScaledNumericValue();\r
- private ScaledNumericValue emissionValue = new ScaledNumericValue();\r
- private ScaledNumericValue scaleValue = new ScaledNumericValue();\r
- private ScaledNumericValue rotationValue = new ScaledNumericValue();\r
- private ScaledNumericValue velocityValue = new ScaledNumericValue();\r
- private ScaledNumericValue angleValue = new ScaledNumericValue();\r
- private ScaledNumericValue windValue = new ScaledNumericValue();\r
- private ScaledNumericValue gravityValue = new ScaledNumericValue();\r
- private ScaledNumericValue transparencyValue = new ScaledNumericValue();\r
- private GradientColorValue tintValue = new GradientColorValue();\r
- private RangedNumericValue xOffsetValue = new ScaledNumericValue();\r
- private RangedNumericValue yOffsetValue = new ScaledNumericValue();\r
- private ScaledNumericValue spawnWidthValue = new ScaledNumericValue();\r
- private ScaledNumericValue spawnHeightValue = new ScaledNumericValue();\r
- private SpawnShapeValue spawnShapeValue = new SpawnShapeValue();\r
- private float accumulator;\r
- private Sprite sprite;\r
- private Particle[] particles;\r
- private int minParticleCount, maxParticleCount = 4;\r
- private float x, y;\r
- private String name;\r
- private String imagePath;\r
- private BitSet active;\r
- private boolean firstUpdate;\r
- private boolean flipX, flipY;\r
- private int updateFlags;\r
- private boolean allowCompletion;\r
- private int emission, emissionDiff, emissionDelta;\r
- private int lifeOffset, lifeOffsetDiff;\r
- private int life, lifeDiff;\r
- private float spawnWidth, spawnWidthDiff;\r
- private float spawnHeight, spawnHeightDiff;\r
- public float duration = 1, durationTimer;\r
- private float delay, delayTimer;\r
- private boolean attached;\r
- private boolean continuous;\r
- private boolean aligned;\r
- private boolean behind;\r
- private boolean additive = true;\r
- \r
- private final ParticleFactory factory;\r
-\r
- public ParticleEmitter() {\r
- this(new StandardParticleFactory());\r
- }\r
-\r
- public ParticleEmitter(ParticleFactory factory) {\r
- this.factory = factory;\r
- initialize();\r
- }\r
-\r
- @Override\r
- protected ParticleEmitter clone() {\r
- ParticleEmitter n = new ParticleEmitter();\r
- n.sprite = sprite;\r
- n.name = name;\r
- n.setMaxParticleCount(maxParticleCount);\r
- n.minParticleCount = minParticleCount;\r
- n.delayValue.load(delayValue);\r
- n.durationValue.load(durationValue);\r
- n.emissionValue.load(emissionValue);\r
- n.lifeValue.load(lifeValue);\r
- n.lifeOffsetValue.load(lifeOffsetValue);\r
- n.scaleValue.load(scaleValue);\r
- n.rotationValue.load(rotationValue);\r
- n.velocityValue.load(velocityValue);\r
- n.angleValue.load(angleValue);\r
- n.windValue.load(windValue);\r
- n.gravityValue.load(gravityValue);\r
- n.transparencyValue.load(transparencyValue);\r
- n.tintValue.load(tintValue);\r
- return n;\r
- }\r
-\r
- private void initialize() {\r
- durationValue.setAlwaysActive(true);\r
- emissionValue.setAlwaysActive(true);\r
- lifeValue.setAlwaysActive(true);\r
- scaleValue.setAlwaysActive(true);\r
- transparencyValue.setAlwaysActive(true);\r
- spawnShapeValue.setAlwaysActive(true);\r
- spawnWidthValue.setAlwaysActive(true);\r
- spawnHeightValue.setAlwaysActive(true);\r
- }\r
-\r
- public void setMaxParticleCount(int maxParticleCount) {\r
- this.maxParticleCount = maxParticleCount;\r
- active = new BitSet(maxParticleCount);\r
- particles = new Particle[maxParticleCount];\r
- }\r
-\r
- private int addParticleAt(int ID) {\r
- int i = active.nextClearBit(ID);\r
- activateParticle(i);\r
- return i;\r
- }\r
-\r
- public void addParticles(int count) {\r
- int possibleCount = Math.min(count, maxParticleCount - getActiveCount());\r
- int last = 0;\r
- for (int i = 0; i < possibleCount; i++) {\r
- last = addParticleAt(last);\r
- }\r
- }\r
-\r
- public void addParticle() {\r
- addParticles(1);\r
- }\r
-\r
- public void update(float delta) {\r
- accumulator += Math.min(delta * 1000, 250);\r
- if (accumulator < 1) {\r
- return;\r
- }\r
- int deltaMillis = (int) accumulator;\r
- accumulator -= deltaMillis;\r
-\r
- for (int i = 0; i < maxParticleCount; i++) {\r
- if (active.get(i) && !updateParticle(particles[i], delta, deltaMillis)) {\r
- active.clear(i);\r
- }\r
- }\r
-\r
- if (delayTimer < delay) {\r
- delayTimer += deltaMillis;\r
- return;\r
- }\r
-\r
- if (firstUpdate) {\r
- firstUpdate = false;\r
- addParticle();\r
- }\r
-\r
- if (durationTimer < duration) {\r
- durationTimer += deltaMillis;\r
- } else {\r
- if (!continuous || allowCompletion) {\r
- return;\r
- }\r
- restart();\r
- }\r
-\r
- emissionDelta += deltaMillis;\r
- float emissionTime = emission + emissionDiff * emissionValue.getScale(durationTimer / (float) duration);\r
- if (emissionTime > 0) {\r
- emissionTime = 1000 / emissionTime;\r
- if (emissionDelta >= emissionTime) {\r
- int emitCount = (int) (emissionDelta / emissionTime);\r
- emitCount = Math.min(emitCount, maxParticleCount - getActiveCount());\r
- emissionDelta -= emitCount * emissionTime;\r
- emissionDelta %= emissionTime;\r
- addParticles(emitCount);\r
- }\r
- }\r
-\r
- int ac = getActiveCount();\r
- if (ac < minParticleCount) {\r
- addParticles(minParticleCount - ac);\r
- }\r
- }\r
-\r
- public void draw(SpriteBatch spriteBatch) {\r
- if (additive) {\r
- spriteBatch.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE);\r
- }\r
-\r
- for (int i = 0, n = maxParticleCount; i < n; i++) {\r
- if (active.get(i)) {\r
- particles[i].draw(spriteBatch);\r
- }\r
- }\r
-\r
- if (additive) {\r
- spriteBatch.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);\r
- }\r
- }\r
-\r
- /**\r
- * Updates and draws the particles. This is slightly more efficient than\r
- * calling {@link #update(float)} and {@link #draw(SpriteBatch)} separately.\r
- */\r
- public void draw(SpriteBatch spriteBatch, float delta) {\r
- accumulator += Math.min(delta * 1000, 250);\r
- if (accumulator < 1) {\r
- draw(spriteBatch);\r
- return;\r
- }\r
- int deltaMillis = (int) accumulator;\r
- accumulator -= deltaMillis;\r
-\r
- if (additive) {\r
- spriteBatch.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE);\r
- }\r
-\r
- for (int i = 0, n = maxParticleCount; i < n; i++) {\r
- if (active.get(i)) {\r
- Particle particle = particles[i];\r
- if (updateParticle(particle, delta, deltaMillis)) {\r
- particle.draw(spriteBatch);\r
- } else {\r
- active.clear(i);\r
- }\r
- }\r
- }\r
-\r
- if (additive) {\r
- spriteBatch.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);\r
- }\r
-\r
- if (delayTimer < delay) {\r
- delayTimer += deltaMillis;\r
- return;\r
- }\r
-\r
- if (firstUpdate) {\r
- firstUpdate = false;\r
- addParticle();\r
- }\r
-\r
- if (durationTimer < duration) {\r
- durationTimer += deltaMillis;\r
- } else {\r
- if (!continuous || allowCompletion) {\r
- return;\r
- }\r
- restart();\r
- }\r
-\r
- emissionDelta += deltaMillis;\r
- float emissionTime = emission + emissionDiff * emissionValue.getScale(durationTimer / (float) duration);\r
- if (emissionTime > 0) {\r
- emissionTime = 1000 / emissionTime;\r
- if (emissionDelta >= emissionTime) {\r
- int emitCount = (int) (emissionDelta / emissionTime);\r
- emitCount = Math.min(emitCount, maxParticleCount - getActiveCount());\r
- emissionDelta -= emitCount * emissionTime;\r
- emissionDelta %= emissionTime;\r
- addParticles(emitCount);\r
- }\r
- }\r
- if (getActiveCount() < minParticleCount) {\r
- addParticles(minParticleCount - getActiveCount());\r
- }\r
- }\r
-\r
- public void start() {\r
- firstUpdate = true;\r
- allowCompletion = false;\r
- restart();\r
- }\r
-\r
- public void reset() {\r
- emissionDelta = 0;\r
- durationTimer = 0;\r
- start();\r
- }\r
-\r
- private void restart() {\r
- delay = delayValue.active ? delayValue.newLowValue() : 0;\r
- delayTimer = 0;\r
-\r
- durationTimer -= duration;\r
- duration = durationValue.newLowValue();\r
-\r
- emission = (int) emissionValue.newLowValue();\r
- emissionDiff = (int) emissionValue.newHighValue();\r
- if (!emissionValue.isRelative()) {\r
- emissionDiff -= emission;\r
- }\r
-\r
- life = (int) lifeValue.newLowValue();\r
- lifeDiff = (int) lifeValue.newHighValue();\r
- if (!lifeValue.isRelative()) {\r
- lifeDiff -= life;\r
- }\r
-\r
- lifeOffset = lifeOffsetValue.active ? (int) lifeOffsetValue.newLowValue() : 0;\r
- lifeOffsetDiff = (int) lifeOffsetValue.newHighValue();\r
- if (!lifeOffsetValue.isRelative()) {\r
- lifeOffsetDiff -= lifeOffset;\r
- }\r
-\r
- spawnWidth = spawnWidthValue.newLowValue();\r
- spawnWidthDiff = spawnWidthValue.newHighValue();\r
- if (!spawnWidthValue.isRelative()) {\r
- spawnWidthDiff -= spawnWidth;\r
- }\r
-\r
- spawnHeight = spawnHeightValue.newLowValue();\r
- spawnHeightDiff = spawnHeightValue.newHighValue();\r
- if (!spawnHeightValue.isRelative()) {\r
- spawnHeightDiff -= spawnHeight;\r
- }\r
-\r
- updateFlags = 0;\r
- if (angleValue.active && angleValue.timeline.length > 1) {\r
- updateFlags |= UPDATE_ANGLE;\r
- }\r
- if (velocityValue.active && velocityValue.active) {\r
- updateFlags |= UPDATE_VELOCITY;\r
- }\r
- if (scaleValue.timeline.length > 1) {\r
- updateFlags |= UPDATE_SCALE;\r
- }\r
- if (rotationValue.active && rotationValue.timeline.length > 1) {\r
- updateFlags |= UPDATE_ROTATION;\r
- }\r
- if (windValue.active) {\r
- updateFlags |= UPDATE_WIND;\r
- }\r
- if (gravityValue.active) {\r
- updateFlags |= UPDATE_GRAVITY;\r
- }\r
- if (tintValue.timeline.length > 1) {\r
- updateFlags |= UPDATE_TINT;\r
- }\r
- }\r
-\r
- private void activateParticle(int index) {\r
- Particle particle = particles[index];\r
- if (particle == null) {\r
- particles[index] = particle = factory.createParticle(sprite);\r
- particle.flip(flipX, flipY);\r
- }\r
-\r
- float percent = durationTimer / (float) duration;\r
- int updateFlags = this.updateFlags;\r
-\r
- particle.currentLife = particle.life = life + (int) (lifeDiff * lifeValue.getScale(percent));\r
-\r
- if (velocityValue.active) {\r
- particle.velocity = velocityValue.newLowValue();\r
- particle.velocityDiff = velocityValue.newHighValue();\r
- if (!velocityValue.isRelative()) {\r
- particle.velocityDiff -= particle.velocity;\r
- }\r
- }\r
-\r
- particle.angle = angleValue.newLowValue();\r
- particle.angleDiff = angleValue.newHighValue();\r
- if (!angleValue.isRelative()) {\r
- particle.angleDiff -= particle.angle;\r
- }\r
- float angle = 0;\r
- if ((updateFlags & UPDATE_ANGLE) == 0) {\r
- angle = particle.angle + particle.angleDiff * angleValue.getScale(0);\r
- particle.angle = angle;\r
- particle.angleCos = MathUtils.cosDeg(angle);\r
- particle.angleSin = MathUtils.sinDeg(angle);\r
- }\r
-\r
- float spriteWidth = sprite.getWidth();\r
- particle.scale = scaleValue.newLowValue() / spriteWidth;\r
- particle.scaleDiff = scaleValue.newHighValue() / spriteWidth;\r
- if (!scaleValue.isRelative()) {\r
- particle.scaleDiff -= particle.scale;\r
- }\r
- particle.setScale(particle.scale + particle.scaleDiff * scaleValue.getScale(0));\r
-\r
- if (rotationValue.active) {\r
- particle.rotation = rotationValue.newLowValue();\r
- particle.rotationDiff = rotationValue.newHighValue();\r
- if (!rotationValue.isRelative()) {\r
- particle.rotationDiff -= particle.rotation;\r
- }\r
- float rotation = particle.rotation + particle.rotationDiff * rotationValue.getScale(0);\r
- if (aligned) {\r
- rotation += angle;\r
- }\r
- particle.setRotation(rotation);\r
- }\r
-\r
- if (windValue.active) {\r
- particle.wind = windValue.newLowValue();\r
- particle.windDiff = windValue.newHighValue();\r
- if (!windValue.isRelative()) {\r
- particle.windDiff -= particle.wind;\r
- }\r
- }\r
-\r
- if (gravityValue.active) {\r
- particle.gravity = gravityValue.newLowValue();\r
- particle.gravityDiff = gravityValue.newHighValue();\r
- if (!gravityValue.isRelative()) {\r
- particle.gravityDiff -= particle.gravity;\r
- }\r
- }\r
-\r
- float[] color = particle.tint;\r
- if (color == null) {\r
- particle.tint = color = new float[3];\r
- }\r
- float[] temp = tintValue.getColor(0);\r
- color[0] = temp[0];\r
- color[1] = temp[1];\r
- color[2] = temp[2];\r
-\r
- particle.transparency = transparencyValue.newLowValue();\r
- particle.transparencyDiff = transparencyValue.newHighValue() - particle.transparency;\r
-\r
- // Spawn.\r
- float x = this.x;\r
- if (xOffsetValue.active) {\r
- x += xOffsetValue.newLowValue();\r
- }\r
- float y = this.y;\r
- if (yOffsetValue.active) {\r
- y += yOffsetValue.newLowValue();\r
- }\r
- switch (spawnShapeValue.shape) {\r
- case square: {\r
- float width = spawnWidth + (spawnWidthDiff * spawnWidthValue.getScale(percent));\r
- float height = spawnHeight + (spawnHeightDiff * spawnHeightValue.getScale(percent));\r
- x += MathUtils.random(width) - width / 2;\r
- y += MathUtils.random(height) - height / 2;\r
- break;\r
- }\r
- case ellipse: {\r
- float width = spawnWidth + (spawnWidthDiff * spawnWidthValue.getScale(percent));\r
- float height = spawnHeight + (spawnHeightDiff * spawnHeightValue.getScale(percent));\r
- float radiusX = width / 2;\r
- float radiusY = height / 2;\r
- if (radiusX == 0 || radiusY == 0) {\r
- break;\r
- }\r
- float scaleY = radiusX / (float) radiusY;\r
- if (spawnShapeValue.edges) {\r
- float spawnAngle;\r
- switch (spawnShapeValue.side) {\r
- case top:\r
- spawnAngle = -MathUtils.random(179f);\r
- break;\r
- case bottom:\r
- spawnAngle = MathUtils.random(179f);\r
- break;\r
- default:\r
- spawnAngle = MathUtils.random(360f);\r
- break;\r
- }\r
- float cosDeg = MathUtils.cosDeg(spawnAngle);\r
- float sinDeg = MathUtils.sinDeg(spawnAngle);\r
- x += cosDeg * radiusX;\r
- y += sinDeg * radiusX / scaleY;\r
- if ((updateFlags & UPDATE_ANGLE) == 0) {\r
- particle.angle = spawnAngle;\r
- particle.angleCos = cosDeg;\r
- particle.angleSin = sinDeg;\r
- }\r
- } else {\r
- float radius2 = radiusX * radiusX;\r
- while (true) {\r
- float px = MathUtils.random(width) - radiusX;\r
- float py = MathUtils.random(width) - radiusX;\r
- if (px * px + py * py <= radius2) {\r
- x += px;\r
- y += py / scaleY;\r
- break;\r
- }\r
- }\r
- }\r
- break;\r
- }\r
- case line: {\r
- float width = spawnWidth + (spawnWidthDiff * spawnWidthValue.getScale(percent));\r
- float height = spawnHeight + (spawnHeightDiff * spawnHeightValue.getScale(percent));\r
- if (width != 0) {\r
- float lineX = width * MathUtils.random();\r
- x += lineX;\r
- y += lineX * (height / (float) width);\r
- } else {\r
- y += height * MathUtils.random();\r
- }\r
- break;\r
- }\r
- }\r
-\r
- float spriteHeight = sprite.getHeight();\r
- particle.setBounds(x - spriteWidth / 2, y - spriteHeight / 2, spriteWidth, spriteHeight);\r
-\r
- int offsetTime = (int) (lifeOffset + lifeOffsetDiff * lifeOffsetValue.getScale(percent));\r
- if (offsetTime > 0) {\r
- if (offsetTime >= particle.currentLife) {\r
- offsetTime = particle.currentLife - 1;\r
- }\r
- updateParticle(particle, offsetTime / 1000f, offsetTime);\r
- }\r
-\r
- active.set(index);\r
- }\r
-\r
- private boolean updateParticle(Particle particle, float delta, int deltaMillis) {\r
- int life = particle.currentLife - deltaMillis;\r
- if (life <= 0) {\r
- return false;\r
- }\r
- particle.currentLife = life;\r
-\r
- float percent = 1 - particle.currentLife / (float) particle.life;\r
- int updateFlags = this.updateFlags;\r
-\r
- if ((updateFlags & UPDATE_SCALE) != 0) {\r
- particle.setScale(particle.scale + particle.scaleDiff * scaleValue.getScale(percent));\r
- }\r
-\r
- if ((updateFlags & UPDATE_VELOCITY) != 0) {\r
- float velocity = (particle.velocity + particle.velocityDiff * velocityValue.getScale(percent)) * delta;\r
-\r
- float velocityX, velocityY;\r
- if ((updateFlags & UPDATE_ANGLE) != 0) {\r
- float angle = particle.angle + particle.angleDiff * angleValue.getScale(percent);\r
- velocityX = velocity * MathUtils.cosDeg(angle);\r
- velocityY = velocity * MathUtils.sinDeg(angle);\r
- if ((updateFlags & UPDATE_ROTATION) != 0) {\r
- float rotation = particle.rotation + particle.rotationDiff * rotationValue.getScale(percent);\r
- if (aligned) {\r
- rotation += angle;\r
- }\r
- particle.setRotation(rotation);\r
- }\r
- } else {\r
- velocityX = velocity * particle.angleCos;\r
- velocityY = velocity * particle.angleSin;\r
- if (aligned || (updateFlags & UPDATE_ROTATION) != 0) {\r
- float rotation = particle.rotation + particle.rotationDiff * rotationValue.getScale(percent);\r
- if (aligned) {\r
- rotation += particle.angle;\r
- }\r
- particle.setRotation(rotation);\r
- }\r
- }\r
-\r
- if ((updateFlags & UPDATE_WIND) != 0) {\r
- velocityX += (particle.wind + particle.windDiff * windValue.getScale(percent)) * delta;\r
- }\r
-\r
- if ((updateFlags & UPDATE_GRAVITY) != 0) {\r
- velocityY += (particle.gravity + particle.gravityDiff * gravityValue.getScale(percent)) * delta;\r
- }\r
-\r
- particle.translate(velocityX, velocityY);\r
- } else {\r
- if ((updateFlags & UPDATE_ROTATION) != 0) {\r
- particle.setRotation(particle.rotation + particle.rotationDiff * rotationValue.getScale(percent));\r
- }\r
- }\r
-\r
- float[] color;\r
- if ((updateFlags & UPDATE_TINT) != 0) {\r
- color = tintValue.getColor(percent);\r
- } else {\r
- color = particle.tint;\r
- }\r
- particle.setColor(color[0], color[1], color[2],\r
- particle.transparency + particle.transparencyDiff * transparencyValue.getScale(percent));\r
-\r
- return true;\r
- }\r
-\r
- public void setPosition(float x, float y) {\r
- if (attached) {\r
- float xAmount = x - this.x;\r
- float yAmount = y - this.y;\r
- for (int i = 0; i < maxParticleCount; i++) {\r
- if (active.get(i)) {\r
- particles[i].translate(xAmount, yAmount);\r
- }\r
- }\r
- }\r
- this.x = x;\r
- this.y = y;\r
- }\r
-\r
- public void setSprite(Sprite sprite) {\r
- this.sprite = sprite;\r
- if (sprite == null) {\r
- return;\r
- }\r
- float originX = sprite.getOriginX();\r
- float originY = sprite.getOriginY();\r
- Texture texture = sprite.getTexture();\r
- for (int i = 0, n = particles.length; i < n; i++) {\r
- Particle particle = particles[i];\r
- if (particle == null) {\r
- break;\r
- }\r
- particle.setTexture(texture);\r
- particle.setOrigin(originX, originY);\r
- }\r
- }\r
-\r
- /**\r
- * Ignores the {@link #setContinuous(boolean) continuous} setting until the\r
- * emitter is started again. This allows the emitter to stop smoothly.\r
- */\r
- public void allowCompletion() {\r
- allowCompletion = true;\r
- durationTimer = duration;\r
- }\r
-\r
- public Sprite getSprite() {\r
- return sprite;\r
- }\r
-\r
- public String getName() {\r
- return name;\r
- }\r
-\r
- public void setName(String name) {\r
- this.name = name;\r
- }\r
-\r
- public ScaledNumericValue getLife() {\r
- return lifeValue;\r
- }\r
-\r
- public ScaledNumericValue getScale() {\r
- return scaleValue;\r
- }\r
-\r
- public ScaledNumericValue getRotation() {\r
- return rotationValue;\r
- }\r
-\r
- public GradientColorValue getTint() {\r
- return tintValue;\r
- }\r
-\r
- public ScaledNumericValue getVelocity() {\r
- return velocityValue;\r
- }\r
-\r
- public ScaledNumericValue getWind() {\r
- return windValue;\r
- }\r
-\r
- public ScaledNumericValue getGravity() {\r
- return gravityValue;\r
- }\r
-\r
- public ScaledNumericValue getAngle() {\r
- return angleValue;\r
- }\r
-\r
- public ScaledNumericValue getEmission() {\r
- return emissionValue;\r
- }\r
-\r
- public ScaledNumericValue getTransparency() {\r
- return transparencyValue;\r
- }\r
-\r
- public RangedNumericValue getDuration() {\r
- return durationValue;\r
- }\r
-\r
- public RangedNumericValue getDelay() {\r
- return delayValue;\r
- }\r
-\r
- public ScaledNumericValue getLifeOffset() {\r
- return lifeOffsetValue;\r
- }\r
-\r
- public RangedNumericValue getXOffsetValue() {\r
- return xOffsetValue;\r
- }\r
-\r
- public RangedNumericValue getYOffsetValue() {\r
- return yOffsetValue;\r
- }\r
-\r
- public ScaledNumericValue getSpawnWidth() {\r
- return spawnWidthValue;\r
- }\r
-\r
- public ScaledNumericValue getSpawnHeight() {\r
- return spawnHeightValue;\r
- }\r
-\r
- public SpawnShapeValue getSpawnShape() {\r
- return spawnShapeValue;\r
- }\r
-\r
- public boolean isAttached() {\r
- return attached;\r
- }\r
-\r
- public void setAttached(boolean attached) {\r
- this.attached = attached;\r
- }\r
-\r
- public boolean isContinuous() {\r
- return continuous;\r
- }\r
-\r
- public void setContinuous(boolean continuous) {\r
- this.continuous = continuous;\r
- }\r
-\r
- public boolean isAligned() {\r
- return aligned;\r
- }\r
-\r
- public void setAligned(boolean aligned) {\r
- this.aligned = aligned;\r
- }\r
-\r
- public boolean isAdditive() {\r
- return additive;\r
- }\r
-\r
- public void setAdditive(boolean additive) {\r
- this.additive = additive;\r
- }\r
-\r
- public boolean isBehind() {\r
- return behind;\r
- }\r
-\r
- public void setBehind(boolean behind) {\r
- this.behind = behind;\r
- }\r
-\r
- public int getMinParticleCount() {\r
- return minParticleCount;\r
- }\r
-\r
- public void setMinParticleCount(int minParticleCount) {\r
- this.minParticleCount = minParticleCount;\r
- }\r
-\r
- public int getMaxParticleCount() {\r
- return maxParticleCount;\r
- }\r
-\r
- public boolean isComplete() {\r
- if (delayTimer < delay) {\r
- return false;\r
- }\r
- return durationTimer >= duration && getActiveCount() == 0;\r
- }\r
-\r
- public float getPercentComplete() {\r
- if (delayTimer < delay) {\r
- return 0;\r
- }\r
- return Math.min(1, durationTimer / (float) duration);\r
- }\r
-\r
- public float getX() {\r
- return x;\r
- }\r
-\r
- public float getY() {\r
- return y;\r
- }\r
-\r
- public int getActiveCount() {\r
- return active.cardinality();\r
- }\r
-\r
- public String getImagePath() {\r
- return imagePath;\r
- }\r
-\r
- public void setImagePath(String imagePath) {\r
- this.imagePath = imagePath;\r
- }\r
-\r
- public void setFlip(boolean flipX, boolean flipY) {\r
- this.flipX = flipX;\r
- this.flipY = flipY;\r
- if (particles == null) {\r
- return;\r
- }\r
- for (int i = 0, n = particles.length; i < n; i++) {\r
- Particle particle = particles[i];\r
- if (particle != null) {\r
- particle.flip(flipX, flipY);\r
- }\r
- }\r
- }\r
-\r
- public void save(Writer output) throws IOException {\r
- output.write(name + "\n");\r
- output.write("- Delay -\n");\r
- delayValue.save(output);\r
- output.write("- Duration - \n");\r
- durationValue.save(output);\r
- output.write("- Count - \n");\r
- output.write("min: " + minParticleCount + "\n");\r
- output.write("max: " + maxParticleCount + "\n");\r
- output.write("- Emission - \n");\r
- emissionValue.save(output);\r
- output.write("- Life - \n");\r
- lifeValue.save(output);\r
- output.write("- Life Offset - \n");\r
- lifeOffsetValue.save(output);\r
- output.write("- X Offset - \n");\r
- xOffsetValue.save(output);\r
- output.write("- Y Offset - \n");\r
- yOffsetValue.save(output);\r
- output.write("- Spawn Shape - \n");\r
- spawnShapeValue.save(output);\r
- output.write("- Spawn Width - \n");\r
- spawnWidthValue.save(output);\r
- output.write("- Spawn Height - \n");\r
- spawnHeightValue.save(output);\r
- output.write("- Scale - \n");\r
- scaleValue.save(output);\r
- output.write("- Velocity - \n");\r
- velocityValue.save(output);\r
- output.write("- Angle - \n");\r
- angleValue.save(output);\r
- output.write("- Rotation - \n");\r
- rotationValue.save(output);\r
- output.write("- Wind - \n");\r
- windValue.save(output);\r
- output.write("- Gravity - \n");\r
- gravityValue.save(output);\r
- output.write("- Tint - \n");\r
- tintValue.save(output);\r
- output.write("- Transparency - \n");\r
- transparencyValue.save(output);\r
- output.write("- Options - \n");\r
- output.write("attached: " + attached + "\n");\r
- output.write("continuous: " + continuous + "\n");\r
- output.write("aligned: " + aligned + "\n");\r
- output.write("additive: " + additive + "\n");\r
- output.write("behind: " + behind + "\n");\r
- }\r
-\r
- public void load(BufferedReader reader) throws IOException {\r
- try {\r
- name = readString(reader, "name");\r
- reader.readLine();\r
- delayValue.load(reader);\r
- reader.readLine();\r
- durationValue.load(reader);\r
- reader.readLine();\r
- setMinParticleCount(readInt(reader, "minParticleCount"));\r
- setMaxParticleCount(readInt(reader, "maxParticleCount"));\r
- reader.readLine();\r
- emissionValue.load(reader);\r
- reader.readLine();\r
- lifeValue.load(reader);\r
- reader.readLine();\r
- lifeOffsetValue.load(reader);\r
- reader.readLine();\r
- xOffsetValue.load(reader);\r
- reader.readLine();\r
- yOffsetValue.load(reader);\r
- reader.readLine();\r
- spawnShapeValue.load(reader);\r
- reader.readLine();\r
- spawnWidthValue.load(reader);\r
- reader.readLine();\r
- spawnHeightValue.load(reader);\r
- reader.readLine();\r
- scaleValue.load(reader);\r
- reader.readLine();\r
- velocityValue.load(reader);\r
- reader.readLine();\r
- angleValue.load(reader);\r
- reader.readLine();\r
- rotationValue.load(reader);\r
- reader.readLine();\r
- windValue.load(reader);\r
- reader.readLine();\r
- gravityValue.load(reader);\r
- reader.readLine();\r
- tintValue.load(reader);\r
- reader.readLine();\r
- transparencyValue.load(reader);\r
- reader.readLine();\r
- attached = readBoolean(reader, "attached");\r
- continuous = readBoolean(reader, "continuous");\r
- aligned = readBoolean(reader, "aligned");\r
- additive = readBoolean(reader, "additive");\r
- behind = readBoolean(reader, "behind");\r
- } catch (RuntimeException ex) {\r
- if (name == null) {\r
- throw ex;\r
- }\r
- throw new RuntimeException("Error parsing emitter: " + name, ex);\r
- }\r
- }\r
-\r
- static String readString(BufferedReader reader, String name) throws IOException {\r
- String line = reader.readLine();\r
- if (line == null) {\r
- throw new IOException("Missing value: " + name);\r
- }\r
- return line.substring(line.indexOf(":") + 1).trim();\r
- }\r
-\r
- static boolean readBoolean(BufferedReader reader, String name) throws IOException {\r
- return Boolean.parseBoolean(readString(reader, name));\r
- }\r
-\r
- static int readInt(BufferedReader reader, String name) throws IOException {\r
- return Integer.parseInt(readString(reader, name));\r
- }\r
-\r
- static float readFloat(BufferedReader reader, String name) throws IOException {\r
- return Float.parseFloat(readString(reader, name));\r
- }\r
-\r
- public static class ParticleValue {\r
-\r
- boolean active;\r
- boolean alwaysActive;\r
-\r
- public void setAlwaysActive(boolean alwaysActive) {\r
- this.alwaysActive = alwaysActive;\r
- }\r
-\r
- public boolean isAlwaysActive() {\r
- return alwaysActive;\r
- }\r
-\r
- public boolean isActive() {\r
- return alwaysActive || active;\r
- }\r
-\r
- public void setActive(boolean active) {\r
- this.active = active;\r
- }\r
-\r
- public void save(Writer output) throws IOException {\r
- if (!alwaysActive) {\r
- output.write("active: " + active + "\n");\r
- } else {\r
- active = true;\r
- }\r
- }\r
-\r
- public void load(BufferedReader reader) throws IOException {\r
- if (!alwaysActive) {\r
- active = readBoolean(reader, "active");\r
- } else {\r
- active = true;\r
- }\r
- }\r
-\r
- public void load(ParticleValue value) {\r
- active = value.active;\r
- alwaysActive = value.alwaysActive;\r
- }\r
- }\r
-\r
- static public class NumericValue extends ParticleValue {\r
-\r
- private float value;\r
-\r
- public float getValue() {\r
- return value;\r
- }\r
-\r
- public void setValue(float value) {\r
- this.value = value;\r
- }\r
-\r
- public void save(Writer output) throws IOException {\r
- super.save(output);\r
- if (!active) {\r
- return;\r
- }\r
- output.write("value: " + value + "\n");\r
- }\r
-\r
- public void load(BufferedReader reader) throws IOException {\r
- super.load(reader);\r
- if (!active) {\r
- return;\r
- }\r
- value = readFloat(reader, "value");\r
- }\r
-\r
- public void load(NumericValue value) {\r
- super.load(value);\r
- this.value = value.value;\r
- }\r
- }\r
-\r
- static public class RangedNumericValue extends ParticleValue {\r
-\r
- private float lowMin, lowMax;\r
-\r
- public float newLowValue() {\r
- return lowMin + (lowMax - lowMin) * MathUtils.random();\r
- }\r
-\r
- public void setLow(float value) {\r
- lowMin = value;\r
- lowMax = value;\r
- }\r
-\r
- public void setLow(float min, float max) {\r
- lowMin = min;\r
- lowMax = max;\r
- }\r
-\r
- public float getLowMin() {\r
- return lowMin;\r
- }\r
-\r
- public void setLowMin(float lowMin) {\r
- this.lowMin = lowMin;\r
- }\r
-\r
- public float getLowMax() {\r
- return lowMax;\r
- }\r
-\r
- public void setLowMax(float lowMax) {\r
- this.lowMax = lowMax;\r
- }\r
-\r
- public void save(Writer output) throws IOException {\r
- super.save(output);\r
- if (!active) {\r
- return;\r
- }\r
- output.write("lowMin: " + lowMin + "\n");\r
- output.write("lowMax: " + lowMax + "\n");\r
- }\r
-\r
- public void load(BufferedReader reader) throws IOException {\r
- super.load(reader);\r
- if (!active) {\r
- return;\r
- }\r
- lowMin = readFloat(reader, "lowMin");\r
- lowMax = readFloat(reader, "lowMax");\r
- }\r
-\r
- public void load(RangedNumericValue value) {\r
- super.load(value);\r
- lowMax = value.lowMax;\r
- lowMin = value.lowMin;\r
- }\r
- }\r
-\r
- static public class ScaledNumericValue extends RangedNumericValue {\r
-\r
- private float[] scaling = {1};\r
- float[] timeline = {0};\r
- private float highMin, highMax;\r
- private boolean relative;\r
-\r
- public float newHighValue() {\r
- return highMin + (highMax - highMin) * MathUtils.random();\r
- }\r
-\r
- public void setHigh(float value) {\r
- highMin = value;\r
- highMax = value;\r
- }\r
-\r
- public void setHigh(float min, float max) {\r
- highMin = min;\r
- highMax = max;\r
- }\r
-\r
- public float getHighMin() {\r
- return highMin;\r
- }\r
-\r
- public void setHighMin(float highMin) {\r
- this.highMin = highMin;\r
- }\r
-\r
- public float getHighMax() {\r
- return highMax;\r
- }\r
-\r
- public void setHighMax(float highMax) {\r
- this.highMax = highMax;\r
- }\r
-\r
- public float[] getScaling() {\r
- return scaling;\r
- }\r
-\r
- public void setScaling(float[] values) {\r
- this.scaling = values;\r
- }\r
-\r
- public float[] getTimeline() {\r
- return timeline;\r
- }\r
-\r
- public void setTimeline(float[] timeline) {\r
- this.timeline = timeline;\r
- }\r
-\r
- public boolean isRelative() {\r
- return relative;\r
- }\r
-\r
- public void setRelative(boolean relative) {\r
- this.relative = relative;\r
- }\r
-\r
- public float getScale(float percent) {\r
- int endIndex = -1;\r
- float[] timeline = this.timeline;\r
- int n = timeline.length;\r
- for (int i = 1; i < n; i++) {\r
- float t = timeline[i];\r
- if (t > percent) {\r
- endIndex = i;\r
- break;\r
- }\r
- }\r
- if (endIndex == -1) {\r
- return scaling[n - 1];\r
- }\r
- float[] scaling = this.scaling;\r
- int startIndex = endIndex - 1;\r
- float startValue = scaling[startIndex];\r
- float startTime = timeline[startIndex];\r
- return startValue + (scaling[endIndex] - startValue) * ((percent - startTime) / (timeline[endIndex] - startTime));\r
- }\r
-\r
- public void save(Writer output) throws IOException {\r
- super.save(output);\r
- if (!active) {\r
- return;\r
- }\r
- output.write("highMin: " + highMin + "\n");\r
- output.write("highMax: " + highMax + "\n");\r
- output.write("relative: " + relative + "\n");\r
- output.write("scalingCount: " + scaling.length + "\n");\r
- for (int i = 0; i < scaling.length; i++) {\r
- output.write("scaling" + i + ": " + scaling[i] + "\n");\r
- }\r
- output.write("timelineCount: " + timeline.length + "\n");\r
- for (int i = 0; i < timeline.length; i++) {\r
- output.write("timeline" + i + ": " + timeline[i] + "\n");\r
- }\r
- }\r
-\r
- public void load(BufferedReader reader) throws IOException {\r
- super.load(reader);\r
- if (!active) {\r
- return;\r
- }\r
- highMin = readFloat(reader, "highMin");\r
- highMax = readFloat(reader, "highMax");\r
- relative = readBoolean(reader, "relative");\r
- scaling = new float[readInt(reader, "scalingCount")];\r
- for (int i = 0; i < scaling.length; i++) {\r
- scaling[i] = readFloat(reader, "scaling" + i);\r
- }\r
- timeline = new float[readInt(reader, "timelineCount")];\r
- for (int i = 0; i < timeline.length; i++) {\r
- timeline[i] = readFloat(reader, "timeline" + i);\r
- }\r
- }\r
-\r
- public void load(ScaledNumericValue value) {\r
- super.load(value);\r
- highMax = value.highMax;\r
- highMin = value.highMin;\r
- scaling = new float[value.scaling.length];\r
- System.arraycopy(value.scaling, 0, scaling, 0, scaling.length);\r
- timeline = new float[value.timeline.length];\r
- System.arraycopy(value.timeline, 0, timeline, 0, timeline.length);\r
- relative = value.relative;\r
- }\r
- }\r
-\r
- static public class GradientColorValue extends ParticleValue {\r
-\r
- static private float[] temp = new float[4];\r
- private float[] colors = {1, 1, 1};\r
- float[] timeline = {0};\r
-\r
- public GradientColorValue() {\r
- alwaysActive = true;\r
- }\r
-\r
- public float[] getTimeline() {\r
- return timeline;\r
- }\r
-\r
- public void setTimeline(float[] timeline) {\r
- this.timeline = timeline;\r
- }\r
-\r
- public float[] getColors() {\r
- return colors;\r
- }\r
-\r
- public void setColors(float[] colors) {\r
- this.colors = colors;\r
- }\r
-\r
- public float[] getColor(float percent) {\r
- int startIndex = 0, endIndex = -1;\r
- float[] timeline = this.timeline;\r
- int n = timeline.length;\r
- for (int i = 1; i < n; i++) {\r
- float t = timeline[i];\r
- if (t > percent) {\r
- endIndex = i;\r
- break;\r
- }\r
- startIndex = i;\r
- }\r
- float startTime = timeline[startIndex];\r
- startIndex *= 3;\r
- float r1 = colors[startIndex];\r
- float g1 = colors[startIndex + 1];\r
- float b1 = colors[startIndex + 2];\r
- if (endIndex == -1) {\r
- temp[0] = r1;\r
- temp[1] = g1;\r
- temp[2] = b1;\r
- return temp;\r
- }\r
- float factor = (percent - startTime) / (timeline[endIndex] - startTime);\r
- endIndex *= 3;\r
- temp[0] = r1 + (colors[endIndex] - r1) * factor;\r
- temp[1] = g1 + (colors[endIndex + 1] - g1) * factor;\r
- temp[2] = b1 + (colors[endIndex + 2] - b1) * factor;\r
- return temp;\r
- }\r
-\r
- public void save(Writer output) throws IOException {\r
- super.save(output);\r
- if (!active) {\r
- return;\r
- }\r
- output.write("colorsCount: " + colors.length + "\n");\r
- for (int i = 0; i < colors.length; i++) {\r
- output.write("colors" + i + ": " + colors[i] + "\n");\r
- }\r
- output.write("timelineCount: " + timeline.length + "\n");\r
- for (int i = 0; i < timeline.length; i++) {\r
- output.write("timeline" + i + ": " + timeline[i] + "\n");\r
- }\r
- }\r
-\r
- public void load(BufferedReader reader) throws IOException {\r
- super.load(reader);\r
- if (!active) {\r
- return;\r
- }\r
- colors = new float[readInt(reader, "colorsCount")];\r
- for (int i = 0; i < colors.length; i++) {\r
- colors[i] = readFloat(reader, "colors" + i);\r
- }\r
- timeline = new float[readInt(reader, "timelineCount")];\r
- for (int i = 0; i < timeline.length; i++) {\r
- timeline[i] = readFloat(reader, "timeline" + i);\r
- }\r
- }\r
-\r
- public void load(GradientColorValue value) {\r
- super.load(value);\r
- colors = new float[value.colors.length];\r
- System.arraycopy(value.colors, 0, colors, 0, colors.length);\r
- timeline = new float[value.timeline.length];\r
- System.arraycopy(value.timeline, 0, timeline, 0, timeline.length);\r
- }\r
- }\r
-\r
- static public class SpawnShapeValue extends ParticleValue {\r
-\r
- SpawnShape shape = SpawnShape.point;\r
- boolean edges;\r
- SpawnEllipseSide side = SpawnEllipseSide.both;\r
-\r
- public SpawnShape getShape() {\r
- return shape;\r
- }\r
-\r
- public void setShape(SpawnShape shape) {\r
- this.shape = shape;\r
- }\r
-\r
- public boolean isEdges() {\r
- return edges;\r
- }\r
-\r
- public void setEdges(boolean edges) {\r
- this.edges = edges;\r
- }\r
-\r
- public SpawnEllipseSide getSide() {\r
- return side;\r
- }\r
-\r
- public void setSide(SpawnEllipseSide side) {\r
- this.side = side;\r
- }\r
-\r
- public void save(Writer output) throws IOException {\r
- super.save(output);\r
- if (!active) {\r
- return;\r
- }\r
- output.write("shape: " + shape + "\n");\r
- if (shape == SpawnShape.ellipse) {\r
- output.write("edges: " + edges + "\n");\r
- output.write("side: " + side + "\n");\r
- }\r
- }\r
-\r
- public void load(BufferedReader reader) throws IOException {\r
- super.load(reader);\r
- if (!active) {\r
- return;\r
- }\r
- shape = SpawnShape.valueOf(readString(reader, "shape"));\r
- if (shape == SpawnShape.ellipse) {\r
- edges = readBoolean(reader, "edges");\r
- side = SpawnEllipseSide.valueOf(readString(reader, "side"));\r
- }\r
- }\r
-\r
- public void load(SpawnShapeValue value) {\r
- super.load(value);\r
- shape = value.shape;\r
- edges = value.edges;\r
- side = value.side;\r
- }\r
- }\r
-\r
- static public enum SpawnShape {\r
-\r
- point, line, square, ellipse\r
- }\r
-\r
- static public enum SpawnEllipseSide {\r
-\r
- both, top, bottom\r
- }\r
-}\r