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 }