OSDN Git Service

[fixed] LwjglApplication had large first delta.
authornathan.sweet <nathan.sweet@6c4fd544-2939-11df-bb46-9574ba5d0bfa>
Mon, 1 Nov 2010 10:30:17 +0000 (10:30 +0000)
committernathan.sweet <nathan.sweet@6c4fd544-2939-11df-bb46-9574ba5d0bfa>
Mon, 1 Nov 2010 10:30:17 +0000 (10:30 +0000)
[changed] ParticleEmitter to be slightly more efficient. Still no javadoc, I didn't forget.
[changed] Sprite javadocs. Added empty constructor.

backends/gdx-backend-lwjgl/src/com/badlogic/gdx/backends/desktop/LwjglApplication.java
backends/gdx-backend-lwjgl/src/com/badlogic/gdx/backends/desktop/LwjglGraphics.java
extensions/particle-editor/src/com/badlogic/gdx/graphics/particles/EffectPanel.java
extensions/twl/gdx-twl-tests/src/com/badlogic/gdx/twl/tests/TextAreaTest.java
gdx/src/com/badlogic/gdx/graphics/OrthographicCamera.java
gdx/src/com/badlogic/gdx/graphics/Sprite.java
gdx/src/com/badlogic/gdx/graphics/SpriteBatch.java
gdx/src/com/badlogic/gdx/graphics/particles/ParticleEffect.java
gdx/src/com/badlogic/gdx/graphics/particles/ParticleEmitter.java

index 847d9a3..657c0ed 100644 (file)
@@ -177,6 +177,7 @@ import com.badlogic.gdx.utils.GdxRuntimeException;
                for (RenderListener listener : listeners)\r
                        listener.surfaceCreated();\r
                setSize(width, height);\r
+               graphics.lastTime = System.nanoTime();\r
                for (RenderListener listener : listeners)\r
                        listener.render();\r
 \r
index afd147d..d73ba1a 100644 (file)
@@ -44,12 +44,13 @@ public final class LwjglGraphics implements Graphics, RenderListener {
        private GL11 gl11;\r
        private GL20 gl20;\r
        private final boolean useGL2;\r
-       private long lastTime;\r
        private float deltaTime = 0;\r
        private long frameStart = 0;\r
        private int frames = 0;\r
        private int fps;\r
 \r
+       long lastTime;\r
+\r
        LwjglGraphics (final LwjglApplication application, String title, int width, int height, boolean useGL2IfAvailable) {\r
                this.app = application;\r
                useGL2 = useGL2IfAvailable;\r
@@ -180,8 +181,6 @@ public final class LwjglGraphics implements Graphics, RenderListener {
                Gdx.gl10 = gl10;\r
                Gdx.gl11 = gl11;\r
                Gdx.gl20 = gl20;\r
-\r
-               lastTime = System.nanoTime();\r
        }\r
 \r
        public float getDeltaTime () {\r
index 527e172..8043e6c 100644 (file)
@@ -40,6 +40,31 @@ class EffectPanel extends JPanel {
 \r
        public ParticleEmitter newEmitter (String name, boolean select) {\r
                final ParticleEmitter emitter = new ParticleEmitter();\r
+\r
+               emitter.getDuration().setLow(3000, 3000);\r
+\r
+               emitter.getEmission().setHigh(10, 10);\r
+\r
+               emitter.getLife().setHigh(1000, 1000);\r
+\r
+               emitter.getScale().setHigh(32, 32);\r
+\r
+               emitter.getRotation().setLow(1, 360);\r
+               emitter.getRotation().setHigh(180, 180);\r
+               emitter.getRotation().setTimeline(new float[] {0, 1});\r
+               emitter.getRotation().setScaling(new float[] {0, 1});\r
+               emitter.getRotation().setRelative(true);\r
+\r
+               emitter.getAngle().setHigh(1, 360);\r
+               emitter.getAngle().setActive(true);\r
+\r
+               emitter.getVelocity().setHigh(80, 80);\r
+               emitter.getVelocity().setActive(true);\r
+\r
+               emitter.getTransparency().setHigh(1, 1);\r
+               emitter.getTransparency().setTimeline(new float[] {0, 0.2f, 0.8f, 1});\r
+               emitter.getTransparency().setScaling(new float[] {0, 1, 1, 0});\r
+\r
                emitter.setFlip(false, true);\r
                emitter.setMaxParticleCount(15);\r
                emitter.setImagePath("data/particle.png");\r
index 33aa324..c74b509 100644 (file)
@@ -64,6 +64,7 @@ public class TextAreaTest implements RenderListener {
                                }\r
                                if (timer.isRunning()) return;\r
                                timer.start();\r
+                               System.out.println();\r
                                speed = -speed;\r
                        }\r
                });\r
index 385c29c..2660a23 100644 (file)
@@ -147,7 +147,6 @@ public final class OrthographicCamera {
         */\r
        public void update () {\r
                proj.setToOrtho2D(0, 0, (viewportWidth * scale), (viewportHeight * scale), near, far);\r
-               model.idt();\r
                model.setToTranslation(tmp.set((-position.x + (viewportWidth / 2) * scale), (-position.y + (viewportHeight / 2) * scale),\r
                        (-position.z)));\r
                combined.set(proj);\r
index 03f5075..f8c37d9 100644 (file)
@@ -27,6 +27,13 @@ public class Sprite {
        private boolean dirty;\r
 \r
        /**\r
+        * Creates an uninitialized sprite. The sprite will need a texture, texture region, bounds, and color set before it can be\r
+        * drawn.\r
+        */\r
+       public Sprite () {\r
+       }\r
+\r
+       /**\r
         * Creates a sprite with width, height, and texture region equal to the size of the texture.\r
         */\r
        public Sprite (Texture texture) {\r
@@ -36,6 +43,8 @@ public class Sprite {
        /**\r
         * Creates a sprite with width, height, and texture region equal to the specified size. The texture region's upper left corner\r
         * will be 0,0.\r
+        * @param srcWidth The width of the texture region. May be negative to flip the sprite when drawn.\r
+        * @param srcHeight The height of the texture region. May be negative to flip the sprite when drawn.\r
         */\r
        public Sprite (Texture texture, int srcWidth, int srcHeight) {\r
                this(texture, 0, 0, srcWidth, srcHeight);\r
@@ -43,19 +52,23 @@ public class Sprite {
 \r
        /**\r
         * Creates a sprite with width, height, and texture region equal to the specified size.\r
+        * @param srcWidth The width of the texture region. May be negative to flip the sprite when drawn.\r
+        * @param srcHeight The height of the texture region. May be negative to flip the sprite when drawn.\r
         */\r
        public Sprite (Texture texture, int srcX, int srcY, int srcWidth, int srcHeight) {\r
                if (texture == null) throw new IllegalArgumentException("texture cannot be null.");\r
                this.texture = texture;\r
                setTextureRegion(srcX, srcY, srcWidth, srcHeight);\r
                setColor(1, 1, 1, 1);\r
-               setBounds(0, 0, Math.abs(srcWidth), Math.abs(srcHeight));\r
+               setSize(Math.abs(srcWidth), Math.abs(srcHeight));\r
                setOrigin(width / 2, height / 2);\r
        }\r
 \r
        /**\r
         * Creates a sprite with width, height, and texture region equal to the specified size, relative to specified sprite's texture\r
         * region.\r
+        * @param srcWidth The width of the texture region. May be negative to flip the sprite when drawn.\r
+        * @param srcHeight The height of the texture region. May be negative to flip the sprite when drawn.\r
         */\r
        public Sprite (Sprite parent, int srcX, int srcY, int srcWidth, int srcHeight) {\r
                this(parent.texture, (int)(srcX + parent.vertices[U1] * parent.texture.getWidth()), (int)(srcY + parent.vertices[V2]\r
@@ -63,8 +76,8 @@ public class Sprite {
        }\r
 \r
        /**\r
-        * Sets the size and position of the sprite when drawn, before scaling and rotation are applied. If origin, rotation, or scale\r
-        * are changed, it is slightly more efficient to set the bounds afterward.\r
+        * Sets the position and size of the sprite when drawn, before scaling and rotation are applied. If origin, rotation, or scale\r
+        * are changed, it is slightly more efficient to set the bounds after those operations.\r
         */\r
        public void setBounds (float x, float y, float width, float height) {\r
                this.x = x;\r
@@ -94,8 +107,8 @@ public class Sprite {
 \r
        /**\r
         * Sets the size of the sprite when drawn, before scaling and rotation are applied. If origin, rotation, or scale are changed,\r
-        * it is slightly more efficient to set the size afterward. If both position and size are to be changed, it is better to use\r
-        * {@link #setBounds(float, float, float, float)}.\r
+        * it is slightly more efficient to set the size after those operations. If both position and size are to be changed, it is\r
+        * better to use {@link #setBounds(float, float, float, float)}.\r
         */\r
        public void setSize (float width, float height) {\r
                this.width = width;\r
@@ -123,7 +136,7 @@ public class Sprite {
 \r
        /**\r
         * Sets the position where the sprite will be drawn. If origin, rotation, or scale are changed, it is slightly more efficient\r
-        * to set the position afterward. If both position and size are to be changed, it is better to use\r
+        * to set the position after those operations. If both position and size are to be changed, it is better to use\r
         * {@link #setBounds(float, float, float, float)}.\r
         */\r
        public void setPosition (float x, float y) {\r
@@ -132,7 +145,7 @@ public class Sprite {
 \r
        /**\r
         * Sets the position relative to the current position where the sprite will be drawn. If origin, rotation, or scale are\r
-        * changed, it is slightly more efficient to translate afterward.\r
+        * changed, it is slightly more efficient to translate after those operations.\r
         */\r
        public void translate (float xAmount, float yAmount) {\r
                x += xAmount;\r
@@ -155,7 +168,9 @@ public class Sprite {
        }\r
 \r
        /**\r
-        * Sets the texture coordinates in pixels to apply to the sprite.\r
+        * Sets the texture coordinates in pixels to apply to the sprite. This resets calling {@link #flip(boolean, boolean)}.\r
+        * @param srcWidth The width of the texture region. May be negative to flip the sprite when drawn.\r
+        * @param srcHeight The height of the texture region. May be negative to flip the sprite when drawn.\r
         */\r
        public void setTextureRegion (int srcX, int srcY, int srcWidth, int srcHeight) {\r
                float invTexWidth = 1.0f / texture.getWidth();\r
@@ -192,7 +207,7 @@ public class Sprite {
        }\r
 \r
        /**\r
-        * Flips the texture.\r
+        * Flips the current texture region.\r
         */\r
        public void flip (boolean x, boolean y) {\r
                float[] vertices = this.vertices;\r
index 92539cc..30d47ee 100644 (file)
@@ -200,6 +200,7 @@ public class SpriteBatch {
         * @param transform the transformation matrix.\r
         */\r
        public void begin () {\r
+               if (drawing) throw new IllegalStateException("you have to call SpriteBatch.end() first");\r
                renderCalls = 0;        \r
                \r
                if (Gdx.graphics.isGL20Available() == false) {\r
@@ -243,6 +244,7 @@ public class SpriteBatch {
         * Finishes off rendering of the last batch of sprites\r
         */\r
        public void end () {\r
+               if (!drawing) throw new IllegalStateException("you have to call SpriteBatch.begin() first");\r
                if (idx > 0) renderMesh();\r
                lastTexture = null;\r
                idx = 0;\r
index 0437241..44b3ebb 100644 (file)
@@ -14,12 +14,11 @@ import com.badlogic.gdx.Files.FileType;
 import com.badlogic.gdx.Gdx;\r
 import com.badlogic.gdx.files.FileHandle;\r
 import com.badlogic.gdx.graphics.SpriteBatch;\r
+import com.badlogic.gdx.graphics.Texture;\r
 import com.badlogic.gdx.graphics.Texture.TextureFilter;\r
 import com.badlogic.gdx.graphics.Texture.TextureWrap;\r
 import com.badlogic.gdx.utils.GdxRuntimeException;\r
 \r
-// BOZO - Cache particle images? Or add hook to customize loading of particle images?\r
-\r
 public class ParticleEffect {\r
        private ArrayList<ParticleEmitter> emitters = new ArrayList();\r
 \r
@@ -129,8 +128,12 @@ public class ParticleEffect {
                        if (imagePath == null) continue;\r
                        imagePath = imagePath.replace('\\', '/');\r
                        imagePath = imagesDir + new File(imagePath).getName();\r
-                       emitter.setTexture(Gdx.graphics.newTexture(Gdx.files.getFileHandle(imagePath, fileType), TextureFilter.Linear,\r
-                               TextureFilter.Linear, TextureWrap.ClampToEdge, TextureWrap.ClampToEdge));\r
+                       emitter.setTexture(loadTexture(Gdx.files.getFileHandle(imagePath, fileType)));\r
                }\r
        }\r
+\r
+       protected Texture loadTexture (FileHandle file) {\r
+               return Gdx.graphics.newTexture(file, TextureFilter.Linear, TextureFilter.Linear, TextureWrap.ClampToEdge,\r
+                       TextureWrap.ClampToEdge);\r
+       }\r
 }\r
index d2910f2..d47bbc2 100644 (file)
@@ -4,7 +4,6 @@ package com.badlogic.gdx.graphics.particles;
 import java.io.BufferedReader;\r
 import java.io.IOException;\r
 import java.io.Writer;\r
-import java.math.BigInteger;\r
 import java.util.BitSet;\r
 \r
 import com.badlogic.gdx.graphics.GL10;\r
@@ -13,7 +12,7 @@ import com.badlogic.gdx.graphics.SpriteBatch;
 import com.badlogic.gdx.graphics.Texture;\r
 import com.badlogic.gdx.utils.MathUtils;\r
 \r
-// BOZO - Support point particles?\r
+// BOZO - Javadoc.\r
 // BOZO - Add a duplicate emitter button.\r
 \r
 public class ParticleEmitter {\r
@@ -57,9 +56,9 @@ public class ParticleEmitter {
        private boolean flipX, flipY;\r
        private int updateFlags;\r
 \r
-       private float emission, emissionDiff, emissionDelta;\r
-       private float lifeOffset, lifeOffsetDiff;\r
-       private float life, lifeDiff;\r
+       private int emission, emissionDiff, emissionDelta;\r
+       private int lifeOffset, lifeOffsetDiff;\r
+       private int life, lifeDiff;\r
        private int spawnWidth, spawnWidthDiff;\r
        private int spawnHeight, spawnHeightDiff;\r
        public float duration = 1, durationTimer;\r
@@ -72,37 +71,7 @@ public class ParticleEmitter {
        private boolean additive = true;\r
 \r
        public ParticleEmitter () {\r
-               this((Texture)null);\r
-       }\r
-\r
-       public ParticleEmitter (Texture texture) {\r
-               this.texture = texture;\r
-\r
                initialize();\r
-\r
-               durationValue.setLow(3, 3);\r
-\r
-               emissionValue.setHigh(10, 10);\r
-\r
-               lifeValue.setHigh(1, 1);\r
-\r
-               scaleValue.setHigh(32, 32);\r
-\r
-               rotationValue.setLow(1, 360);\r
-               rotationValue.setHigh(180, 180);\r
-               rotationValue.setTimeline(new float[] {0, 1});\r
-               rotationValue.setScaling(new float[] {0, 1});\r
-               rotationValue.setRelative(true);\r
-\r
-               angleValue.setHigh(1, 360);\r
-               angleValue.setActive(true);\r
-\r
-               velocityValue.setHigh(80, 80);\r
-               velocityValue.setActive(true);\r
-\r
-               transparencyValue.setHigh(1, 1);\r
-               transparencyValue.setTimeline(new float[] {0, 0.2f, 0.8f, 1});\r
-               transparencyValue.setScaling(new float[] {0, 1, 1, 0});\r
        }\r
 \r
        public ParticleEmitter (BufferedReader reader) throws IOException {\r
@@ -182,6 +151,7 @@ public class ParticleEmitter {
 \r
        public void draw (SpriteBatch spriteBatch, float delta) {\r
                delta = Math.min(delta, 0.250f);\r
+               int deltaMillis = (int)(delta * 1000);\r
 \r
                if (additive) spriteBatch.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE);\r
 \r
@@ -191,7 +161,7 @@ public class ParticleEmitter {
                while (true) {\r
                        index = active.nextSetBit(index);\r
                        if (index == -1) break;\r
-                       if (updateParticle(index, delta))\r
+                       if (updateParticle(index, delta, deltaMillis))\r
                                particles[index].draw(spriteBatch);\r
                        else {\r
                                active.clear(index);\r
@@ -204,7 +174,7 @@ public class ParticleEmitter {
                if (additive) spriteBatch.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);\r
 \r
                if (delayTimer < delay) {\r
-                       delayTimer += delta;\r
+                       delayTimer += deltaMillis;\r
                        return;\r
                }\r
 \r
@@ -214,16 +184,16 @@ public class ParticleEmitter {
                }\r
 \r
                if (durationTimer < duration)\r
-                       durationTimer += delta;\r
+                       durationTimer += deltaMillis;\r
                else {\r
                        if (!continuous) return;\r
                        restart();\r
                }\r
 \r
-               emissionDelta += delta;\r
+               emissionDelta += deltaMillis;\r
                float emissionTime = emission + emissionDiff * emissionValue.getScale(durationTimer / (float)duration);\r
                if (emissionTime > 0) {\r
-                       emissionTime = 1 / emissionTime;\r
+                       emissionTime = 1000 / emissionTime;\r
                        if (emissionDelta >= emissionTime) {\r
                                int emitCount = (int)(emissionDelta / emissionTime);\r
                                emitCount = Math.min(emitCount, maxParticleCount - activeCount);\r
@@ -247,16 +217,16 @@ public class ParticleEmitter {
                durationTimer -= duration;\r
                duration = durationValue.newLowValue();\r
 \r
-               emission = emissionValue.newLowValue();\r
-               emissionDiff = emissionValue.newHighValue();\r
+               emission = (int)emissionValue.newLowValue();\r
+               emissionDiff = (int)emissionValue.newHighValue();\r
                if (!emissionValue.isRelative()) emissionDiff -= emission;\r
 \r
-               life = lifeValue.newLowValue();\r
-               lifeDiff = lifeValue.newHighValue();\r
+               life = (int)lifeValue.newLowValue();\r
+               lifeDiff = (int)lifeValue.newHighValue();\r
                if (!lifeValue.isRelative()) lifeDiff -= life;\r
 \r
-               lifeOffset = lifeOffsetValue.active ? lifeOffsetValue.newLowValue() : 0;\r
-               lifeOffsetDiff = lifeOffsetValue.newHighValue();\r
+               lifeOffset = lifeOffsetValue.active ? (int)lifeOffsetValue.newLowValue() : 0;\r
+               lifeOffsetDiff = (int)lifeOffsetValue.newHighValue();\r
                if (!lifeOffsetValue.isRelative()) lifeOffsetDiff -= lifeOffset;\r
 \r
                spawnWidth = (int)spawnWidthValue.newLowValue();\r
@@ -277,7 +247,7 @@ public class ParticleEmitter {
                if (tintValue.timeline.length > 1) updateFlags |= UPDATE_TINT;\r
        }\r
 \r
-       public void activateParticle (int index) {\r
+       private void activateParticle (int index) {\r
                Particle particle = particles[index];\r
                if (particle == null) {\r
                        particles[index] = particle = new Particle(texture);\r
@@ -288,7 +258,7 @@ public class ParticleEmitter {
                int updateFlags = this.updateFlags;\r
 \r
                float offsetTime = lifeOffset + lifeOffsetDiff * lifeOffsetValue.getScale(percent);\r
-               particle.life = particle.currentLife = life + lifeDiff * lifeValue.getScale(percent);\r
+               particle.life = particle.currentLife = life + (int)(lifeDiff * lifeValue.getScale(percent));\r
 \r
                if (velocityValue.active) {\r
                        particle.velocity = velocityValue.newLowValue();\r
@@ -299,7 +269,12 @@ public class ParticleEmitter {
                particle.angle = angleValue.newLowValue();\r
                particle.angleDiff = angleValue.newHighValue();\r
                if (!angleValue.isRelative()) particle.angleDiff -= particle.angle;\r
-               if ((updateFlags & UPDATE_ANGLE) == 0) particle.angle = particle.angle + particle.angleDiff * angleValue.getScale(0);\r
+               if ((updateFlags & UPDATE_ANGLE) == 0) {\r
+                       float 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
                particle.scale = scaleValue.newLowValue() / texture.getWidth();\r
                particle.scaleDiff = scaleValue.newHighValue() / texture.getWidth();\r
@@ -402,36 +377,51 @@ public class ParticleEmitter {
                particle.setBounds(x - texture.getWidth() / 2, y - texture.getHeight() / 2, texture.getWidth(), texture.getHeight());\r
        }\r
 \r
-       public boolean updateParticle (int index, float delta) {\r
+       private boolean updateParticle (int index, float delta, int deltaMillis) {\r
                Particle particle = particles[index];\r
-               float life = particle.currentLife - delta;\r
+               int life = particle.currentLife - deltaMillis;\r
                if (life <= 0) return false;\r
                particle.currentLife = life;\r
 \r
-               float percent = 1 - particle.currentLife / 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(percent));\r
 \r
-               float angle = particle.angle;\r
-               if ((updateFlags & UPDATE_ANGLE) != 0) angle += particle.angleDiff * angleValue.getScale(percent);\r
-\r
-               if ((updateFlags & UPDATE_ROTATION) != 0) {\r
-                       float rotation = particle.rotation + particle.rotationDiff * rotationValue.getScale(percent);\r
-                       if (aligned) rotation += angle;\r
-                       if (rotation != 0) particle.setRotation(rotation);\r
-               }\r
-\r
                if ((updateFlags & UPDATE_VELOCITY) != 0) {\r
                        float velocity = (particle.velocity + particle.velocityDiff * velocityValue.getScale(percent)) * delta;\r
-                       float velocityX = velocity * MathUtils.cosDeg(angle);\r
-                       float velocityY = velocity * MathUtils.sinDeg(angle);\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 ((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
@@ -702,52 +692,57 @@ public class ParticleEmitter {
        }\r
 \r
        public void load (BufferedReader reader) throws IOException {\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
+               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
@@ -769,11 +764,12 @@ public class ParticleEmitter {
        }\r
 \r
        static class Particle extends Sprite {\r
-               float life, currentLife;\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