001 package com.croftsoft.apps.zombie;
002
003 import java.applet.*;
004 import java.awt.*;
005 import java.awt.event.*;
006 import java.io.*;
007 import java.net.*;
008 import java.util.*;
009 import javax.swing.*;
010 import javax.swing.event.*;
011
012 import com.croftsoft.core.animation.*;
013 import com.croftsoft.core.animation.animator.*;
014 import com.croftsoft.core.animation.clock.*;
015 import com.croftsoft.core.animation.component.*;
016 import com.croftsoft.core.animation.icon.*;
017 import com.croftsoft.core.animation.painter.*;
018 import com.croftsoft.core.animation.sprite.*;
019 import com.croftsoft.core.animation.updater.*;
020 import com.croftsoft.core.awt.image.ImageLib;
021 import com.croftsoft.core.lang.ClassLib;
022 import com.croftsoft.core.lang.NullArgumentException;
023 import com.croftsoft.core.lang.lifecycle.*;
024
025 /*********************************************************************
026 * Animates the zombies.
027 *
028 * @version
029 * 2003-07-17
030 * @since
031 * 2002-02-17
032 * @author
033 * <a href="https://www.croftsoft.com/">David Wallace Croft</a>
034 *********************************************************************/
035
036 public final class ZombieReanimator
037 implements Clock, ComponentAnimator, ZombieConstants
038 //////////////////////////////////////////////////////////////////////
039 //////////////////////////////////////////////////////////////////////
040 {
041
042 private final AnimatedComponent animatedComponent;
043
044 private final Random random;
045
046 private final Rectangle componentBounds;
047
048 private final Map iconMap;
049
050 private final AudioClip shotgunAudioClip;
051
052 private final AudioClip hitAudioClip;
053
054 private final AudioClip barkAudioClip;
055
056 private final Clock clock;
057
058 private final ArrayComponentUpdater arrayComponentUpdater;
059
060 private final ArrayComponentPainter arrayComponentPainter;
061
062 //
063
064 private boolean initialized;
065
066 private ZombieSprite [ ] zombies;
067
068 private boolean resetZombies;
069
070 private long updateTimeNanos;
071
072 // private ResourceImageIcon backgroundResourceImageIcon;
073
074 //////////////////////////////////////////////////////////////////////
075 //////////////////////////////////////////////////////////////////////
076
077 public ZombieReanimator ( )
078 //////////////////////////////////////////////////////////////////////
079 {
080 iconMap = new HashMap ( );
081
082 random = new Random ( );
083
084 componentBounds = new Rectangle ( );
085
086 //
087
088 URL audioURL = getClass ( ).getClassLoader ( ).getResource (
089 SHOTGUN_AUDIO_FILENAME );
090
091 shotgunAudioClip = Applet.newAudioClip ( audioURL );
092
093 audioURL = getClass ( ).getClassLoader ( ).getResource (
094 HIT_AUDIO_FILENAME );
095
096 hitAudioClip = Applet.newAudioClip ( audioURL );
097
098 audioURL = getClass ( ).getClassLoader ( ).getResource (
099 BARK_AUDIO_FILENAME );
100
101 barkAudioClip = Applet.newAudioClip ( audioURL );
102
103 //
104
105 animatedComponent
106 = new AnimatedComponent ( this, FRAME_RATE );
107
108 animatedComponent.repaint ( );
109
110 animatedComponent.addComponentListener (
111 new ComponentAdapter ( )
112 {
113 public void componentResized ( ComponentEvent e )
114 {
115 handleAnimatedComponentResize ( );
116 }
117 } );
118
119 animatedComponent.setCursor (
120 new Cursor ( Cursor.CROSSHAIR_CURSOR ) );
121
122 animatedComponent.addMouseListener (
123 new MouseAdapter ( )
124 {
125 public void mousePressed ( MouseEvent mouseEvent )
126 {
127 fire ( mouseEvent.getX ( ), mouseEvent.getY ( ) );
128 }
129 } );
130
131 clock = new HiResClock ( );
132
133 arrayComponentUpdater = new ArrayComponentUpdater ( );
134
135 arrayComponentPainter = new ArrayComponentPainter ( );
136 }
137
138 //////////////////////////////////////////////////////////////////////
139 //////////////////////////////////////////////////////////////////////
140
141 public AnimatedComponent getAnimatedComponent ( )
142 //////////////////////////////////////////////////////////////////////
143 {
144 return animatedComponent;
145 }
146
147 public Random getRandom ( )
148 //////////////////////////////////////////////////////////////////////
149 {
150 return random;
151 }
152
153 public int getComponentWidth ( )
154 //////////////////////////////////////////////////////////////////////
155 {
156 return componentBounds.width;
157 }
158
159 public int getComponentHeight ( )
160 //////////////////////////////////////////////////////////////////////
161 {
162 return componentBounds.height;
163 }
164
165 //////////////////////////////////////////////////////////////////////
166 //////////////////////////////////////////////////////////////////////
167
168 public long currentTimeNanos ( )
169 //////////////////////////////////////////////////////////////////////
170 {
171 return updateTimeNanos;
172 }
173
174 public void update ( JComponent component )
175 //////////////////////////////////////////////////////////////////////
176 {
177 if ( !initialized )
178 {
179 return;
180 }
181
182 updateTimeNanos = clock.currentTimeNanos ( );
183
184 if ( resetZombies )
185 {
186 resetZombies ( );
187 }
188
189 arrayComponentUpdater.update ( component );
190 }
191
192 public void paint (
193 JComponent component,
194 Graphics2D graphics )
195 //////////////////////////////////////////////////////////////////////
196 {
197 if ( !initialized )
198 {
199 initialize ( );
200
201 return;
202 }
203
204 arrayComponentPainter.paint ( component, graphics );
205 }
206
207 //////////////////////////////////////////////////////////////////////
208 // private methods
209 //////////////////////////////////////////////////////////////////////
210
211 private void initialize ( )
212 //////////////////////////////////////////////////////////////////////
213 {
214 /*
215 backgroundResourceImageIcon = new ResourceImageIcon (
216 BACKGROUND_IMAGE_FILENAME,
217 getClass ( ).getClassLoader ( ),
218 new Dimension ( componentBounds.getSize ( ) ),
219 animatedComponent );
220
221 arrayComponentPainter.add (
222 new IconPainter ( 0, 0, backgroundResourceImageIcon ) );
223 */
224
225 try
226 {
227 Image backgroundImage = loadAutomaticImage (
228 BACKGROUND_IMAGE_FILENAME, Transparency.OPAQUE );
229
230 arrayComponentPainter.add (
231 new IconPainter (
232 0, 0, new StretchImageIcon ( backgroundImage ) ) );
233 }
234 catch ( IOException ex )
235 {
236 ex.printStackTrace ( );
237 }
238
239 Icon [ ] zombieIcons
240 = new Icon [ ZOMBIE_IMAGE_FILENAMES.length ];
241
242 for ( int i = 0; i < ZOMBIE_IMAGE_FILENAMES.length; i++ )
243 {
244 zombieIcons [ i ]
245 = validateIcon ( ZOMBIE_IMAGE_FILENAMES [ i ] );
246 }
247
248 Clock clock = new HiResClock ( );
249
250 zombies = new ZombieSprite [ ZOMBIE_COUNT ];
251
252 for ( int i = 0; i < ZOMBIE_COUNT; i++ )
253 {
254 ZombieSprite zombie
255 = new ZombieSprite ( zombieIcons [ 0 ], this );
256
257 zombie.setComponentUpdater (
258 new ArrayComponentUpdater ( new ComponentUpdater [ ] {
259 new IconSequenceUpdater (
260 zombie, zombieIcons, 1000000000L, this ),
261 new BounceUpdater ( zombie, componentBounds, this ) } ) );
262
263 zombies [ i ] = zombie;
264
265 arrayComponentPainter.add ( zombie );
266
267 arrayComponentUpdater.add ( zombie );
268 }
269
270 resetZombies ( );
271
272 /*
273 FrameRateUpdater frameRateUpdater
274 = new FrameRateUpdater ( true );
275
276 arrayComponentUpdater.add ( frameRateUpdater );
277 */
278
279 initialized = true;
280 }
281
282 // shift this reusable code to another class (ImageIconCache?)
283 private Icon validateIcon ( String imageFilename )
284 //////////////////////////////////////////////////////////////////////
285 {
286 Icon icon = ( Icon ) iconMap.get ( imageFilename );
287
288 if ( icon == null )
289 {
290 Image image = null;
291
292 try
293 {
294 image
295 = loadAutomaticImage ( imageFilename, Transparency.BITMASK );
296 }
297 catch ( IOException ex )
298 {
299 ex.printStackTrace ( );
300 }
301
302 if ( image == null )
303 {
304 return null;
305 }
306
307 icon = new ImageIcon ( image );
308
309 iconMap.put ( imageFilename, icon );
310 }
311
312 return icon;
313 }
314
315 private void handleAnimatedComponentResize ( )
316 //////////////////////////////////////////////////////////////////////
317 {
318 animatedComponent.getBounds ( componentBounds );
319
320 /*
321 ResourceImageIcon backgroundResourceImageIcon
322 = this.backgroundResourceImageIcon;
323
324 if ( backgroundResourceImageIcon != null )
325 {
326 backgroundResourceImageIcon.setSize (
327 componentBounds.getSize ( ) );
328 }
329 */
330 }
331
332 private void fire ( int x, int y )
333 //////////////////////////////////////////////////////////////////////
334 {
335 shotgunAudioClip.play ( );
336
337 boolean allZombiesDestroyed = true;
338
339 for ( int i = ZOMBIE_COUNT - 1; i >= 0; i-- )
340 {
341 ZombieSprite zombie = zombies [ i ];
342
343 if ( !zombie.isDestroyed ( ) )
344 {
345 allZombiesDestroyed = false;
346
347 if ( zombie.getCollisionShape ( ).contains ( x, y ) )
348 {
349 hitAudioClip.play ( );
350
351 zombie.setHit ( );
352
353 break;
354 }
355 }
356 }
357
358 resetZombies = allZombiesDestroyed;
359 }
360
361 private Image loadAutomaticImage (
362 String imageFilename,
363 int transparency )
364 throws IOException
365 //////////////////////////////////////////////////////////////////////
366 {
367 return ImageLib.loadAutomaticImage (
368 imageFilename,
369 transparency,
370 animatedComponent,
371 getClass ( ).getClassLoader ( ),
372 null );
373 }
374
375 private void resetZombies ( )
376 //////////////////////////////////////////////////////////////////////
377 {
378 resetZombies = false;
379
380 barkAudioClip.play ( );
381
382 for ( int i = 0; i < ZOMBIE_COUNT; i++ )
383 {
384 zombies [ i ].reset ( );
385 }
386 }
387
388 //////////////////////////////////////////////////////////////////////
389 //////////////////////////////////////////////////////////////////////
390 }