scg/ch01/spacesprites/Ship

From FANG

Jump to: navigation, search

001 package scg.ch01.spacesprites;
002 
003 import java.awt.Color;
004 import java.awt.event.KeyEvent;
005 
006 import fang2.attributes.Location2D;
007 import fang2.attributes.Vector2D;
008 import fang2.core.Alarm;
009 import fang2.core.Game;
010 import fang2.core.Sprite;
011 import fang2.sprites.PolygonSprite;
012 import fang2.transformers.*;
013 
014 /**
015  * A triangular spaceship sprite. It can be positioned on the screen,
016  * created in a variety of colors, and the like. By default it is
017  * controlled by the keyboard but it can also be constructed as a
018  * non-player controlled space craft. Also, by default, it wraps around
019  * the screen at the edges.
020  */
021 public class Ship
022   extends PolygonSprite
023   implements Alarm, HitTarget, Shootable, Shooter {
024   /** how much speed up does the acceleration add for the ship? */
025   private static final double ACCELERATION_SCREENS_PER_SECOND_SQUARED =
026     2.0;
027 
028   /** the alarm interval in seconds; used for counting down timers */
029   private static final double ALARM_INTERVAL = 0.25;
030 
031   /** the turning speed of this ship; in radians/second */
032   private static final double ANGULAR_VELOCITY_DEGREES_PER_SECOND = 300;
033 
034   /** number of lives a ship gets by default */
035   private static final int DEFAULT_LIFE_COUNT = 3;
036 
037   /** default size (in screen fraction) of a newly created ship */
038   private static final double DEFAULT_SCALE = 0.1;
039 
040   /** the color of the ship (if there is no other color specified */
041   private static final Color DEFAULT_SHIP_COLOR = Game.getColor(
042       "SCG Red");
043 
044   /** gun location relative to ship location */
045   private static Location2D GUN_LOCATION = new Location2D(0.70);
046 
047   /** what is the speed limit for the ship? */
048   private static final double MAX_VELOCITY_SCREENS_PER_SECOND = 0.25;
049   // ----- Data for individual ships -----
050   // ---------- Collision Control
051 
052   /** classes of sprites which can hit us tracked here */
053   private HitClassTransformer collisionClasses;
054 
055   /** specific sprites which can hit us tracked here */
056   private HitSpriteTransformer collisions;
057 
058   // ---------- Gameplay Variables: use setShootingDelay and
059   // setImmunityDelay to change timing; extraLife to
060   // add an extra life
061   /** seconds, after hit, while ship is immune from damage */
062   private double immunityDelay;
063 
064   /** time, in seconds, remaining on current immunity */
065   private double immunityDelayRemaining;
066   // ---------- Score/Lives remaining display
067 
068   /** number of remaining lives */
069   private final ScoreSprite lives;
070 
071   /** game we are part of */
072   private final Game myGame;
073 
074   /** score (for the projectiles) */
075   private final ScoreSprite score;
076 
077   /** time, in seconds, between shots */
078   private double shootingDelay;
079 
080   /** time, in seconds, remaining before we can shoot again */
081   private double shootingDelayRemaining;
082 
083   // --------- Targeting Data: sprite/class for projectiles
084   /** the specific sprite this ship's projectiles hit */
085   private Sprite target;
086 
087   /** the class of objects this ship's projectiles hit */
088   private Class<? extends Sprite> targetClass;
089 
090   // ----- Command Definitions (methods) -----
091   /**
092    * Construct a {@link Ship} associated with the given game.
093    *
094    @param  myGame  the game to which this ship belongs
095    */
096   public Ship(Game myGame{
097     this(myGame, DEFAULT_SHIP_COLOR, DEFAULT_SCALE, DEFAULT_LIFE_COUNT);
098     addAllTransformers();
099   }
100 
101   /**
102    * Construct a new {@link Ship} associated with the given game and
103    * having the given color.
104    *
105    @param  myGame  the {@link Game} to which the ship belongs
106    @param  color   the {@link Color} to display the ship
107    */
108   public Ship(Game myGame, Color color{
109     this(myGame, color, DEFAULT_SCALE, DEFAULT_LIFE_COUNT);
110   }
111 
112   /**
113    * Construct a new {@link Ship} associated with the given game, using
114    * the given scale and color.
115    *
116    @param  myGame  the {@link Game} to which it is associated
117    @param  color   the color to fill the ship with
118    @param  scale   the scale (in percentages of a screen)
119    @param  lives   the number of lives the ship has
120    */
121   public Ship(Game myGame, Color color, double scale, int lives{
122     super(0.50, -0.5, -0.25, -0.50.25);
123     this.myGame = myGame;
124     this.setScale(scale);
125     this.setColor(color);
126 
127     this.lives = new ScoreSprite(lives);
128     this.lives.hide();
129     Game.getCurrentGame().addSprite(lives);
130 
131     this.score = new ScoreSprite(0);
132     this.score.translateX(0.5);// move score over
133     this.score.setColor(myGame.getColor("gray"));
134     this.score.hide();
135 
136     this.addTransformer(new WrapTransformer());
137     this.myGame.scheduleRelative(this, ALARM_INTERVAL);
138   }
139 
140   public void act() {
141     if (immunityDelayRemaining > 0.0{
142       immunityDelayRemaining -= ALARM_INTERVAL;
143     }
144     if (shootingDelayRemaining > 0.0{
145       shootingDelayRemaining -= ALARM_INTERVAL;
146     }
147     Game.getCurrentGame().scheduleRelative(this, ALARM_INTERVAL);
148   }
149 
150   /**
151    * Construct all of the transformers that make this ship move
152    * according to the keyboard
153    */
154   public void addAllTransformers() {
155     addKeyboardTransformers();
156     addShooterTransformers();
157   }
158 
159   /**
160    * Add a whole class of sprites as "rocks" that damages this ship
161    *
162    @param  targetClass  the {@link Sprite} derived class to shoot at
163    */
164   public void addCollision(Class<? extends Sprite> targetClass{
165     if (collisionClasses == null{
166       collisionClasses = new HitClassTransformer(this, targetClass);
167       addTransformer(collisionClasses);
168     } else {
169       collisionClasses.add(targetClass);
170     }
171   }
172 
173   /**
174    * Add a specific sprite as a "rock" that damages this ship
175    *
176    @param  target  the {@link Sprite} to shoot
177    */
178   public void addCollision(Sprite target{
179     if (collisions == null{
180       collisions = new HitSpriteTransformer(target);
181       addTransformer(collisions);
182     } else {
183       collisions.add(target);
184     }
185   }
186 
187   /**
188    * Associate the ship with rotation and acceleration by pressing the
189    * right keys.
190    */
191   public void addKeyboardTransformers() {
192     AccelerationAheadTransformer velocity =
193       new AccelerationAheadTransformer(
194         ACCELERATION_SCREENS_PER_SECOND_SQUARED);
195     velocity.setMaximumMagnitude(MAX_VELOCITY_SCREENS_PER_SECOND);
196 
197     KeyboardTransformer driveKeys = new KeyboardTransformer(velocity);
198     driveKeys.addPlusKey(KeyEvent.VK_UP);
199     driveKeys.addPlusKey(KeyEvent.VK_KP_UP);
200     // uncomment (remove "//") following lines to provide backup
201     // acceleration driveKeys.addMinusKey(KeyEvent.VK_DOWN);
202     // driveKeys.addMinusKey(KeyEvent.VK_KP_DOWN);
203     this.addTransformer(driveKeys);
204 
205     SpinTransformer turn = new SpinTransformer(
206         ANGULAR_VELOCITY_DEGREES_PER_SECOND);
207     turn.setResetToNominal(true);
208 
209     KeyboardTransformer turnKeys = new KeyboardTransformer(turn);
210     turnKeys.addPlusKey(KeyEvent.VK_RIGHT);
211     turnKeys.addPlusKey(KeyEvent.VK_KP_RIGHT);
212     turnKeys.addMinusKey(KeyEvent.VK_LEFT);
213     turnKeys.addMinusKey(KeyEvent.VK_KP_LEFT);
214     this.addTransformer(turnKeys);
215   }
216 
217   /**
218    * Associate the ship with shooting by pressing the correct key.
219    */
220   public void addShooterTransformers() {
221     ShooterTransformer bang = new ShooterTransformer();
222     KeyboardTransformer shoot = new KeyboardTransformer(bang);
223     shoot.addPlusKey(KeyEvent.VK_SPACE);
224     this.addTransformer(shoot);
225   }
226 
227   /**
228    * Give the ship an extra life. Usually the player's ship.
229    */
230   public void extraLife() {
231     lives.increment();
232   }
233 
234   /**
235    @return  the immunityDelay
236    */
237   public double getImmunityDelay() {
238     return immunityDelay;
239   }
240 
241   /**
242    * Get the score sprite holding the life count for this ship.
243    *
244    @return  the {@link ScoreSprite} counting lives.
245    */
246   public ScoreSprite getLives() {
247     return lives;
248   }
249 
250   /**
251    * Get a bullet. Used to shoot the guns.
252    */
253   public LittleRoundProjectile getProjectile() {
254     if (shootingDelayRemaining <= 0{
255       // Calculate where the shot should originate.
256       // gunLocation is location, relative to original sized sprite
257       // rotate, scale, add to our location
258       Vector2D rotatedX = getFacingVector().normalize();
259       Vector2D rotatedY = rotatedX.getNormal();
260       Location2D shotDelta = GUN_LOCATION.multiply(getScale());
261       Location2D shotLocation = getLocation().add(rotatedX.multiply(
262             shotDelta.getX()).addTo(
263             rotatedY.multiply(shotDelta.getY())));
264 
265       LittleRoundProjectile projectile = new LittleRoundProjectile(
266           score);
267       projectile.setLocation(shotLocation);
268       projectile.setRotation(getRotation());// shoot straight ahead
269       projectile.addTransformer(new SpeedAheadTransformer(1.0));
270       projectile.addTimeToLive(0.9);
271       projectile.scale(1.5);
272       projectile.setColor(Game.getColor("orange red"));
273       if (targetClass != null{
274         projectile.addTarget(targetClass);
275       }
276       if (target != null{
277         projectile.addTarget(target);
278       }
279       shootingDelayRemaining = shootingDelay;
280       return projectile;
281     } else {
282       return null;
283     }
284   }
285 
286   /**
287    * Get the score display sprite
288    *
289    @return  the score display
290    */
291   public ScoreSprite getScore() {
292     return score;
293   }
294 
295   /**
296    @return  the shootingDelay
297    */
298   public double getShootingDelay() {
299     return shootingDelay;
300   }
301 
302   /**
303    @return  the target
304    */
305   public Sprite getTarget() {
306     return target;
307   }
308 
309   /**
310    @return  the targetClass
311    */
312   public Class<? extends Sprite> getTargetClass() {
313     return targetClass;
314   }
315 
316   /**
317    * Hide the remaining lives counter
318    */
319   public void hideLives() {
320     lives.hide();
321   }
322 
323   /**
324    * Hide the score display on the screen
325    */
326   public void hideScore() {
327     score.hide();
328   }
329 
330   /**
331    * What happens when this object collides with some other object it is
332    * programmed to interact with? Check for immunity; if not immune,
333    * make it react to us (so two ships hitting each react once) avoid
334    * recursion trap by setting immunityDelay before call to other object
335    * (it will make us react but next time we are immune so it only goes:
336    * A.react -> B.react -> A.react (when A and B are this and other on
337    * the first call.
338    */
339   public boolean react(Sprite other{
340     if (immunityDelayRemaining <= 0.0{
341       immunityDelayRemaining = 1.0;
342       HitTarget ht = (HitTargetother;
343       if (ht != null{
344         ht.react(this);
345       }
346       subtractALife();
347       return true;
348     }
349     return false;
350   }
351 
352   /**
353    @param  immunityDelay  the immunityDelay to set
354    */
355   public void setImmunityDelay(double immunityDelay{
356     this.immunityDelay = immunityDelay;
357   }
358 
359   /**
360    @param  shootingDelay  the shootingDelay to set
361    */
362   public void setShootingDelay(double shootingDelay{
363     this.shootingDelay = shootingDelay;
364   }
365 
366   /**
367    @param  targetClass  the targetClass to set
368    */
369   public void setTarget(Class<? extends Sprite> targetClass{
370     this.targetClass = targetClass;
371   }
372 
373   /**
374    @param  target  the target to set
375    */
376   public void setTarget(Sprite target{
377     this.target = target;
378   }
379 
380   /**
381    * What happens when this ship is shot?
382    */
383   public void shot(Sprite shooter{
384     subtractALife();
385   }
386 
387   /**
388    * Make the lives counter visible.
389    */
390   public void showLives() {
391     lives.show();
392   }
393 
394   /**
395    * Make the score display visible
396    */
397   public void showScore() {
398     score.show();
399   }
400 
401   /**
402    * Remove a life. Decrement the life counter and if the life count
403    * goes to 0, remove the ship from the game. Also reset the immunity
404    * timer.
405    */
406   public void subtractALife() {
407     lives.decrement();
408 
409     if (lives.getScore() <= 0{
410       lives.removeFromCanvas();
411       removeFromCanvas();
412     }
413 
414     immunityDelayRemaining = immunityDelay;
415   }
416 }
417 
418 //Uploaded on Mon Mar 29 21:40:58 EDT 2010


Download/View scg/ch01/spacesprites/Ship.java





Views
Personal tools
Add to 
del.icio.usAdd to 
diggAdd to 
FacebookAdd to 
favoritesAdd to 
GoogleAdd to 
MySpaceAdd to 
PrintAdd to 
SlashdotAdd to 
StumbleUponAdd to 
Twitter

Games
Games