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 }