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 }