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         }