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 }