001         package com.croftsoft.apps.dodger;
002    
003         import java.applet.*;
004         import java.awt.*;
005         import java.awt.event.*;
006         import java.awt.geom.*;
007         import java.beans.*;
008         import java.util.Random;
009         import javax.swing.*;
010         import javax.swing.event.*;
011    
012         import com.croftsoft.core.lang.NullArgumentException;
013         import com.croftsoft.core.animation.*;
014         import com.croftsoft.core.animation.sprite.IconSprite;
015    
016         /*********************************************************************
017         * An IconSprite subclass representing the Dodger.
018         *
019         * @version
020         *   2003-07-12
021         * @since
022         *   2002-03-18
023         * @author
024         *   <a href="https://www.croftsoft.com/">David Wallace Croft</a>
025         *********************************************************************/
026    
027         public class  DodgerSprite
028           extends IconSprite
029           implements KeyListener, MouseInputListener
030         //////////////////////////////////////////////////////////////////////
031         //////////////////////////////////////////////////////////////////////
032         {
033    
034         private static final long  IDLE_TIMEOUT_MILLIS         = 60 * 1000;
035    
036         private static final long  INIT_RECHARGE_PERIOD_MILLIS = 1;
037    
038         private static final long  BANG_PERIOD_MILLIS          = 300;
039    
040         private static final long  RECOVERY_PERIOD_MILLIS      = 1000;
041    
042         //
043    
044         private static final int   STATE_GREEN  = 0;
045    
046         private static final int   STATE_YELLOW = 1;
047    
048         private static final int   STATE_RED    = 2;
049    
050         private static final int   STATE_BANG   = 3;
051    
052         private static final int   STATE_BOOM   = 4;
053    
054         //
055    
056         private final Icon         greenIcon;
057    
058         private final Icon         yellowIcon;
059    
060         private final Icon         redIcon;
061    
062         private final Icon         bangIcon;
063    
064         private final Icon         boomIcon;
065    
066         private final AudioClip    bangAudioClip;
067    
068         private final Rectangle    bounds;
069    
070         private final int          dodgerWidth;
071    
072         private final int          dodgerHalfWidth;
073    
074         private final int          dodgerHalfHeight;
075    
076         private final int          dodgerVerticalOffset;
077    
078         private final Rectangle2D  shootArea;
079    
080         private final Rectangle    paintBounds;
081    
082         //
083    
084         private long     rechargePeriodMillis;
085    
086         private boolean  bang;
087    
088         private long     bangTimeMillis;
089    
090         private Point    mousePoint;
091    
092         private boolean  shooting;
093    
094         private long     score;
095    
096         private long     lastMoveTimeMillis;
097    
098         private int      state;
099    
100         private long     boomTimeMillis;
101    
102         //////////////////////////////////////////////////////////////////////
103         // constructor methods
104         //////////////////////////////////////////////////////////////////////
105    
106    
107         public  DodgerSprite (
108           Icon       greenIcon,
109           Icon       yellowIcon,
110           Icon       redIcon,
111           Icon       bangIcon,
112           Icon       boomIcon,
113           AudioClip  bangAudioClip,
114           Rectangle  bounds )
115         //////////////////////////////////////////////////////////////////////
116         {
117           super ( 0.0, 0.0, 0.0, 0.0, 0.0, null, greenIcon );
118    
119           NullArgumentException.check ( this.greenIcon     = greenIcon     );
120    
121           NullArgumentException.check ( this.yellowIcon    = yellowIcon    );
122    
123           NullArgumentException.check ( this.redIcon       = redIcon       );
124    
125           NullArgumentException.check ( this.bangIcon      = bangIcon      );
126    
127           NullArgumentException.check ( this.boomIcon      = boomIcon      );
128    
129           NullArgumentException.check ( this.bangAudioClip = bangAudioClip );
130    
131           NullArgumentException.check ( this.bounds        = bounds        );
132    
133           dodgerWidth = greenIcon.getIconWidth ( );
134    
135           dodgerHalfWidth  = dodgerWidth / 2;
136    
137           dodgerHalfHeight = greenIcon.getIconHeight ( ) / 2;
138    
139           dodgerVerticalOffset = 3 * dodgerHalfHeight;
140    
141           shootArea = new Rectangle2D.Double ( );
142    
143           paintBounds = new Rectangle ( );
144    
145           setX ( Double.POSITIVE_INFINITY );
146    
147           rechargePeriodMillis = INIT_RECHARGE_PERIOD_MILLIS;
148         }
149    
150         //////////////////////////////////////////////////////////////////////
151         // accessor methods
152         //////////////////////////////////////////////////////////////////////
153    
154         public long  getScore ( ) { return score; }
155    
156         public boolean  isShooting ( ) { return shooting; }
157    
158         public Rectangle2D  getShootArea ( ) { return shootArea; }
159    
160         //////////////////////////////////////////////////////////////////////
161         // mutator methods
162         //////////////////////////////////////////////////////////////////////
163    
164         public void  resetScore ( )
165         //////////////////////////////////////////////////////////////////////
166         {
167           score = 0;
168         }
169    
170         public void  setHit ( )
171         //////////////////////////////////////////////////////////////////////
172         {
173           rechargePeriodMillis = INIT_RECHARGE_PERIOD_MILLIS;
174    
175           score = 0;
176    
177           setIcon ( boomIcon );
178    
179           state = STATE_BOOM;
180    
181           boomTimeMillis = System.currentTimeMillis ( );
182         }
183    
184         //////////////////////////////////////////////////////////////////////
185         // interface ComponentAnimator methods
186         //////////////////////////////////////////////////////////////////////
187    
188         public void  update ( JComponent  component )
189         //////////////////////////////////////////////////////////////////////
190         {
191           long  updateTimeMillis = System.currentTimeMillis ( );
192    
193           if ( updateTimeMillis >= lastMoveTimeMillis + IDLE_TIMEOUT_MILLIS )
194           {
195             setX ( Integer.MAX_VALUE );
196    
197             return;
198           }
199    
200           score++;
201    
202           shooting = false;
203    
204           if ( bang
205             && ( updateTimeMillis >= bangTimeMillis + rechargePeriodMillis ) )
206           {
207             shooting = true;
208    
209             rechargePeriodMillis = 2 * rechargePeriodMillis;
210    
211             shootArea.setRect ( getX ( ), 0, dodgerWidth, getY ( ) );
212    
213             bangTimeMillis = updateTimeMillis;
214    
215             bangAudioClip.play ( );
216    
217             if ( state != STATE_BOOM )
218             {
219               state = STATE_BANG;
220    
221               setIcon ( bangIcon );
222             }
223           }
224           else if ( state == STATE_BOOM )
225           {
226             if ( updateTimeMillis >= boomTimeMillis + RECOVERY_PERIOD_MILLIS )
227             {
228               setIcon ( greenIcon );
229    
230               state = STATE_GREEN;
231             }
232           }
233           else if ( ( state == STATE_BANG   )
234                  || ( state == STATE_RED    )
235                  || ( state == STATE_YELLOW ) )
236           {
237             if ( updateTimeMillis >= bangTimeMillis + rechargePeriodMillis )
238             {
239               setIcon ( greenIcon );
240    
241               state = STATE_GREEN;
242             }
243             else if (
244               updateTimeMillis >= bangTimeMillis + rechargePeriodMillis / 2 )
245             {
246               setIcon ( yellowIcon );
247    
248               state = STATE_YELLOW;
249             }
250             else if (
251               updateTimeMillis >= bangTimeMillis + BANG_PERIOD_MILLIS )
252             {
253               setIcon ( redIcon );
254    
255               state = STATE_RED;
256             }
257           }
258    
259           double  x = getX ( );
260    
261           double  velocity = getVelocity ( );
262    
263           Point  mousePoint = this.mousePoint;
264    
265           if ( mousePoint != null )
266           {
267             double  delta = mousePoint.x - dodgerHalfWidth - x;
268    
269             if ( delta > 0 )
270             {
271               if ( velocity > delta / 2 )
272               {
273                 velocity = delta / 2;
274               }
275               else if ( velocity < 0 )
276               {
277                 velocity = velocity / 2 + 1;
278               }
279               else
280               {
281                 velocity++;
282               }
283             }
284             else if ( delta < 0 )
285             {
286               if ( velocity < delta / 2 )
287               {
288                 velocity = delta / 2;
289               }
290               else if ( velocity > 0 )
291               {
292                 velocity = velocity / 2 - 1;
293               }
294               else
295               {
296                 velocity--;
297               }
298             }
299             else
300             {
301               velocity = 0;
302             }
303    
304             x += velocity;
305    
306             x = x < -dodgerHalfWidth ? -dodgerHalfWidth : x;
307    
308             x = x > bounds.width - dodgerHalfWidth
309               ? bounds.width - dodgerHalfWidth : x;
310    
311             setX ( x );
312    
313             setY ( bounds.height - dodgerVerticalOffset );
314    
315             setVelocity ( velocity );
316           }
317         }
318    
319         //////////////////////////////////////////////////////////////////////
320         //////////////////////////////////////////////////////////////////////
321    
322    /*
323         public void  paint (
324           JComponent  component,
325           Graphics2D  graphics,
326           int         offsetX,
327           int         offsetY )
328         //////////////////////////////////////////////////////////////////////
329         {
330           super.paint ( component, graphics, offsetX, offsetY );
331    
332           if ( shielded )
333           {
334             graphics.setColor ( Color.BLACK );
335    
336             getPaintBounds ( paintBounds );
337    
338             graphics.drawRect (
339               paintBounds.x,
340               paintBounds.y,
341               paintBounds.width,
342               paintBounds.height );
343           }
344         }
345    */
346    
347         //////////////////////////////////////////////////////////////////////
348         //////////////////////////////////////////////////////////////////////
349    
350         public void  mouseClicked ( MouseEvent  mouseEvent )
351         //////////////////////////////////////////////////////////////////////
352         {
353         }
354    
355         public void  mouseDragged ( MouseEvent  mouseEvent )
356         //////////////////////////////////////////////////////////////////////
357         {
358           mousePoint = mouseEvent.getPoint ( );
359    
360           lastMoveTimeMillis = System.currentTimeMillis ( );
361         }
362    
363         public void  mouseEntered ( MouseEvent  mouseEvent )
364         //////////////////////////////////////////////////////////////////////
365         {
366         }
367    
368         public void  mouseExited ( MouseEvent  mouseEvent )
369         //////////////////////////////////////////////////////////////////////
370         {
371         }
372    
373         public void  mouseMoved ( MouseEvent  mouseEvent )
374         //////////////////////////////////////////////////////////////////////
375         {
376           mousePoint = mouseEvent.getPoint ( );
377    
378           lastMoveTimeMillis = System.currentTimeMillis ( );
379         }
380    
381         public void  mousePressed ( MouseEvent  mouseEvent )
382         //////////////////////////////////////////////////////////////////////
383         {
384           bang = true;
385    
386           lastMoveTimeMillis = System.currentTimeMillis ( );
387         }
388    
389         public void  mouseReleased ( MouseEvent  mouseEvent )
390         //////////////////////////////////////////////////////////////////////
391         {
392           bang = false;
393    
394           lastMoveTimeMillis = System.currentTimeMillis ( );
395         }
396    
397         //////////////////////////////////////////////////////////////////////
398         //////////////////////////////////////////////////////////////////////
399    
400         public void  keyPressed ( KeyEvent  keyEvent )
401         //////////////////////////////////////////////////////////////////////
402         {
403           bang = true;
404    
405           lastMoveTimeMillis = System.currentTimeMillis ( );
406         }
407         
408         public void  keyReleased ( KeyEvent  keyEvent )
409         //////////////////////////////////////////////////////////////////////
410         {
411           bang = false;
412    
413           lastMoveTimeMillis = System.currentTimeMillis ( );
414         }
415         
416         public void  keyTyped ( KeyEvent  keyEvent )
417         //////////////////////////////////////////////////////////////////////
418         {
419         }
420         
421         //////////////////////////////////////////////////////////////////////
422         //////////////////////////////////////////////////////////////////////
423         }