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.util.Random; 008 import javax.swing.*; 009 import javax.swing.event.*; 010 011 import com.croftsoft.core.lang.NullArgumentException; 012 import com.croftsoft.core.animation.*; 013 import com.croftsoft.core.animation.painter.NullComponentPainter; 014 import com.croftsoft.core.animation.sprite.*; 015 import com.croftsoft.core.animation.updater.NullComponentUpdater; 016 017 /********************************************************************* 018 * An IconSprite subclass representing a Shooter attacker. 019 * 020 * @version 021 * 2003-07-11 022 * @since 023 * 2002-03-23 024 * @author 025 * <a href="https://www.croftsoft.com/">David Wallace Croft</a> 026 *********************************************************************/ 027 028 public class AttackerSprite 029 extends AbstractSprite 030 ////////////////////////////////////////////////////////////////////// 031 ////////////////////////////////////////////////////////////////////// 032 { 033 034 private static final int ATTACKER_WIDTH = 32; 035 036 private static final int ATTACKER_HEIGHT = 32; 037 038 private static final int ATTACKER_HALF_WIDTH = ATTACKER_WIDTH / 2; 039 040 private static final int ATTACKER_HALF_HEIGHT = ATTACKER_HEIGHT / 2; 041 042 private static final long EXPLODE_PERIOD_MILLIS = 1000; 043 044 // 045 046 private final AudioClip explodeAudioClip; 047 048 private final Random random; 049 050 private final Rectangle paintBounds; 051 052 // 053 054 private Color color; 055 056 private long explodeTimeMillis; 057 058 private boolean hit; 059 060 private boolean exploding; 061 062 private int componentHeight; 063 064 private int componentWidth; 065 066 private double averageVelocity; 067 068 ////////////////////////////////////////////////////////////////////// 069 // constructor methods 070 ////////////////////////////////////////////////////////////////////// 071 072 073 public AttackerSprite ( 074 AudioClip explodeAudioClip, 075 Random random, 076 double averageVelocity ) 077 ////////////////////////////////////////////////////////////////////// 078 { 079 super ( 0.0, 0.0, 0.0, 0.0, 0.0, 080 NullComponentUpdater.INSTANCE, 081 NullComponentPainter.INSTANCE ); 082 083 NullArgumentException.check ( 084 this.explodeAudioClip = explodeAudioClip ); 085 086 NullArgumentException.check ( this.random = random ); 087 088 paintBounds = new Rectangle ( 089 0, 0, ATTACKER_WIDTH, ATTACKER_HEIGHT ); 090 091 setY ( Double.POSITIVE_INFINITY ); 092 093 color = new Color ( 094 random.nextInt ( 256 ), 095 random.nextInt ( 256 ), 096 random.nextInt ( 256 ) ); 097 098 this.averageVelocity = averageVelocity; 099 } 100 101 ////////////////////////////////////////////////////////////////////// 102 // accessor methods 103 ////////////////////////////////////////////////////////////////////// 104 105 public void getPaintBounds ( Rectangle paintBounds ) 106 ////////////////////////////////////////////////////////////////////// 107 { 108 paintBounds.setBounds ( this.paintBounds ); 109 } 110 111 public Shape getCollisionShape ( ) 112 ////////////////////////////////////////////////////////////////////// 113 { 114 if ( exploding ) 115 { 116 return null; 117 } 118 119 return paintBounds; 120 } 121 122 public boolean intersectsLine ( 123 double x1, 124 double y1, 125 double x2, 126 double y2 ) 127 ////////////////////////////////////////////////////////////////////// 128 { 129 return paintBounds.intersectsLine ( x1, y1, x2, y2 ); 130 } 131 132 public boolean isHit ( ) { return hit; } 133 134 ////////////////////////////////////////////////////////////////////// 135 // mutator methods 136 ////////////////////////////////////////////////////////////////////// 137 138 public void setX ( double x ) 139 ////////////////////////////////////////////////////////////////////// 140 { 141 super.setX ( x ); 142 143 paintBounds.x = ( int ) Math.round ( x ) - ATTACKER_HALF_HEIGHT; 144 } 145 146 public void setY ( double y ) 147 ////////////////////////////////////////////////////////////////////// 148 { 149 super.setY ( y ); 150 151 paintBounds.y = ( int ) Math.round ( y ) - ATTACKER_HALF_WIDTH; 152 } 153 154 public void setHit ( ) 155 ////////////////////////////////////////////////////////////////////// 156 { 157 hit = true; 158 } 159 160 public void reset ( ) 161 ////////////////////////////////////////////////////////////////////// 162 { 163 hit = false; 164 165 exploding = false; 166 167 double centerX = componentWidth / 2.0; 168 169 double centerY = componentHeight / 2.0; 170 171 double radius = centerX > centerY ? centerX : centerY; 172 173 double angle = 2.0 * Math.PI * random.nextDouble ( ); 174 175 double x = centerX + radius * Math.cos ( angle ); 176 177 double y = centerY + radius * Math.sin ( angle ); 178 179 setX ( x ); 180 181 setY ( y ); 182 183 setHeading ( Math.atan2 ( ( centerY - y ), ( centerX - x ) ) ); 184 185 setVelocity ( ( 0.5 + random.nextDouble ( ) ) * averageVelocity ); 186 187 color = new Color ( 188 random.nextInt ( 256 ), 189 random.nextInt ( 256 ), 190 random.nextInt ( 256 ) ); 191 } 192 193 ////////////////////////////////////////////////////////////////////// 194 // interface ComponentAnimator methods 195 ////////////////////////////////////////////////////////////////////// 196 197 public void update ( JComponent component ) 198 ////////////////////////////////////////////////////////////////////// 199 { 200 long updateTimeMillis = System.currentTimeMillis ( ); 201 202 double x = getX ( ); 203 204 double y = getY ( ); 205 206 double velocity = getVelocity ( ); 207 208 double heading = getHeading ( ); 209 210 x += ( velocity * Math.cos ( heading ) ); 211 212 y += ( velocity * Math.sin ( heading ) ); 213 214 componentWidth = component.getWidth ( ); 215 216 componentHeight = component.getHeight ( ); 217 218 if ( ( y >= 2.0 * componentHeight ) 219 || ( y <= -1.0 * componentHeight ) 220 || ( x >= 2.0 * componentWidth ) 221 || ( x <= -1.0 * componentWidth ) ) 222 { 223 reset ( ); 224 } 225 else 226 { 227 setX ( x ); 228 229 setY ( y ); 230 } 231 232 if ( exploding ) 233 { 234 if ( updateTimeMillis 235 >= explodeTimeMillis + EXPLODE_PERIOD_MILLIS ) 236 { 237 reset ( ); 238 } 239 240 color = new Color ( 241 random.nextInt ( 256 ), 242 random.nextInt ( 256 ), 243 random.nextInt ( 256 ) ); 244 } 245 else if ( hit ) 246 { 247 explodeAudioClip.play ( ); 248 249 color = new Color ( 250 random.nextInt ( 256 ), 251 random.nextInt ( 256 ), 252 random.nextInt ( 256 ) ); 253 254 explodeTimeMillis = updateTimeMillis; 255 256 exploding = true; 257 } 258 } 259 260 public void paint ( 261 JComponent component, 262 Graphics2D graphics ) 263 ////////////////////////////////////////////////////////////////////// 264 { 265 graphics.setColor ( color ); 266 267 graphics.fillRect ( 268 paintBounds.x, 269 paintBounds.y, 270 ATTACKER_WIDTH, 271 ATTACKER_HEIGHT ); 272 273 graphics.setColor ( Color.WHITE ); 274 275 graphics.drawRect ( 276 paintBounds.x, 277 paintBounds.y, 278 ATTACKER_WIDTH, 279 ATTACKER_HEIGHT ); 280 } 281 282 ////////////////////////////////////////////////////////////////////// 283 ////////////////////////////////////////////////////////////////////// 284 }