You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Ship.java 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. package spacewar;
  2. class Ship extends SpaceObject {
  3. pointcut helmCommandsCut(Ship ship):
  4. target(ship) && ( call(void rotate(int)) ||
  5. call(void thrust(boolean)) ||
  6. call(void fire()) );
  7. /**
  8. * Energy and Damage are key values in the state of a ship. Energy is
  9. * basically about fuel, and damage is about how bad a shape we are in.
  10. *
  11. * The energy related values are:
  12. * MAX_ENERGY
  13. * BULLET_ENERGY
  14. * ACCELERATION_ENERGY_FACTOR
  15. * energy
  16. *
  17. * The damage related values are:
  18. * MAX_DAMAGE
  19. * BULLET_DAMAGE
  20. * COLLISION_DAMAGE_FACTOR
  21. * damage
  22. *
  23. * Finally, REPAIR_RATE is the rate at which energy is consumed to fix
  24. * damage.
  25. *
  26. */
  27. private static final int MAX_ENERGY = 100;
  28. private static final int BULLET_ENERGY= 2;
  29. private static final double ACCELERATION_COST_FACTOR = 0.05;
  30. //XXX was private
  31. static final int MAX_DAMAGE = 100;
  32. private static final int BULLET_DAMAGE = 15;
  33. private static final double COLLISION_DAMAGE_FACTOR = 0.1;
  34. private static final double REPAIR_RATE = 0.08;
  35. private static final int EXPLOSION_LENGTH = 10;
  36. static final int BULLET_SPEED = 10;
  37. static final int CLOCKWISE = 1;
  38. static final int STOP = 0;
  39. static final int COUNTERCLOCKWISE = (-1);
  40. static final double DEFAULT_ANGULAR_VELOCITY = 0.2;
  41. static final double DEFAULT_ACCELERATION = .4;
  42. static private final int SIZE = 30; //Can't be changed for now!!!
  43. private double energy; // range: 0 to MAX_ENERGY
  44. private double damage; // range: 0 to MAX_DAMAGE
  45. private double orientation; // in degrees
  46. private double angularVel; // in ???
  47. private double xAcc, yAcc, rAcc; //
  48. private int countdown; // remaining explosion time
  49. private Pilot pilot;
  50. Ship(Game theGame, double xPos, double yPos, double orientation) {
  51. super(theGame, xPos, yPos, 0, 0);
  52. xAcc = 0;
  53. yAcc = 0;
  54. this.orientation = orientation;
  55. angularVel = 0;
  56. energy = MAX_ENERGY;
  57. damage = 0;
  58. countdown = EXPLOSION_LENGTH;
  59. }
  60. int getSize() { return SIZE; }
  61. double getEnergy() { return energy; }
  62. double getDamage() { return damage; }
  63. double getOrientation() { return orientation; }
  64. double getRAcc() { return rAcc; }
  65. Pilot getPilot() { return pilot; }
  66. void setPilot (Pilot p) { pilot = p; }
  67. float getEnergyLevel() {
  68. return (float)energy / (float)MAX_ENERGY;
  69. }
  70. float getDamageLevel() {
  71. return (float)damage / (float)MAX_DAMAGE;
  72. }
  73. // returns false if energy is out, otherwise decrements energy by amount
  74. // and returns true
  75. boolean expendEnergy(double amount) {
  76. if (amount <= energy) {
  77. energy -= amount;
  78. return true;
  79. }
  80. else
  81. return false;
  82. }
  83. // increments damage by amount and handles the destruction of a ship if
  84. // damage reaches MAX_DAMAGE.
  85. void inflictDamage(double amount) {
  86. if (amount < 0) // shouldn't happen
  87. return;
  88. damage = Math.min(MAX_DAMAGE, damage + amount);
  89. if (damage == MAX_DAMAGE)
  90. setIsAlive(false);
  91. }
  92. void repairDamage(double amount) {
  93. if (amount < 0) // shouldn't happen
  94. return;
  95. if (damage == 0)
  96. return;
  97. damage = Math.max(0, damage - amount);
  98. }
  99. public void clockTick() {
  100. if (! isAlive()) {
  101. //
  102. // If we aren't alive, but we are still in the registry, it means
  103. // we are exploding. countdown counts the length of the explosion.
  104. //
  105. if (--countdown == 0)
  106. die();
  107. }
  108. else {
  109. if (angularVel != 0) {
  110. orientation += angularVel;
  111. xAcc = rAcc * Math.cos(orientation);
  112. yAcc = rAcc * Math.sin(orientation);
  113. }
  114. setXVel(getXVel() + xAcc);
  115. setYVel(getYVel() + yAcc);
  116. //expend energy
  117. if (!expendEnergy(rAcc * ACCELERATION_COST_FACTOR))
  118. rAcc = xAcc = yAcc = 0;
  119. // fix damage
  120. if (energy > 10 && damage > REPAIR_RATE) {
  121. expendEnergy(REPAIR_RATE);
  122. repairDamage(REPAIR_RATE);
  123. }
  124. }
  125. super.clockTick();
  126. }
  127. /**
  128. * First check to make sure we have enough energy to accelerate. If
  129. * we do, then go ahead and do so. Acceleration is in the direction
  130. * we are already facing (i.e. orientation).
  131. */
  132. void setAcceleration(double acc) {
  133. if (acc * ACCELERATION_COST_FACTOR <= energy) {
  134. rAcc = acc;
  135. xAcc = rAcc * Math.cos(orientation);
  136. yAcc = rAcc * Math.sin(orientation);
  137. }
  138. }
  139. void setAngularVelocity(double omega) {
  140. // changing direction of rotation takes energy
  141. if (!expendEnergy(Math.abs(omega - angularVel) / 2))
  142. return;
  143. //sets amount of degree rotation per clock tick, in radians;
  144. //clockwise is positive
  145. angularVel = omega;
  146. }
  147. void rotate(int direction) {
  148. setAngularVelocity(
  149. direction == CLOCKWISE ? DEFAULT_ANGULAR_VELOCITY :
  150. direction == COUNTERCLOCKWISE ? -DEFAULT_ANGULAR_VELOCITY :
  151. 0);
  152. }
  153. void thrust(boolean onOff) {
  154. setAcceleration(onOff ? DEFAULT_ACCELERATION : 0);
  155. }
  156. void fire() {
  157. // firing a shot takes energy
  158. if (!expendEnergy(BULLET_ENERGY))
  159. return;
  160. //create a bullet object so it doesn't hit the ship that's firing it
  161. double xV = getXVel() + BULLET_SPEED * (Math.cos(orientation));
  162. double yV = getYVel() + BULLET_SPEED * (Math.sin(orientation));
  163. // create the actual bullet
  164. new Bullet(
  165. getGame(),
  166. (getXPos() + ((getSize()/2 + 2) * (Math.cos(orientation))) + xV),
  167. (getYPos() + ((getSize()/2 + 2) * (Math.sin(orientation))) + yV),
  168. xV,
  169. yV);
  170. }
  171. void handleCollision(SpaceObject obj) {
  172. if (obj instanceof Ship) {
  173. // should never be called. ship - ship collisions are handled in
  174. // Ship.bounce(Ship shipA, Ship shipB)
  175. }
  176. else if (obj instanceof Bullet) {
  177. inflictDamage(BULLET_DAMAGE);
  178. }
  179. else if (obj instanceof EnergyPacket) {
  180. double packetEnergy = ((EnergyPacket)obj).getEnergy();
  181. energy = Math.max(0, Math.min(energy + packetEnergy, MAX_ENERGY));
  182. }
  183. else {
  184. System.err.println("collision with UFO!");
  185. }
  186. }
  187. static void bounce(Ship shipA, Ship shipB) {
  188. double dx, dy, denominator,
  189. xAccA, yAccA, xAccB, yAccB, damage,
  190. xComp, yComp, dvx, dvy;
  191. dx = Math.abs(shipA.getXPos() - shipB.getXPos());
  192. dy = Math.abs(shipA.getYPos() - shipB.getYPos());
  193. denominator = Math.sqrt(dx * dx + dy * dy);
  194. xComp = dx / denominator;
  195. yComp = dy / denominator;
  196. xAccA = shipB.getXVel() * xComp + shipA.getXVel() * (1 - xComp) -
  197. shipA.getXVel();
  198. yAccA = shipB.getYVel() * yComp + shipA.getYVel() * (1 - yComp) -
  199. shipA.getYVel();
  200. xAccB = shipA.getXVel() * xComp + shipB.getXVel() * (1 - xComp) -
  201. shipB.getXVel();
  202. yAccB = shipA.getYVel() * yComp + shipB.getYVel() * (1 - yComp) -
  203. shipB.getYVel();
  204. shipA.accelerate(xAccA, yAccA);
  205. shipB.accelerate(xAccB, yAccB);
  206. dvx = shipA.getXVel() - shipB.getXVel();
  207. dvy = shipA.getYVel() - shipA.getYVel();
  208. damage = COLLISION_DAMAGE_FACTOR * (dvx * dvx + dvy * dvy);
  209. shipA.inflictDamage(damage);
  210. shipB.inflictDamage(damage);
  211. // !!!
  212. // !!! poopers! this does a local time warp. this has to be a
  213. // !!! violation of the clockTick protocol
  214. // !!!
  215. while (Game.isCollision(shipA, shipB)) {
  216. shipA.clockTick();
  217. shipB.clockTick();
  218. }
  219. }
  220. }