--- /dev/null
+/*******************************************************************************\r
+ * Copyright 2011 See AUTHORS file.\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of 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,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ ******************************************************************************/\r
+\r
+package com.badlogic.gdx.graphics.g2d;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.File;\r
+import java.io.FileWriter;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.InputStreamReader;\r
+import java.io.Writer;\r
+\r
+import com.badlogic.gdx.files.FileHandle;\r
+import com.badlogic.gdx.graphics.Texture;\r
+import com.badlogic.gdx.utils.Array;\r
+import com.badlogic.gdx.utils.Disposable;\r
+import com.badlogic.gdx.utils.GdxRuntimeException;\r
+\r
+/** See <a href="http://www.badlogicgames.com/wordpress/?p=1255">http://www.badlogicgames.com/wordpress/?p=1255</a>\r
+ * @author mzechner */\r
+public class ParticleEffect implements Disposable {\r
+ private final Array<ParticleEmitter> emitters;\r
+\r
+ public ParticleEffect () {\r
+ emitters = new Array(8);\r
+ }\r
+\r
+ public ParticleEffect (ParticleEffect effect) {\r
+ emitters = new Array(true, effect.emitters.size);\r
+ for (int i = 0, n = effect.emitters.size; i < n; i++)\r
+ emitters.add(new ParticleEmitter(effect.emitters.get(i)));\r
+ }\r
+\r
+ public void start () {\r
+ for (int i = 0, n = emitters.size; i < n; i++)\r
+ emitters.get(i).start();\r
+ }\r
+\r
+ public void update (float delta) {\r
+ for (int i = 0, n = emitters.size; i < n; i++)\r
+ emitters.get(i).update(delta);\r
+ }\r
+\r
+ public void draw (SpriteBatch spriteBatch) {\r
+ for (int i = 0, n = emitters.size; i < n; i++)\r
+ emitters.get(i).draw(spriteBatch);\r
+ }\r
+\r
+ public void draw (SpriteBatch spriteBatch, float delta) {\r
+ for (int i = 0, n = emitters.size; i < n; i++)\r
+ emitters.get(i).draw(spriteBatch, delta);\r
+ }\r
+\r
+ public void allowCompletion () {\r
+ for (int i = 0, n = emitters.size; i < n; i++)\r
+ emitters.get(i).allowCompletion();\r
+ }\r
+\r
+ public boolean isComplete () {\r
+ for (int i = 0, n = emitters.size; i < n; i++) {\r
+ ParticleEmitter emitter = emitters.get(i);\r
+ if (emitter.isContinuous()) return false;\r
+ if (!emitter.isComplete()) return false;\r
+ }\r
+ return true;\r
+ }\r
+\r
+ public void setDuration (int duration) {\r
+ for (int i = 0, n = emitters.size; i < n; i++) {\r
+ ParticleEmitter emitter = emitters.get(i);\r
+ emitter.setContinuous(false);\r
+ emitter.duration = duration;\r
+ emitter.durationTimer = 0;\r
+ }\r
+ }\r
+\r
+ public void setPosition (float x, float y) {\r
+ for (int i = 0, n = emitters.size; i < n; i++)\r
+ emitters.get(i).setPosition(x, y);\r
+ }\r
+\r
+ public void setFlip (boolean flipX, boolean flipY) {\r
+ for (int i = 0, n = emitters.size; i < n; i++)\r
+ emitters.get(i).setFlip(flipX, flipY);\r
+ }\r
+\r
+ public Array<ParticleEmitter> getEmitters () {\r
+ return emitters;\r
+ }\r
+\r
+ /** Returns the emitter with the specified name, or null. */\r
+ public ParticleEmitter findEmitter (String name) {\r
+ for (int i = 0, n = emitters.size; i < n; i++) {\r
+ ParticleEmitter emitter = emitters.get(i);\r
+ if (emitter.getName().equals(name)) return emitter;\r
+ }\r
+ return null;\r
+ }\r
+\r
+ public void save (File file) {\r
+ Writer output = null;\r
+ try {\r
+ output = new FileWriter(file);\r
+ int index = 0;\r
+ for (int i = 0, n = emitters.size; i < n; i++) {\r
+ ParticleEmitter emitter = emitters.get(i);\r
+ if (index++ > 0) output.write("\n\n");\r
+ emitter.save(output);\r
+ output.write("- Image Path -\n");\r
+ output.write(emitter.getImagePath() + "\n");\r
+ }\r
+ } catch (IOException ex) {\r
+ throw new GdxRuntimeException("Error saving effect: " + file, ex);\r
+ } finally {\r
+ try {\r
+ if (output != null) output.close();\r
+ } catch (IOException ex) {\r
+ }\r
+ }\r
+ }\r
+\r
+ public void load (FileHandle effectFile, FileHandle imagesDir) {\r
+ loadEmitters(effectFile);\r
+ loadEmitterImages(imagesDir);\r
+ }\r
+\r
+ public void load (FileHandle effectFile, TextureAtlas atlas) {\r
+ loadEmitters(effectFile);\r
+ loadEmitterImages(atlas);\r
+ }\r
+\r
+ public void loadEmitters (FileHandle effectFile) {\r
+ InputStream input = effectFile.read();\r
+ emitters.clear();\r
+ BufferedReader reader = null;\r
+ try {\r
+ reader = new BufferedReader(new InputStreamReader(input), 512);\r
+ while (true) {\r
+ ParticleEmitter emitter = new ParticleEmitter(reader);\r
+ reader.readLine();\r
+ emitter.setImagePath(reader.readLine());\r
+ emitters.add(emitter);\r
+ if (reader.readLine() == null) break;\r
+ if (reader.readLine() == null) break;\r
+ }\r
+ } catch (IOException ex) {\r
+ throw new GdxRuntimeException("Error loading effect: " + effectFile, ex);\r
+ } finally {\r
+ try {\r
+ if (reader != null) reader.close();\r
+ } catch (IOException ex) {\r
+ }\r
+ }\r
+ }\r
+\r
+ public void loadEmitterImages (TextureAtlas atlas) {\r
+ for (int i = 0, n = emitters.size; i < n; i++) {\r
+ ParticleEmitter emitter = emitters.get(i);\r
+ String imagePath = emitter.getImagePath();\r
+ if (imagePath == null) continue;\r
+ String imageName = new File(imagePath.replace('\\', '/')).getName();\r
+ int lastDotIndex = imageName.lastIndexOf('.');\r
+ if (lastDotIndex != -1) imageName = imageName.substring(0, lastDotIndex);\r
+ Sprite sprite = atlas.createSprite(imageName);\r
+ if (sprite == null) throw new IllegalArgumentException("SpriteSheet missing image: " + imageName);\r
+ emitter.setSprite(sprite);\r
+ }\r
+ }\r
+\r
+ public void loadEmitterImages (FileHandle imagesDir) {\r
+ for (int i = 0, n = emitters.size; i < n; i++) {\r
+ ParticleEmitter emitter = emitters.get(i);\r
+ String imagePath = emitter.getImagePath();\r
+ if (imagePath == null) continue;\r
+ String imageName = new File(imagePath.replace('\\', '/')).getName();\r
+ emitter.setSprite(new Sprite(loadTexture(imagesDir.child(imageName))));\r
+ }\r
+ }\r
+\r
+ protected Texture loadTexture (FileHandle file) {\r
+ return new Texture(file, false);\r
+ }\r
+\r
+ /** Disposes the texture for each sprite for each ParticleEmitter. */\r
+ public void dispose () {\r
+ for (int i = 0, n = emitters.size; i < n; i++) {\r
+ ParticleEmitter emitter = emitters.get(i);\r
+ emitter.getSprite().getTexture().dispose();\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/*******************************************************************************\r
+ * Copyright 2011 See AUTHORS file.\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of 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,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ ******************************************************************************/\r
+\r
+package com.badlogic.gdx.graphics.g2d;\r
+\r
+import com.badlogic.gdx.graphics.g2d.ParticleEffectPool.PooledEffect;\r
+import com.badlogic.gdx.utils.Pool;\r
+\r
+public class ParticleEffectPool extends Pool<PooledEffect> {\r
+ private final ParticleEffect effect;\r
+\r
+ public ParticleEffectPool (ParticleEffect effect, int initialCapacity, int max) {\r
+ super(initialCapacity, max);\r
+ this.effect = effect;\r
+ }\r
+\r
+ protected PooledEffect newObject () {\r
+ return new PooledEffect(effect);\r
+ }\r
+\r
+ public PooledEffect obtain () {\r
+ PooledEffect effect = super.obtain();\r
+ effect.start();\r
+ return effect;\r
+ }\r
+\r
+ public class PooledEffect extends ParticleEffect {\r
+ PooledEffect (ParticleEffect effect) {\r
+ super(effect);\r
+ }\r
+\r
+ public void free () {\r
+ ParticleEffectPool.this.free(this);\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/*******************************************************************************\r
+ * Copyright 2011 See AUTHORS file.\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of 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,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ ******************************************************************************/\r
+\r
+package com.badlogic.gdx.graphics.g2d;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.IOException;\r
+import java.io.Writer;\r
+\r
+import com.badlogic.gdx.graphics.GL10;\r
+import com.badlogic.gdx.graphics.Texture;\r
+import com.badlogic.gdx.math.MathUtils;\r
+\r
+// BOZO - Javadoc.\r
+// BOZO - Add a duplicate emitter button.\r
+\r
+public class ParticleEmitter {\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
+\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
+\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 int activeCount;\r
+ private boolean[] active;\r
+ private boolean firstUpdate;\r
+ private boolean flipX, flipY;\r
+ private int updateFlags;\r
+ private boolean allowCompletion;\r
+\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
+\r
+ private boolean attached;\r
+ private boolean continuous;\r
+ private boolean aligned;\r
+ private boolean behind;\r
+ private boolean additive = true;\r
+\r
+ public ParticleEmitter () {\r
+ initialize();\r
+ }\r
+\r
+ public ParticleEmitter (BufferedReader reader) throws IOException {\r
+ initialize();\r
+ load(reader);\r
+ }\r
+\r
+ public ParticleEmitter (ParticleEmitter emitter) {\r
+ sprite = emitter.sprite;\r
+ name = emitter.name;\r
+ setMaxParticleCount(emitter.maxParticleCount);\r
+ minParticleCount = emitter.minParticleCount;\r
+ delayValue.load(emitter.delayValue);\r
+ durationValue.load(emitter.durationValue);\r
+ emissionValue.load(emitter.emissionValue);\r
+ lifeValue.load(emitter.lifeValue);\r
+ lifeOffsetValue.load(emitter.lifeOffsetValue);\r
+ scaleValue.load(emitter.scaleValue);\r
+ rotationValue.load(emitter.rotationValue);\r
+ velocityValue.load(emitter.velocityValue);\r
+ angleValue.load(emitter.angleValue);\r
+ windValue.load(emitter.windValue);\r
+ gravityValue.load(emitter.gravityValue);\r
+ transparencyValue.load(emitter.transparencyValue);\r
+ tintValue.load(emitter.tintValue);\r
+ xOffsetValue.load(emitter.xOffsetValue);\r
+ yOffsetValue.load(emitter.yOffsetValue);\r
+ spawnWidthValue.load(emitter.spawnWidthValue);\r
+ spawnHeightValue.load(emitter.spawnHeightValue);\r
+ spawnShapeValue.load(emitter.spawnShapeValue);\r
+ attached = emitter.attached;\r
+ continuous = emitter.continuous;\r
+ aligned = emitter.aligned;\r
+ behind = emitter.behind;\r
+ additive = emitter.additive;\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 boolean[maxParticleCount];\r
+ activeCount = 0;\r
+ particles = new Particle[maxParticleCount];\r
+ }\r
+\r
+ public void addParticle () {\r
+ int activeCount = this.activeCount;\r
+ if (activeCount == maxParticleCount) return;\r
+ boolean[] active = this.active;\r
+ for (int i = 0, n = active.length; i < n; i++) {\r
+ if (!active[i]) {\r
+ activateParticle(i);\r
+ active[i] = true;\r
+ this.activeCount = activeCount + 1;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ public void addParticles (int count) {\r
+ count = Math.min(count, maxParticleCount - activeCount);\r
+ if (count == 0) return;\r
+ boolean[] active = this.active;\r
+ int index = 0, n = active.length;\r
+ outer:\r
+ for (int i = 0; i < count; i++) {\r
+ for (; index < n; index++) {\r
+ if (!active[index]) {\r
+ activateParticle(index);\r
+ active[index++] = true;\r
+ continue outer;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ this.activeCount += count;\r
+ }\r
+\r
+ public void update (float delta) {\r
+ accumulator += Math.min(delta * 1000, 250);\r
+ if (accumulator < 1) return;\r
+ int deltaMillis = (int)accumulator;\r
+ accumulator -= deltaMillis;\r
+\r
+ boolean[] active = this.active;\r
+ int activeCount = this.activeCount;\r
+ for (int i = 0, n = active.length; i < n; i++) {\r
+ if (active[i] && !updateParticle(particles[i], delta, deltaMillis)) {\r
+ active[i] = false;\r
+ activeCount--;\r
+ }\r
+ }\r
+ this.activeCount = activeCount;\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) return;\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 - activeCount);\r
+ emissionDelta -= emitCount * emissionTime;\r
+ emissionDelta %= emissionTime;\r
+ addParticles(emitCount);\r
+ }\r
+ }\r
+ if (activeCount < minParticleCount) addParticles(minParticleCount - activeCount);\r
+ }\r
+\r
+ public void draw (SpriteBatch spriteBatch) {\r
+ if (additive) spriteBatch.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE);\r
+\r
+ Particle[] particles = this.particles;\r
+ boolean[] active = this.active;\r
+ int activeCount = this.activeCount;\r
+\r
+ for (int i = 0, n = active.length; i < n; i++)\r
+ if (active[i]) particles[i].draw(spriteBatch);\r
+ this.activeCount = activeCount;\r
+\r
+ if (additive) spriteBatch.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);\r
+ }\r
+\r
+ /** Updates and draws the particles. This is slightly more efficient than calling {@link #update(float)} and\r
+ * {@link #draw(SpriteBatch)} separately. */\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) spriteBatch.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE);\r
+\r
+ Particle[] particles = this.particles;\r
+ boolean[] active = this.active;\r
+ int activeCount = this.activeCount;\r
+ for (int i = 0, n = active.length; i < n; i++) {\r
+ if (active[i]) {\r
+ Particle particle = particles[i];\r
+ if (updateParticle(particle, delta, deltaMillis))\r
+ particle.draw(spriteBatch);\r
+ else {\r
+ active[i] = false;\r
+ activeCount--;\r
+ }\r
+ }\r
+ }\r
+ this.activeCount = activeCount;\r
+\r
+ if (additive) spriteBatch.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);\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) return;\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 - activeCount);\r
+ emissionDelta -= emitCount * emissionTime;\r
+ emissionDelta %= emissionTime;\r
+ addParticles(emitCount);\r
+ }\r
+ }\r
+ if (activeCount < minParticleCount) addParticles(minParticleCount - activeCount);\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()) emissionDiff -= emission;\r
+\r
+ life = (int)lifeValue.newLowValue();\r
+ lifeDiff = (int)lifeValue.newHighValue();\r
+ if (!lifeValue.isRelative()) lifeDiff -= life;\r
+\r
+ lifeOffset = lifeOffsetValue.active ? (int)lifeOffsetValue.newLowValue() : 0;\r
+ lifeOffsetDiff = (int)lifeOffsetValue.newHighValue();\r
+ if (!lifeOffsetValue.isRelative()) lifeOffsetDiff -= lifeOffset;\r
+\r
+ spawnWidth = spawnWidthValue.newLowValue();\r
+ spawnWidthDiff = spawnWidthValue.newHighValue();\r
+ if (!spawnWidthValue.isRelative()) spawnWidthDiff -= spawnWidth;\r
+\r
+ spawnHeight = spawnHeightValue.newLowValue();\r
+ spawnHeightDiff = spawnHeightValue.newHighValue();\r
+ if (!spawnHeightValue.isRelative()) spawnHeightDiff -= spawnHeight;\r
+\r
+ updateFlags = 0;\r
+ if (angleValue.active && angleValue.timeline.length > 1) updateFlags |= UPDATE_ANGLE;\r
+ if (velocityValue.active && velocityValue.active) updateFlags |= UPDATE_VELOCITY;\r
+ if (scaleValue.timeline.length > 1) updateFlags |= UPDATE_SCALE;\r
+ if (rotationValue.active && rotationValue.timeline.length > 1) updateFlags |= UPDATE_ROTATION;\r
+ if (windValue.active) updateFlags |= UPDATE_WIND;\r
+ if (gravityValue.active) updateFlags |= UPDATE_GRAVITY;\r
+ if (tintValue.timeline.length > 1) updateFlags |= UPDATE_TINT;\r
+ }\r
+\r
+ protected Particle newParticle (Sprite sprite) {\r
+ return new Particle(sprite);\r
+ }\r
+\r
+ private void activateParticle (int index) {\r
+ Particle particle = particles[index];\r
+ if (particle == null) {\r
+ particles[index] = particle = newParticle(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()) particle.velocityDiff -= particle.velocity;\r
+ }\r
+\r
+ particle.angle = angleValue.newLowValue();\r
+ particle.angleDiff = angleValue.newHighValue();\r
+ if (!angleValue.isRelative()) particle.angleDiff -= particle.angle;\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()) particle.scaleDiff -= particle.scale;\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()) particle.rotationDiff -= particle.rotation;\r
+ float rotation = particle.rotation + particle.rotationDiff * rotationValue.getScale(0);\r
+ if (aligned) rotation += angle;\r
+ particle.setRotation(rotation);\r
+ }\r
+\r
+ if (windValue.active) {\r
+ particle.wind = windValue.newLowValue();\r
+ particle.windDiff = windValue.newHighValue();\r
+ if (!windValue.isRelative()) particle.windDiff -= particle.wind;\r
+ }\r
+\r
+ if (gravityValue.active) {\r
+ particle.gravity = gravityValue.newLowValue();\r
+ particle.gravityDiff = gravityValue.newHighValue();\r
+ if (!gravityValue.isRelative()) particle.gravityDiff -= particle.gravity;\r
+ }\r
+\r
+ float[] color = particle.tint;\r
+ if (color == null) particle.tint = color = new float[3];\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) x += xOffsetValue.newLowValue();\r
+ float y = this.y;\r
+ if (yOffsetValue.active) y += yOffsetValue.newLowValue();\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) break;\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
+ 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) offsetTime = particle.currentLife - 1;\r
+ updateParticle(particle, offsetTime / 1000f, offsetTime);\r
+ }\r
+ }\r
+\r
+ private boolean updateParticle (Particle particle, float delta, int deltaMillis) {\r
+ int life = particle.currentLife - deltaMillis;\r
+ if (life <= 0) return false;\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
+ 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) rotation += angle;\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) rotation += particle.angle;\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
+ if ((updateFlags & UPDATE_GRAVITY) != 0)\r
+ velocityY += (particle.gravity + particle.gravityDiff * gravityValue.getScale(percent)) * delta;\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
+ float[] color;\r
+ if ((updateFlags & UPDATE_TINT) != 0)\r
+ color = tintValue.getColor(percent);\r
+ else\r
+ color = particle.tint;\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
+ boolean[] active = this.active;\r
+ for (int i = 0, n = active.length; i < n; i++)\r
+ if (active[i]) particles[i].translate(xAmount, yAmount);\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) return;\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) break;\r
+ particle.setTexture(texture);\r
+ particle.setOrigin(originX, originY);\r
+ }\r
+ }\r
+\r
+ /** Ignores the {@link #setContinuous(boolean) continuous} setting until the emitter is started again. This allows the emitter\r
+ * to stop smoothly. */\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) return false;\r
+ return durationTimer >= duration && activeCount == 0;\r
+ }\r
+\r
+ public float getPercentComplete () {\r
+ if (delayTimer < delay) return 0;\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 activeCount;\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) return;\r
+ for (int i = 0, n = particles.length; i < n; i++) {\r
+ Particle particle = particles[i];\r
+ if (particle != null) particle.flip(flipX, flipY);\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) throw ex;\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) throw new IOException("Missing value: " + name);\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
+ static class Particle extends Sprite {\r
+ int life, currentLife;\r
+ float scale, scaleDiff;\r
+ float rotation, rotationDiff;\r
+ float velocity, velocityDiff;\r
+ float angle, angleDiff;\r
+ float angleCos, angleSin;\r
+ float transparency, transparencyDiff;\r
+ float wind, windDiff;\r
+ float gravity, gravityDiff;\r
+ float[] tint;\r
+\r
+ public Particle (Sprite sprite) {\r
+ super(sprite);\r
+ }\r
+ }\r
+\r
+ static public class ParticleValue {\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
+ public void load (BufferedReader reader) throws IOException {\r
+ if (!alwaysActive)\r
+ active = readBoolean(reader, "active");\r
+ else\r
+ active = true;\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
+ 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) return;\r
+ output.write("value: " + value + "\n");\r
+ }\r
+\r
+ public void load (BufferedReader reader) throws IOException {\r
+ super.load(reader);\r
+ if (!active) return;\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
+ 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) return;\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) return;\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
+ 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) return scaling[n - 1];\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) return;\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
+ 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
+ public void load (BufferedReader reader) throws IOException {\r
+ super.load(reader);\r
+ if (!active) return;\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
+ 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
+ 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
+ static private float[] temp = new float[4];\r
+\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) return;\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
+ 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
+ public void load (BufferedReader reader) throws IOException {\r
+ super.load(reader);\r
+ if (!active) return;\r
+ colors = new float[readInt(reader, "colorsCount")];\r
+ for (int i = 0; i < colors.length; i++)\r
+ colors[i] = readFloat(reader, "colors" + i);\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
+ 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
+ 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) return;\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) return;\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
+ point, line, square, ellipse\r
+ }\r
+\r
+ static public enum SpawnEllipseSide {\r
+ both, top, bottom\r
+ }\r
+}\r
--- /dev/null
+/*******************************************************************************\r
+ * Copyright 2011 See AUTHORS file.\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of 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,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ ******************************************************************************/\r
+\r
+package com.badlogic.gdx.graphics.g2d;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.IOException;\r
+\r
+import com.badlogic.gdx.math.MathUtils;\r
+import com.badlogic.gdx.math.Vector2;\r
+import com.badlogic.gdx.physics.box2d.Fixture;\r
+import com.badlogic.gdx.physics.box2d.RayCastCallback;\r
+import com.badlogic.gdx.physics.box2d.World;\r
+\r
+/** @author kalle_h\r
+ * \r
+ * ParticleEmitterBox2D use box2d rayCast:ing to achieve continuous collision detection against box2d fixtures. If\r
+ * particle detect collision it change it's direction before actual collision would occur. Velocity is 100% reflected.\r
+ * \r
+ * These particles does not have any other physical attributes or functionality. Particles can't collide to other\r
+ * particles. */\r
+public class ParticleEmitterBox2D extends ParticleEmitter {\r
+ final World world;\r
+ final Vector2 startPoint = new Vector2();\r
+ final Vector2 endPoint = new Vector2();\r
+ /** collision flag */\r
+ boolean particleCollided;\r
+ float normalAngle;\r
+ /** If velocities squared is shorter than this it could lead 0 length rayCast that cause c++ assertion at box2d */\r
+ private final static float EPSILON = 0.001f;\r
+\r
+ /** default visibility to prevent synthetic accesor creation */\r
+ final RayCastCallback rayCallBack = new RayCastCallback() {\r
+ public float reportRayFixture (Fixture fixture, Vector2 point, Vector2 normal, float fraction) {\r
+ ParticleEmitterBox2D.this.particleCollided = true;\r
+ ParticleEmitterBox2D.this.normalAngle = MathUtils.atan2(normal.y, normal.x) * MathUtils.radiansToDegrees;\r
+ return fraction;\r
+ }\r
+ };\r
+\r
+ /** Constructs default ParticleEmitterBox2D. Box2d World is used for rayCasting. Assumes that particles use same unit system\r
+ * that box2d world does.\r
+ * \r
+ * @param world */\r
+ public ParticleEmitterBox2D (World world) {\r
+ super();\r
+ this.world = world;\r
+ }\r
+\r
+ /** /**Constructs ParticleEmitterBox2D using bufferedReader. Box2d World is used for rayCasting. Assumes that particles use same\r
+ * unit system that box2d world does.\r
+ * \r
+ * @param world\r
+ * @param reader\r
+ * @throws IOException */\r
+ public ParticleEmitterBox2D (World world, BufferedReader reader) throws IOException {\r
+ super(reader);\r
+ this.world = world;\r
+ }\r
+\r
+ /** Constructs ParticleEmitterBox2D fully copying given emitter attributes. Box2d World is used for rayCasting. Assumes that\r
+ * particles use same unit system that box2d world does.\r
+ * \r
+ * @param world\r
+ * @param emitter */\r
+ public ParticleEmitterBox2D (World world, ParticleEmitter emitter) {\r
+ super(emitter);\r
+ this.world = world;\r
+ }\r
+\r
+ @Override\r
+ protected Particle newParticle (Sprite sprite) {\r
+ return new ParticleBox2D(sprite);\r
+ }\r
+\r
+ /** Particle that can collide to box2d fixtures */\r
+ private class ParticleBox2D extends Particle {\r
+ public ParticleBox2D (Sprite sprite) {\r
+ super(sprite);\r
+ }\r
+\r
+ /** translate particle given amount. Continuous collision detection achieved by using RayCast from oldPos to newPos.\r
+ * \r
+ * @param velocityX\r
+ * @param velocityY */\r
+ @Override\r
+ public void translate (float velocityX, float velocityY) {\r
+ /** If velocities squares summed is shorter than Epsilon it could lead ~0 length rayCast that cause nasty c++ assertion\r
+ * inside box2d. This is so short distance that moving particle has no effect so this return early. */\r
+ if ((velocityX * velocityX + velocityY * velocityY) < EPSILON) return;\r
+\r
+ /** Position offset is half of sprite texture size. */\r
+ final float x = getX() + getWidth() / 2f;\r
+ final float y = getY() + getHeight() / 2f;\r
+\r
+ /** collision flag to false */\r
+ particleCollided = false;\r
+ startPoint.set(x, y);\r
+ endPoint.set(x + velocityX, y + velocityY);\r
+ if (world != null) world.rayCast(rayCallBack, startPoint, endPoint);\r
+\r
+ /** If ray collided boolean has set to true at rayCallBack */\r
+ if (!particleCollided) {\r
+ // perfect reflection\r
+ angle = 2f * normalAngle - angle - 180f;\r
+ angleCos = MathUtils.cosDeg(angle);\r
+ angleSin = MathUtils.sinDeg(angle);\r
+ velocityX = velocity * angleCos;\r
+ velocityY = velocity * angleSin;\r
+ }\r
+\r
+ super.translate(velocityX, velocityY);\r
+ }\r
+ }\r
+}\r
*/\r
private final static float EPSILON = 0.001f;\r
/**\r
- * default visibility to prevent synthetic accessor creation\r
+ * default visibility to prevent synthetic accesor creation\r
*/\r
private final RayCastCallback rayCallBack = new RayCastCallback() {\r
@Override\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.graphics.g2d.particle.emitterattributs.*;\r
import com.badlogic.gdx.math.MathUtils;\r
//TODO - Javadoc.\r
//TODO - Add a duplicate emitter button.\r
public class ParticleEmitter implements Cloneable {\r
\r
private static class StandardParticleFactory implements ParticleFactory {\r
-\r
@Override\r
public Particle createParticle(Sprite sprite) {\r
return new Particle(sprite);\r
private ScaledNumericValue gravityValue = new ScaledNumericValue();\r
private ScaledNumericValue transparencyValue = new ScaledNumericValue();\r
private GradientColorValue tintValue = new GradientColorValue();\r
- private RangedNumericValue xOffsetValue = new RangedNumericValue();\r
- private RangedNumericValue yOffsetValue = new RangedNumericValue();\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 boolean aligned;\r
private boolean behind;\r
private boolean additive = true;\r
+ \r
private final ParticleFactory factory;\r
\r
public ParticleEmitter() {\r
n.name = name;\r
n.setMaxParticleCount(maxParticleCount);\r
n.minParticleCount = minParticleCount;\r
- n.delayValue = delayValue.clone();\r
- n.durationValue = durationValue.clone();\r
- n.emissionValue = emissionValue.clone();\r
- n.lifeValue = lifeValue.clone();\r
- n.lifeOffsetValue = lifeOffsetValue.clone();\r
- n.scaleValue = scaleValue.clone();\r
- n.rotationValue = rotationValue.clone();\r
- n.velocityValue = velocityValue.clone();\r
- n.angleValue = angleValue.clone();\r
- n.windValue = windValue.clone();\r
- n.gravityValue = gravityValue.clone();\r
- n.transparencyValue = transparencyValue.clone();\r
- n.tintValue = tintValue.clone();\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
}\r
\r
public void update(float delta) {\r
- //this hole timeing code does not provide any benefit\r
- accumulator += Math.min(delta * 1000, 250);//TODO bullshit to do this\r
+ accumulator += Math.min(delta * 1000, 250);\r
if (accumulator < 1) {\r
return;\r
}\r
int deltaMillis = (int) accumulator;\r
accumulator -= deltaMillis;\r
\r
-\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
private void restart() {\r
- delay = delayValue.isActive() ? delayValue.newValue() : 0;\r
+ delay = delayValue.active ? delayValue.newLowValue() : 0;\r
delayTimer = 0;\r
\r
durationTimer -= duration;\r
- duration = durationValue.newValue();\r
+ duration = durationValue.newLowValue();\r
\r
emission = (int) emissionValue.newLowValue();\r
emissionDiff = (int) emissionValue.newHighValue();\r
lifeDiff -= life;\r
}\r
\r
- lifeOffset = lifeOffsetValue.isActive() ? (int) lifeOffsetValue.newLowValue() : 0;\r
+ lifeOffset = lifeOffsetValue.active ? (int) lifeOffsetValue.newLowValue() : 0;\r
lifeOffsetDiff = (int) lifeOffsetValue.newHighValue();\r
if (!lifeOffsetValue.isRelative()) {\r
lifeOffsetDiff -= lifeOffset;\r
}\r
\r
updateFlags = 0;\r
- if (angleValue.isActive() && angleValue.getTimeLineCount() > 1) {\r
+ if (angleValue.active && angleValue.timeline.length > 1) {\r
updateFlags |= UPDATE_ANGLE;\r
}\r
- if (velocityValue.isActive() && velocityValue.isActive()) {\r
+ if (velocityValue.active && velocityValue.active) {\r
updateFlags |= UPDATE_VELOCITY;\r
}\r
- if (scaleValue.getTimeLineCount() > 1) {\r
+ if (scaleValue.timeline.length > 1) {\r
updateFlags |= UPDATE_SCALE;\r
}\r
- if (rotationValue.isActive() && rotationValue.getTimeLineCount() > 1) {\r
+ if (rotationValue.active && rotationValue.timeline.length > 1) {\r
updateFlags |= UPDATE_ROTATION;\r
}\r
- if (windValue.isActive()) {\r
+ if (windValue.active) {\r
updateFlags |= UPDATE_WIND;\r
}\r
- if (gravityValue.isActive()) {\r
+ if (gravityValue.active) {\r
updateFlags |= UPDATE_GRAVITY;\r
}\r
- if (tintValue.getTimeLineCount() > 1) {\r
+ if (tintValue.timeline.length > 1) {\r
updateFlags |= UPDATE_TINT;\r
}\r
}\r
\r
particle.currentLife = particle.life = life + (int) (lifeDiff * lifeValue.getScale(percent));\r
\r
- if (velocityValue.isActive()) {\r
+ if (velocityValue.active) {\r
particle.velocity = velocityValue.newLowValue();\r
particle.velocityDiff = velocityValue.newHighValue();\r
if (!velocityValue.isRelative()) {\r
}\r
particle.setScale(particle.scale + particle.scaleDiff * scaleValue.getScale(0));\r
\r
- if (rotationValue.isActive()) {\r
+ if (rotationValue.active) {\r
particle.rotation = rotationValue.newLowValue();\r
particle.rotationDiff = rotationValue.newHighValue();\r
if (!rotationValue.isRelative()) {\r
particle.setRotation(rotation);\r
}\r
\r
- if (windValue.isActive()) {\r
+ if (windValue.active) {\r
particle.wind = windValue.newLowValue();\r
particle.windDiff = windValue.newHighValue();\r
if (!windValue.isRelative()) {\r
}\r
}\r
\r
- if (gravityValue.isActive()) {\r
+ if (gravityValue.active) {\r
particle.gravity = gravityValue.newLowValue();\r
particle.gravityDiff = gravityValue.newHighValue();\r
if (!gravityValue.isRelative()) {\r
\r
// Spawn.\r
float x = this.x;\r
- if (xOffsetValue.isActive()) {\r
- x += xOffsetValue.newValue();\r
+ if (xOffsetValue.active) {\r
+ x += xOffsetValue.newLowValue();\r
}\r
float y = this.y;\r
- if (yOffsetValue.isActive()) {\r
- y += yOffsetValue.newValue();\r
+ if (yOffsetValue.active) {\r
+ y += yOffsetValue.newLowValue();\r
}\r
- switch (spawnShapeValue.getShape()) {\r
+ switch (spawnShapeValue.shape) {\r
case square: {\r
float width = spawnWidth + (spawnWidthDiff * spawnWidthValue.getScale(percent));\r
float height = spawnHeight + (spawnHeightDiff * spawnHeightValue.getScale(percent));\r
break;\r
}\r
float scaleY = radiusX / (float) radiusY;\r
- if (spawnShapeValue.isEdges()) {\r
+ if (spawnShapeValue.edges) {\r
float spawnAngle;\r
- switch (spawnShapeValue.getSide()) {\r
+ switch (spawnShapeValue.side) {\r
case top:\r
spawnAngle = -MathUtils.random(179f);\r
break;\r
active.set(index);\r
}\r
\r
- /**\r
- * @return false if the particles lifetime exceeded\r
- */\r
private boolean updateParticle(Particle particle, float delta, int deltaMillis) {\r
- particle.currentLife -= deltaMillis;\r
- if (particle.currentLife <= 0) {\r
+ int life = particle.currentLife - deltaMillis;\r
+ if (life <= 0) {\r
return false;\r
}\r
+ particle.currentLife = life;\r
\r
- float lostLifePercent = 1 - particle.currentLife / (float) particle.life;\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(lostLifePercent));\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(lostLifePercent)) * delta;\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(lostLifePercent);\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(lostLifePercent);\r
+ float rotation = particle.rotation + particle.rotationDiff * rotationValue.getScale(percent);\r
if (aligned) {\r
rotation += angle;\r
}\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(lostLifePercent);\r
+ float rotation = particle.rotation + particle.rotationDiff * rotationValue.getScale(percent);\r
if (aligned) {\r
rotation += particle.angle;\r
}\r
}\r
\r
if ((updateFlags & UPDATE_WIND) != 0) {\r
- velocityX += (particle.wind + particle.windDiff * windValue.getScale(lostLifePercent)) * delta;\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(lostLifePercent)) * delta;\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(lostLifePercent));\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(lostLifePercent);\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(lostLifePercent));\r
+ particle.transparency + particle.transparencyDiff * transparencyValue.getScale(percent));\r
\r
return true;\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 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
+++ /dev/null
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-package com.badlogic.gdx.graphics.g2d.particle.emitterattributs;
-
-import java.util.Arrays;
-
-/**
- *
- * @author Daniel Heinrich <dannynullzwo@gmail.com>
- */
-public class GradientColorValue extends ParticleValue {
-
- private float[] colors = {1, 1, 1};
- float[] timeline = {0};
-
- public GradientColorValue() {
- setAlwaysActive(true);
- }
-
- public float[] getTimeline() {
- return timeline;
- }
-
- public int getTimeLineCount()
- {
- return timeline.length;
- }
-
- public void setTimeline(float[] timeline) {
- this.timeline = timeline;
- }
-
- public float[] getColors() {
- return colors;
- }
-
- public void setColors(float[] colors) {
- this.colors = colors;
- }
-
- public float[] getColor(float percent) {
- int startIndex = 0, endIndex = -1;
- for (int i = 1; i < timeline.length; i++) {
- float t = timeline[i];
- if (t > percent) {
- endIndex = i;
- break;
- }
- startIndex = i;
- }
- float startTime = timeline[startIndex];
- startIndex *= 3;
- float r1 = colors[startIndex];
- float g1 = colors[startIndex + 1];
- float b1 = colors[startIndex + 2];
- float[] temp = new float[3];
- if (endIndex == -1) {
- temp[0] = r1;
- temp[1] = g1;
- temp[2] = b1;
- return temp;
- }
- float factor = (percent - startTime) / (timeline[endIndex] - startTime);
- endIndex *= 3;
- temp[0] = r1 + (colors[endIndex] - r1) * factor;
- temp[1] = g1 + (colors[endIndex + 1] - g1) * factor;
- temp[2] = b1 + (colors[endIndex + 2] - b1) * factor;
- return temp;
- }
-// public void save(Writer output) throws IOException {
-// super.save(output);
-// if (!active) {
-// return;
-// }
-// output.write("colorsCount: " + colors.length + "\n");
-// for (int i = 0; i < colors.length; i++) {
-// output.write("colors" + i + ": " + colors[i] + "\n");
-// }
-// output.write("timelineCount: " + timeline.length + "\n");
-// for (int i = 0; i < timeline.length; i++) {
-// output.write("timeline" + i + ": " + timeline[i] + "\n");
-// }
-// }
-//
-// public void load(BufferedReader reader) throws IOException {
-// super.load(reader);
-// if (!active) {
-// return;
-// }
-// colors = new float[readInt(reader, "colorsCount")];
-// for (int i = 0; i < colors.length; i++) {
-// colors[i] = readFloat(reader, "colors" + i);
-// }
-// timeline = new float[readInt(reader, "timelineCount")];
-// for (int i = 0; i < timeline.length; i++) {
-// timeline[i] = readFloat(reader, "timeline" + i);
-// }
-// }
-//
-// public void load(GradientColorValue value) {
-// super.load(value);
-// colors = new float[value.colors.length];
-// System.arraycopy(value.colors, 0, colors, 0, colors.length);
-// timeline = new float[value.timeline.length];
-// System.arraycopy(value.timeline, 0, timeline, 0, timeline.length);
-// }
-
- @Override
- public GradientColorValue clone() {
- GradientColorValue n = (GradientColorValue) super.clone();
- n.colors = Arrays.copyOf(colors, colors.length);
- n.timeline = Arrays.copyOf(timeline, timeline.length);
- return n;
- }
-}
+++ /dev/null
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-package com.badlogic.gdx.graphics.g2d.particle.emitterattributs;
-
-/**
- *
- * @author Daniel Heinrich <dannynullzwo@gmail.com>
- */
-public class NumericValue extends ParticleValue {
-
- private float value;
-
- public float getValue() {
- return value;
- }
-
- public void setValue(float value) {
- this.value = value;
- }
-// public void save(Writer output) throws IOException {
-// super.save(output);
-// if (!active) {
-// return;
-// }
-// output.write("value: " + value + "\n");
-// }
-//
-// public void load(BufferedReader reader) throws IOException {
-// super.load(reader);
-// if (!active) {
-// return;
-// }
-// value = readFloat(reader, "value");
-// }
-//
-
- @Override
- public NumericValue clone() {
- return (NumericValue) super.clone();
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-package com.badlogic.gdx.graphics.g2d.particle.emitterattributs;
-
-/**
- *
- * @author Daniel Heinrich <dannynullzwo@gmail.com>
- */
-public class ParticleValue implements Cloneable{
-
- private boolean active;
- private boolean alwaysActive;
-
- public void setAlwaysActive(boolean alwaysActive) {
- this.alwaysActive = alwaysActive;
- }
-
- public boolean isAlwaysActive() {
- return alwaysActive;
- }
-
- public boolean isActive() {
- return alwaysActive || active;
- }
-
- public void setActive(boolean active) {
- this.active = active;
- }
-
-// public void save(Writer output) throws IOException {
-// if (!alwaysActive) {
-// output.write("active: " + active + "\n");
-// } else {
-// active = true;
-// }
-// }
-//
-// public void load(BufferedReader reader) throws IOException {
-// if (!alwaysActive) {
-// active = readBoolean(reader, "active");
-// } else {
-// active = true;
-// }
-// }
-//
-
- @Override
- public ParticleValue clone(){
- try {
- return (ParticleValue) super.clone();
- } catch (CloneNotSupportedException ex) {
- throw new UnsupportedOperationException();
- }
- }
-
-}
+++ /dev/null
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-package com.badlogic.gdx.graphics.g2d.particle.emitterattributs;
-
-import com.badlogic.gdx.math.MathUtils;
-
-/**
- *
- * @author Daniel Heinrich <dannynullzwo@gmail.com>
- */
-public class RangedNumericValue extends ParticleValue {
-
- private float min, max;
-
- public float newValue() {
- return min + (max - min) * MathUtils.random();
- }
-
- public void set(float value) {
- min = value;
- max = value;
- }
-
- public void set(float min, float max) {
- setMin(min);
- setMax(max);
- }
-
- public float getMin() {
- return min;
- }
-
- public void setMin(float min) {
- this.min = min;
- }
-
- public float getMax() {
- return max;
- }
-
- public void setMax(float max) {
- this.max = max;
- }
-// public void save(Writer output) throws IOException {
-// super.save(output);
-// if (!active) {
-// return;
-// }
-// output.write("lowMin: " + lowMin + "\n");
-// output.write("lowMax: " + lowMax + "\n");
-// }
-//
-// public void load(BufferedReader reader) throws IOException {
-// super.load(reader);
-// if (!active) {
-// return;
-// }
-// lowMin = readFloat(reader, "lowMin");
-// lowMax = readFloat(reader, "lowMax");
-// }
-
- @Override
- public RangedNumericValue clone() {
- return (RangedNumericValue) super.clone();
- }
-}
+++ /dev/null
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-package com.badlogic.gdx.graphics.g2d.particle.emitterattributs;
-
-import java.util.Arrays;
-
-/**
- *
- * @author Daniel Heinrich <dannynullzwo@gmail.com>
- */
-public class ScaledNumericValue extends ParticleValue {
-
- private float[] scaling = {1};
- float[] timeline = {0};
- private boolean relative;
- private RangedNumericValue low, heigh;
-
- public ScaledNumericValue() {
- low = new RangedNumericValue();
- heigh = new RangedNumericValue();
- }
-
- public float newHighValue() {
- return heigh.newValue();
- }
-
- public float newLowValue() {
- return low.newValue();
- }
-
- public RangedNumericValue getHeigh() {
- return heigh;
- }
-
- public RangedNumericValue getLow() {
- return low;
- }
-
- public float[] getScaling() {
- return scaling;
- }
-
- public void setScaling(float[] values) {
- this.scaling = values;
- }
-
- public float[] getTimeline() {
- return timeline;
- }
-
- public int getTimeLineCount()
- {
- return timeline.length;
- }
-
- public void setTimeline(float[] timeline) {
- this.timeline = timeline;
- }
-
- public boolean isRelative() {
- return relative;
- }
-
- public void setRelative(boolean relative) {
- this.relative = relative;
- }
-
- public float getScale(float percent) {
- int endIndex = -1;
- for (int i = 1; i < timeline.length; i++) {
- if (timeline[i] > percent) {
- endIndex = i;
- break;
- }
- }
- if (endIndex == -1) {
- return scaling[timeline.length - 1];
- }
- int startIndex = endIndex - 1;
- float startValue = scaling[startIndex];
- float startTime = timeline[startIndex];
- return startValue + (scaling[endIndex] - startValue) * ((percent - startTime) / (timeline[endIndex] - startTime));
- }
-// public void save(Writer output) throws IOException {
-// super.save(output);
-// if (!active) {
-// return;
-// }
-// output.write("highMin: " + highMin + "\n");
-// output.write("highMax: " + highMax + "\n");
-// output.write("relative: " + relative + "\n");
-// output.write("scalingCount: " + scaling.length + "\n");
-// for (int i = 0; i < scaling.length; i++) {
-// output.write("scaling" + i + ": " + scaling[i] + "\n");
-// }
-// output.write("timelineCount: " + timeline.length + "\n");
-// for (int i = 0; i < timeline.length; i++) {
-// output.write("timeline" + i + ": " + timeline[i] + "\n");
-// }
-// }
-//
-// public void load(BufferedReader reader) throws IOException {
-// super.load(reader);
-// if (!active) {
-// return;
-// }
-// highMin = readFloat(reader, "highMin");
-// highMax = readFloat(reader, "highMax");
-// relative = readBoolean(reader, "relative");
-// scaling = new float[readInt(reader, "scalingCount")];
-// for (int i = 0; i < scaling.length; i++) {
-// scaling[i] = readFloat(reader, "scaling" + i);
-// }
-// timeline = new float[readInt(reader, "timelineCount")];
-// for (int i = 0; i < timeline.length; i++) {
-// timeline[i] = readFloat(reader, "timeline" + i);
-// }
-// }
-
- @Override
- public ScaledNumericValue clone() {
- ScaledNumericValue n= (ScaledNumericValue) super.clone();
- n.low = low.clone();
- n.heigh = heigh.clone();
- n.scaling = Arrays.copyOf(scaling, scaling.length);
- n.timeline = Arrays.copyOf(timeline, timeline.length);
- return n;
- }
-}
+++ /dev/null
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-package com.badlogic.gdx.graphics.g2d.particle.emitterattributs;
-
-/**
- *
- * @author Daniel Heinrich <dannynullzwo@gmail.com>
- */
-public class SpawnShapeValue extends ParticleValue {
-
- public static enum SpawnShape {
-
- point, line, square, ellipse
- }
-
- public static enum SpawnEllipseSide {
-
- both, top, bottom
- }
- private SpawnShape shape = SpawnShape.point;
- private boolean edges;
- private SpawnEllipseSide side = SpawnEllipseSide.both;
-
- public SpawnShape getShape() {
- return shape;
- }
-
- public void setShape(SpawnShape shape) {
- this.shape = shape;
- }
-
- public boolean isEdges() {
- return edges;
- }
-
- public void setEdges(boolean edges) {
- this.edges = edges;
- }
-
- public SpawnEllipseSide getSide() {
- return side;
- }
-
- public void setSide(SpawnEllipseSide side) {
- this.side = side;
- }
-// public void save(Writer output) throws IOException {
-// super.save(output);
-// if (!active) {
-// return;
-// }
-// output.write("shape: " + shape + "\n");
-// if (shape == SpawnShape.ellipse) {
-// output.write("edges: " + edges + "\n");
-// output.write("side: " + side + "\n");
-// }
-// }
-//
-// public void load(BufferedReader reader) throws IOException {
-// super.load(reader);
-// if (!active) {
-// return;
-// }
-// shape = SpawnShape.valueOf(readString(reader, "shape"));
-// if (shape == SpawnShape.ellipse) {
-// edges = readBoolean(reader, "edges");
-// side = SpawnEllipseSide.valueOf(readString(reader, "side"));
-// }
-// }
-//
-
- @Override
- public SpawnShapeValue clone() {
- return (SpawnShapeValue) super.clone();
- }
-}