import java.awt.*; import java.lang.Math; /** Most of the ShipSprite code is copied directly from PointSprite (not subclassed... I want each to have a final updatePosition method for performance reasons). However, this sprite controls the direction it "points" when rotateClockwise() and rotateCounterclockwise() are called. */ public class ShipSprite extends HardlySprite { Sequence spriteSeq; int segments; float arc, pointing; boolean isRotating; boolean isExploding; // boolean isInvulnerable; boolean thrustOn; static final float TWOPI = (float) (2 * Math.PI); static final float FRICTION = 5.0F; //decelerating effect of friction, in pixels/sec/sec static final float THRUST = 75.0F; //strength of thrust, in pixels/sec/sec static final float MAX_SPEED = 200.0F; // not currently used. Like Montana, no speed limit float maxRotateSpeed = TWOPI; float rotateSpeed = 0; float scratchAngle; long resumeTime; public final String plagarismReallySucks = "(c)1997 Chris Adamson. http://www.mindspring.com/~plucky/"; /** Creates a ShipSprite @param spriteSeq Sequence of images with all available directions. The first should point right (0 radians). @param world SpriteWorld which contains the sprite @param x Inital x-coordinate, in pixels @param y Initial y-coordinate, in pixels @param direction Initial direction, in radians, with 0 as due right @param speed Initial speed, in pixels-per-second */ public ShipSprite (Sequence spriteSeq, SpriteWorld world, int x, int y, float direction, float speed, float pointing) { super (spriteSeq.imageAt(0), world, x, y, direction, speed); this.spriteSeq = spriteSeq; this.pointing = pointing; segments = spriteSeq.getLength(); arc = TWOPI / segments; changeImage (spriteSeq.imageAt (whichSegment (this.pointing))); isRotating = false; // isInvulnerable = false; // thrustOn = false; isExploding = false; } // main constructor /** Determines which image in the Sequence should be used. Like PointSprite, ShipSprite has an arc, determined by dividing 2 PI (ie, 360 degrees) by the number of images in the Sequence. For example, an 8-frame sequence has arcs of 45 degrees each. Pointed images are centered within this arc. Therefore, the first image, painted to face due right, handles directions from 337.5 degrees (ie, -22.5) to 22.5. The next image is used from 22.5 degrees to 67.5, etc. @param angle The angle to point towards, in radians @return The index of the correct image in the Sequence */ private final int whichSegment (float angle) { if (angle <= arc/2) return 0; if (angle >= (TWOPI - arc/2)) return 0; return (int) ((angle + arc/2) / arc); } // whichSegment /** Just finalizes HardlySprite's setDirection. Doesn't change pointing like PointSprite can @param direction Sprite's new movement direction in radians */ public final void setDirection (float direction) { super.setDirection (direction); } // setDirection - radians /** Just finalizes HardlySprite's setDirection. Doesn't change pointing like PointSprite can @param direction Sprite's new movement direction in degrees */ public final void setDirection (int degrees) { super.setDirection (degrees); } // setDirection - degrees /** Changes the sprite's image to point to the specified direction @param direction The direction to point towards, in radians */ public final void setPointing (float direction) { changeImage (spriteSeq.imageAt ( whichSegment (direction))); } // setPointing - radians /** Changes the sprite's image to point to the specified direction @param degrees The direction to point towards, in degrees */ public final void setPointing (int degrees) { changeImage (spriteSeq.imageAt ( whichSegment (degrees * TWOPI / 360))); } // setPointing - degrees /** Changes the Sequence used by this sprite. Notes its new arc and size, and changes onscreen image. @param newSequence The new Sequence this sprite is to use */ public final void changeSequence (Sequence newSequence) { spriteSeq = newSequence; segments = spriteSeq.getLength(); arc = TWOPI / segments; // Make this point to the current pointing angle changeImage (spriteSeq.imageAt ( whichSegment (getDirection()))); width = spriteImage.getWidth(world); height = spriteImage.getWidth(world); } // changeSequence /** Calls HardlySprite's updatePosition(), calculates pointing direction and changes image appropriately. This version is final, in hopes of restoring speed lost by making superclass' updatePosition() overridable. */ public final boolean updatePosition () { // applyFriction(); if (!isExploding) { super.updatePosition(); } if (isRotating) { scratchAngle = rotateSpeed * timeSliceSeconds; pointing += scratchAngle; if (pointing < 0) { pointing += TWOPI; } else if (pointing > TWOPI) { pointing -= TWOPI; } changeImage (spriteSeq.imageAt (whichSegment(pointing))); } if (isExploding) { if (System.currentTimeMillis() > resumeTime) { setX (world.getWidth() / 2); setY (world.getHeight() / 2); setSpeed (0); super.setDirection (0f); isExploding = false; return false; } // if time to resume } return true; } // updatePosition() public final void rotateClockwise() { isRotating = true; rotateSpeed = maxRotateSpeed; }// rotateClockwise public final void rotateCounterclockwise() { isRotating = true; rotateSpeed = -1 * maxRotateSpeed; }// rotateCounterclockwise public final void stopRotating() { isRotating = false; }// stopRotating public final void thrust () { if (!isExploding) { setThrusting (pointing, THRUST); }// if not exploding }//thrust public final void applyFriction() { if (getSpeed() > 0) { float decelerated = getSpeed() - (FRICTION * timeSlice / 1000f); setSpeed ((decelerated > 0) ? decelerated : 0); } }//applyFriction public final float getPointing() { return pointing; } // getPointing public final void setExploding (boolean exploding) { this.isExploding = exploding; } // setInvulnerability public final boolean isExploding () { return isExploding; } //getInvulnerability public final void explode() { resumeTime = System.currentTimeMillis() + 3000; isExploding = true; isRotating = false; stopThrusting(); setX (world.getWidth()); setY (world.getHeight()); } } /* ShipSprite */