001 package com.croftsoft.apps.shooter; 002 003 import java.applet.*; 004 import java.awt.*; 005 import java.awt.event.*; 006 import java.awt.geom.*; 007 import java.io.*; 008 import java.net.URL; 009 import java.util.*; 010 import javax.swing.*; 011 import javax.swing.event.*; 012 013 import com.croftsoft.core.CroftSoftConstants; 014 import com.croftsoft.core.animation.AnimatedComponent; 015 import com.croftsoft.core.animation.ComponentAnimator; 016 import com.croftsoft.core.animation.Sprite; 017 import com.croftsoft.core.animation.animator.TileAnimator; 018 import com.croftsoft.core.animation.clock.SystemClock; 019 import com.croftsoft.core.animation.painter.SpacePainter; 020 import com.croftsoft.core.animation.sprite.IconSprite; 021 import com.croftsoft.core.animation.sprite.TextSprite; 022 import com.croftsoft.core.awt.image.ImageLib; 023 import com.croftsoft.core.gui.LifecycleWindowListener; 024 import com.croftsoft.core.lang.ClassLib; 025 import com.croftsoft.core.lang.lifecycle.Lifecycle; 026 import com.croftsoft.core.util.loop.FixedDelayLoopGovernor; 027 028 /********************************************************************* 029 * Main Shooter class. 030 * 031 * @version 032 * 2003-07-23 033 * @since 034 * 2002-03-23 035 * @author 036 * <a href="https://www.croftsoft.com/">David Wallace Croft</a> 037 *********************************************************************/ 038 039 public final class Shooter 040 extends JApplet 041 implements ComponentAnimator, Lifecycle 042 ////////////////////////////////////////////////////////////////////// 043 ////////////////////////////////////////////////////////////////////// 044 { 045 046 ////////////////////////////////////////////////////////////////////// 047 // Applet constants 048 ////////////////////////////////////////////////////////////////////// 049 050 private static final String VERSION 051 = "2003-07-17"; 052 053 private static final String TITLE 054 = "CroftSoft Shooter"; 055 056 private static final String INFO 057 = "\n" + TITLE + "\n" 058 + CroftSoftConstants.COPYRIGHT + "\n" 059 + CroftSoftConstants.HOME_PAGE + "\n" 060 + "Version " + VERSION + "\n"; 061 062 ////////////////////////////////////////////////////////////////////// 063 // Frame constants 064 ////////////////////////////////////////////////////////////////////// 065 066 private static final String FRAME_TITLE 067 = TITLE; 068 069 private static final String FRAME_ICON_FILENAME 070 = "/images/croftsoft.png"; 071 072 private static final Dimension FRAME_SIZE 073 = null; 074 075 private static final String SHUTDOWN_CONFIRMATION_PROMPT 076 = "Close " + TITLE + "?"; 077 078 ////////////////////////////////////////////////////////////////////// 079 // animation constants 080 ////////////////////////////////////////////////////////////////////// 081 082 /** frames per second */ 083 private static final double FRAME_RATE = 50.0; 084 085 private static final double ATTACKER_DENSITY = 4.0 / ( 600 * 400 ); 086 087 /** pixels per frame */ 088 private static final double ATTACKER_VELOCITY = 100.0 / FRAME_RATE; 089 090 private static final String MEDIA_DIR = "media/shooter/"; 091 092 private static final String SHOOTER_REST_IMAGE_FILENAME 093 = MEDIA_DIR + "shooter_rest.png"; 094 095 private static final String SHOOTER_BANG_IMAGE_FILENAME 096 = MEDIA_DIR + "shooter_bang.png"; 097 098 private static final String SHOOTER_BOOM_IMAGE_FILENAME 099 = MEDIA_DIR + "shooter_boom.png"; 100 101 private static final String BANG_AUDIO_FILENAME 102 = MEDIA_DIR + "bang.wav"; 103 104 private static final String EXPLODE_AUDIO_FILENAME 105 = MEDIA_DIR + "explode.wav"; 106 107 private static final Color BACKGROUND_COLOR 108 = Color.BLACK; 109 110 ////////////////////////////////////////////////////////////////////// 111 // instance variables 112 ////////////////////////////////////////////////////////////////////// 113 114 private AnimatedComponent animatedComponent; 115 116 private ShooterSprite shooterSprite; 117 118 private AttackerSprite [ ] attackerSprites; 119 120 private long highScore; 121 122 private TextSprite scoreTextSprite; 123 124 private Random random; 125 126 private AudioClip explodeAudioClip; 127 128 private SpacePainter spacePainter; 129 130 ////////////////////////////////////////////////////////////////////// 131 ////////////////////////////////////////////////////////////////////// 132 133 public static void main ( String [ ] args ) 134 ////////////////////////////////////////////////////////////////////// 135 { 136 JFrame jFrame = new JFrame ( FRAME_TITLE ); 137 138 try 139 { 140 jFrame.setIconImage ( ClassLib.getResourceAsImage ( 141 Shooter.class, FRAME_ICON_FILENAME ) ); 142 } 143 catch ( Exception ex ) 144 { 145 } 146 147 Shooter shooter = new Shooter ( ); 148 149 jFrame.setContentPane ( shooter ); 150 151 LifecycleWindowListener.launchFrameAsDesktopApp ( 152 jFrame, 153 new Lifecycle [ ] { shooter }, 154 FRAME_SIZE, 155 SHUTDOWN_CONFIRMATION_PROMPT ); 156 } 157 158 ////////////////////////////////////////////////////////////////////// 159 ////////////////////////////////////////////////////////////////////// 160 161 public String getAppletInfo ( ) 162 ////////////////////////////////////////////////////////////////////// 163 { 164 return INFO; 165 } 166 167 ////////////////////////////////////////////////////////////////////// 168 // interface Lifecycle methods 169 ////////////////////////////////////////////////////////////////////// 170 171 public void init ( ) 172 ////////////////////////////////////////////////////////////////////// 173 { 174 System.out.println ( INFO ); 175 176 animatedComponent = new AnimatedComponent ( this, FRAME_RATE ); 177 178 animatedComponent.setLoopGovernor ( 179 new FixedDelayLoopGovernor ( FRAME_RATE ) ); 180 181 animatedComponent.addComponentListener ( 182 new ComponentAdapter ( ) 183 { 184 public void componentResized ( ComponentEvent componentEvent ) 185 { 186 resetBounds ( ); 187 } 188 } ); 189 190 Container contentPane = getContentPane ( ); 191 192 contentPane.setLayout ( new BorderLayout ( ) ); 193 194 contentPane.add ( animatedComponent, BorderLayout.CENTER ); 195 196 animatedComponent.setCursor ( 197 new Cursor ( Cursor.CROSSHAIR_CURSOR ) ); 198 199 animatedComponent.init ( ); 200 201 try 202 { 203 Image shooterRestImage = loadAutomaticImage ( 204 SHOOTER_REST_IMAGE_FILENAME, Transparency.BITMASK ); 205 206 Image shooterBangImage = loadAutomaticImage ( 207 SHOOTER_BANG_IMAGE_FILENAME, Transparency.BITMASK ); 208 209 Image shooterBoomImage = loadAutomaticImage ( 210 SHOOTER_BOOM_IMAGE_FILENAME, Transparency.BITMASK ); 211 212 URL bangAudioURL = getClass ( ).getClassLoader ( ) 213 .getResource ( BANG_AUDIO_FILENAME ); 214 215 AudioClip bangAudioClip = Applet.newAudioClip ( bangAudioURL ); 216 217 shooterSprite = new ShooterSprite ( 218 shooterRestImage, 219 shooterBangImage, 220 shooterBoomImage, 221 bangAudioClip, 222 this ); 223 224 animatedComponent.addMouseListener ( shooterSprite ); 225 226 animatedComponent.addMouseMotionListener ( shooterSprite ); 227 } 228 catch ( IOException ex ) 229 { 230 ex.printStackTrace ( ); 231 } 232 233 // attackers 234 235 attackerSprites = new AttackerSprite [ 0 ]; 236 237 explodeAudioClip = Applet.newAudioClip ( 238 getClass ( ).getClassLoader ( ).getResource ( 239 EXPLODE_AUDIO_FILENAME ) ); 240 241 random = new Random ( ); 242 243 // shooterBounds = new Rectangle ( ); 244 245 scoreTextSprite = new TextSprite ( TITLE ); 246 247 scoreTextSprite.setX ( 20 ); 248 249 scoreTextSprite.setY ( 20 ); 250 251 scoreTextSprite.setColor ( Color.RED ); 252 253 spacePainter = new SpacePainter ( ); 254 } 255 256 public void start ( ) { animatedComponent.start ( ); } 257 258 public void stop ( ) { animatedComponent.stop ( ); } 259 260 public void destroy ( ) { animatedComponent.destroy ( ); } 261 262 ////////////////////////////////////////////////////////////////////// 263 ////////////////////////////////////////////////////////////////////// 264 265 public AttackerSprite [ ] getAttackerSprites ( ) 266 ////////////////////////////////////////////////////////////////////// 267 { 268 return attackerSprites; 269 } 270 271 ////////////////////////////////////////////////////////////////////// 272 // interface ComponentAnimator methods 273 ////////////////////////////////////////////////////////////////////// 274 275 public void update ( JComponent component ) 276 ////////////////////////////////////////////////////////////////////// 277 { 278 component.repaint ( ); 279 280 AttackerSprite [ ] attackerSprites = this.attackerSprites; 281 282 for ( int i = 0; i < attackerSprites.length; i++ ) 283 { 284 attackerSprites [ i ].update ( component ); 285 } 286 287 Shape shooterCollisionShape = shooterSprite.getCollisionShape ( ); 288 289 if ( shooterCollisionShape != null ) 290 { 291 Rectangle2D shooterCollisionRectangle2D 292 = shooterCollisionShape.getBounds2D ( ); 293 294 for ( int i = 0; i < attackerSprites.length; i++ ) 295 { 296 Shape attackerCollisionShape 297 = attackerSprites [ i ].getCollisionShape ( ); 298 299 if ( attackerCollisionShape != null ) 300 { 301 if ( attackerCollisionShape.intersects ( 302 shooterCollisionRectangle2D ) ) 303 { 304 shooterSprite.setHit ( ); 305 306 attackerSprites [ i ].setHit ( ); 307 308 break; 309 } 310 } 311 } 312 } 313 314 shooterSprite.update ( component ); 315 316 long score = shooterSprite.getScore ( ); 317 318 highScore = score > highScore ? score : highScore; 319 320 scoreTextSprite.setText ( 321 "High Score: " + highScore + " Score: " + score ); 322 } 323 324 public void paint ( 325 JComponent component, 326 Graphics2D graphics ) 327 ////////////////////////////////////////////////////////////////////// 328 { 329 spacePainter.paint ( component, graphics ); 330 331 AttackerSprite [ ] attackerSprites = this.attackerSprites; 332 333 for ( int i = 0; i < attackerSprites.length; i++ ) 334 { 335 attackerSprites [ i ].paint ( component, graphics ); 336 } 337 338 shooterSprite.paint ( component, graphics ); 339 340 scoreTextSprite.paint ( component, graphics ); 341 } 342 343 ////////////////////////////////////////////////////////////////////// 344 ////////////////////////////////////////////////////////////////////// 345 346 private Image loadAutomaticImage ( 347 String imageFilename, 348 int transparency ) 349 throws IOException 350 ////////////////////////////////////////////////////////////////////// 351 { 352 return ImageLib.loadAutomaticImage ( 353 imageFilename, 354 transparency, 355 animatedComponent, 356 getClass ( ).getClassLoader ( ), 357 null ); 358 } 359 360 private void resetBounds ( ) 361 ////////////////////////////////////////////////////////////////////// 362 { 363 shooterSprite.resetScore ( ); 364 365 int attackerCount = ( int ) Math.round ( 366 ATTACKER_DENSITY 367 * animatedComponent.getWidth ( ) 368 * animatedComponent.getHeight ( ) ); 369 370 attackerSprites = new AttackerSprite [ attackerCount ]; 371 372 for ( int i = 0; i < attackerSprites.length; i++ ) 373 { 374 AttackerSprite attackerSprite = new AttackerSprite ( 375 explodeAudioClip, 376 random, 377 ATTACKER_VELOCITY ); 378 379 attackerSprite.setY ( Double.POSITIVE_INFINITY ); 380 381 attackerSprites [ i ] = attackerSprite; 382 } 383 } 384 385 ////////////////////////////////////////////////////////////////////// 386 ////////////////////////////////////////////////////////////////////// 387 }