• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  * Copyright 2011 See AUTHORS file.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  ******************************************************************************/
16 
17 package com.badlogic.gdx.graphics.g2d;
18 
19 import java.io.BufferedReader;
20 import java.io.File;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.InputStreamReader;
24 import java.io.Writer;
25 import java.util.HashMap;
26 
27 import com.badlogic.gdx.files.FileHandle;
28 import com.badlogic.gdx.graphics.Texture;
29 import com.badlogic.gdx.math.collision.BoundingBox;
30 import com.badlogic.gdx.utils.Array;
31 import com.badlogic.gdx.utils.Disposable;
32 import com.badlogic.gdx.utils.GdxRuntimeException;
33 import com.badlogic.gdx.utils.StreamUtils;
34 
35 /** See <a href="http://www.badlogicgames.com/wordpress/?p=1255">http://www.badlogicgames.com/wordpress/?p=1255</a>
36  * @author mzechner */
37 public class ParticleEffect implements Disposable {
38 	private final Array<ParticleEmitter> emitters;
39 	private BoundingBox bounds;
40 	private boolean ownsTexture;
41 
ParticleEffect()42 	public ParticleEffect () {
43 		emitters = new Array(8);
44 	}
45 
ParticleEffect(ParticleEffect effect)46 	public ParticleEffect (ParticleEffect effect) {
47 		emitters = new Array(true, effect.emitters.size);
48 		for (int i = 0, n = effect.emitters.size; i < n; i++)
49 			emitters.add(new ParticleEmitter(effect.emitters.get(i)));
50 	}
51 
start()52 	public void start () {
53 		for (int i = 0, n = emitters.size; i < n; i++)
54 			emitters.get(i).start();
55 	}
56 
reset()57 	public void reset () {
58 		for (int i = 0, n = emitters.size; i < n; i++)
59 			emitters.get(i).reset();
60 	}
61 
update(float delta)62 	public void update (float delta) {
63 		for (int i = 0, n = emitters.size; i < n; i++)
64 			emitters.get(i).update(delta);
65 	}
66 
draw(Batch spriteBatch)67 	public void draw (Batch spriteBatch) {
68 		for (int i = 0, n = emitters.size; i < n; i++)
69 			emitters.get(i).draw(spriteBatch);
70 	}
71 
draw(Batch spriteBatch, float delta)72 	public void draw (Batch spriteBatch, float delta) {
73 		for (int i = 0, n = emitters.size; i < n; i++)
74 			emitters.get(i).draw(spriteBatch, delta);
75 	}
76 
allowCompletion()77 	public void allowCompletion () {
78 		for (int i = 0, n = emitters.size; i < n; i++)
79 			emitters.get(i).allowCompletion();
80 	}
81 
isComplete()82 	public boolean isComplete () {
83 		for (int i = 0, n = emitters.size; i < n; i++) {
84 			ParticleEmitter emitter = emitters.get(i);
85 			if (!emitter.isComplete()) return false;
86 		}
87 		return true;
88 	}
89 
setDuration(int duration)90 	public void setDuration (int duration) {
91 		for (int i = 0, n = emitters.size; i < n; i++) {
92 			ParticleEmitter emitter = emitters.get(i);
93 			emitter.setContinuous(false);
94 			emitter.duration = duration;
95 			emitter.durationTimer = 0;
96 		}
97 	}
98 
setPosition(float x, float y)99 	public void setPosition (float x, float y) {
100 		for (int i = 0, n = emitters.size; i < n; i++)
101 			emitters.get(i).setPosition(x, y);
102 	}
103 
setFlip(boolean flipX, boolean flipY)104 	public void setFlip (boolean flipX, boolean flipY) {
105 		for (int i = 0, n = emitters.size; i < n; i++)
106 			emitters.get(i).setFlip(flipX, flipY);
107 	}
108 
flipY()109 	public void flipY () {
110 		for (int i = 0, n = emitters.size; i < n; i++)
111 			emitters.get(i).flipY();
112 	}
113 
getEmitters()114 	public Array<ParticleEmitter> getEmitters () {
115 		return emitters;
116 	}
117 
118 	/** Returns the emitter with the specified name, or null. */
findEmitter(String name)119 	public ParticleEmitter findEmitter (String name) {
120 		for (int i = 0, n = emitters.size; i < n; i++) {
121 			ParticleEmitter emitter = emitters.get(i);
122 			if (emitter.getName().equals(name)) return emitter;
123 		}
124 		return null;
125 	}
126 
save(Writer output)127 	public void save (Writer output) throws IOException {
128 		int index = 0;
129 		for (int i = 0, n = emitters.size; i < n; i++) {
130 			ParticleEmitter emitter = emitters.get(i);
131 			if (index++ > 0) output.write("\n\n");
132 			emitter.save(output);
133 		}
134 	}
135 
load(FileHandle effectFile, FileHandle imagesDir)136 	public void load (FileHandle effectFile, FileHandle imagesDir) {
137 		loadEmitters(effectFile);
138 		loadEmitterImages(imagesDir);
139 	}
140 
load(FileHandle effectFile, TextureAtlas atlas)141 	public void load (FileHandle effectFile, TextureAtlas atlas) {
142 		load(effectFile, atlas, null);
143 	}
144 
load(FileHandle effectFile, TextureAtlas atlas, String atlasPrefix)145 	public void load (FileHandle effectFile, TextureAtlas atlas, String atlasPrefix) {
146 		loadEmitters(effectFile);
147 		loadEmitterImages(atlas, atlasPrefix);
148 	}
149 
loadEmitters(FileHandle effectFile)150 	public void loadEmitters (FileHandle effectFile) {
151 		InputStream input = effectFile.read();
152 		emitters.clear();
153 		BufferedReader reader = null;
154 		try {
155 			reader = new BufferedReader(new InputStreamReader(input), 512);
156 			while (true) {
157 				ParticleEmitter emitter = new ParticleEmitter(reader);
158 				emitters.add(emitter);
159 				if (reader.readLine() == null) break;
160 				if (reader.readLine() == null) break;
161 			}
162 		} catch (IOException ex) {
163 			throw new GdxRuntimeException("Error loading effect: " + effectFile, ex);
164 		} finally {
165 			StreamUtils.closeQuietly(reader);
166 		}
167 	}
168 
loadEmitterImages(TextureAtlas atlas)169 	public void loadEmitterImages (TextureAtlas atlas) {
170 		loadEmitterImages(atlas, null);
171 	}
172 
loadEmitterImages(TextureAtlas atlas, String atlasPrefix)173 	public void loadEmitterImages (TextureAtlas atlas, String atlasPrefix) {
174 		for (int i = 0, n = emitters.size; i < n; i++) {
175 			ParticleEmitter emitter = emitters.get(i);
176 			String imagePath = emitter.getImagePath();
177 			if (imagePath == null) continue;
178 			String imageName = new File(imagePath.replace('\\', '/')).getName();
179 			int lastDotIndex = imageName.lastIndexOf('.');
180 			if (lastDotIndex != -1) imageName = imageName.substring(0, lastDotIndex);
181 			if (atlasPrefix != null) imageName = atlasPrefix + imageName;
182 			Sprite sprite = atlas.createSprite(imageName);
183 			if (sprite == null) throw new IllegalArgumentException("SpriteSheet missing image: " + imageName);
184 			emitter.setSprite(sprite);
185 		}
186 	}
187 
loadEmitterImages(FileHandle imagesDir)188 	public void loadEmitterImages (FileHandle imagesDir) {
189 		ownsTexture = true;
190 		HashMap<String, Sprite> loadedSprites = new HashMap<String, Sprite>(emitters.size);
191 		for (int i = 0, n = emitters.size; i < n; i++) {
192 			ParticleEmitter emitter = emitters.get(i);
193 			String imagePath = emitter.getImagePath();
194 			if (imagePath == null) continue;
195 			String imageName = new File(imagePath.replace('\\', '/')).getName();
196 			Sprite sprite = loadedSprites.get(imageName);
197 			if (sprite == null) {
198 				sprite = new Sprite(loadTexture(imagesDir.child(imageName)));
199 				loadedSprites.put(imageName, sprite);
200 			}
201 			emitter.setSprite(sprite);
202 		}
203 	}
204 
loadTexture(FileHandle file)205 	protected Texture loadTexture (FileHandle file) {
206 		return new Texture(file, false);
207 	}
208 
209 	/** Disposes the texture for each sprite for each ParticleEmitter. */
dispose()210 	public void dispose () {
211 		if (!ownsTexture) return;
212 		for (int i = 0, n = emitters.size; i < n; i++) {
213 			ParticleEmitter emitter = emitters.get(i);
214 			emitter.getSprite().getTexture().dispose();
215 		}
216 	}
217 
218 	/** Returns the bounding box for all active particles. z axis will always be zero. */
getBoundingBox()219 	public BoundingBox getBoundingBox () {
220 		if (bounds == null) bounds = new BoundingBox();
221 
222 		BoundingBox bounds = this.bounds;
223 		bounds.inf();
224 		for (ParticleEmitter emitter : this.emitters)
225 			bounds.ext(emitter.getBoundingBox());
226 		return bounds;
227 	}
228 
scaleEffect(float scaleFactor)229 	public void scaleEffect (float scaleFactor) {
230 		for (ParticleEmitter particleEmitter : emitters) {
231 			particleEmitter.getScale().setHigh(particleEmitter.getScale().getHighMin() * scaleFactor,
232 				particleEmitter.getScale().getHighMax() * scaleFactor);
233 			particleEmitter.getScale().setLow(particleEmitter.getScale().getLowMin() * scaleFactor,
234 				particleEmitter.getScale().getLowMax() * scaleFactor);
235 
236 			particleEmitter.getVelocity().setHigh(particleEmitter.getVelocity().getHighMin() * scaleFactor,
237 				particleEmitter.getVelocity().getHighMax() * scaleFactor);
238 			particleEmitter.getVelocity().setLow(particleEmitter.getVelocity().getLowMin() * scaleFactor,
239 				particleEmitter.getVelocity().getLowMax() * scaleFactor);
240 
241 			particleEmitter.getGravity().setHigh(particleEmitter.getGravity().getHighMin() * scaleFactor,
242 				particleEmitter.getGravity().getHighMax() * scaleFactor);
243 			particleEmitter.getGravity().setLow(particleEmitter.getGravity().getLowMin() * scaleFactor,
244 				particleEmitter.getGravity().getLowMax() * scaleFactor);
245 
246 			particleEmitter.getWind().setHigh(particleEmitter.getWind().getHighMin() * scaleFactor,
247 				particleEmitter.getWind().getHighMax() * scaleFactor);
248 			particleEmitter.getWind().setLow(particleEmitter.getWind().getLowMin() * scaleFactor,
249 				particleEmitter.getWind().getLowMax() * scaleFactor);
250 
251 			particleEmitter.getSpawnWidth().setHigh(particleEmitter.getSpawnWidth().getHighMin() * scaleFactor,
252 				particleEmitter.getSpawnWidth().getHighMax() * scaleFactor);
253 			particleEmitter.getSpawnWidth().setLow(particleEmitter.getSpawnWidth().getLowMin() * scaleFactor,
254 				particleEmitter.getSpawnWidth().getLowMax() * scaleFactor);
255 
256 			particleEmitter.getSpawnHeight().setHigh(particleEmitter.getSpawnHeight().getHighMin() * scaleFactor,
257 				particleEmitter.getSpawnHeight().getHighMax() * scaleFactor);
258 			particleEmitter.getSpawnHeight().setLow(particleEmitter.getSpawnHeight().getLowMin() * scaleFactor,
259 				particleEmitter.getSpawnHeight().getLowMax() * scaleFactor);
260 
261 			particleEmitter.getXOffsetValue().setLow(particleEmitter.getXOffsetValue().getLowMin() * scaleFactor,
262 				particleEmitter.getXOffsetValue().getLowMax() * scaleFactor);
263 
264 			particleEmitter.getYOffsetValue().setLow(particleEmitter.getYOffsetValue().getLowMin() * scaleFactor,
265 				particleEmitter.getYOffsetValue().getLowMax() * scaleFactor);
266 		}
267 	}
268 
269 	/** Sets the {@link com.badlogic.gdx.graphics.g2d.ParticleEmitter#setCleansUpBlendFunction(boolean) cleansUpBlendFunction}
270 	 * parameter on all {@link com.badlogic.gdx.graphics.g2d.ParticleEmitter ParticleEmitters} currently in this ParticleEffect.
271 	 * <p>
272 	 * IMPORTANT: If set to false and if the next object to use this Batch expects alpha blending, you are responsible for setting
273 	 * the Batch's blend function to (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) before that next object is drawn.
274 	 * @param cleanUpBlendFunction */
setEmittersCleanUpBlendFunction(boolean cleanUpBlendFunction)275 	public void setEmittersCleanUpBlendFunction (boolean cleanUpBlendFunction) {
276 		for (int i = 0, n = emitters.size; i < n; i++) {
277 			emitters.get(i).setCleansUpBlendFunction(cleanUpBlendFunction);
278 		}
279 	}
280 }
281