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         }