ship.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. function Ship(game, controller) {
  2. this.id = 0;
  3. this.position = {x: 400, y: 300};
  4. this.velocity = {x: 0.1, y: 0.1};
  5. this.controller = controller;
  6. this.acceleration = {x: 0, y: 0, speed: 0.08};
  7. this.width = 20;
  8. this.height = 20;
  9. this.maxSpeed = 24;
  10. this.turnRate = Math.PI / 64;
  11. this.moveToTarget = false;
  12. this.targetDestination = {x: 400, y: 400};
  13. this.targetAngle = 0;
  14. this.angleRadians = 0;
  15. this.shipColor = "#DD3333";
  16. this.playerName = "Player";
  17. this.spriteCanvas = null;
  18. this.spriteContext = null;
  19. this.isAccelerating = false;
  20. this.home = null;
  21. this.spawn = null;
  22. this.isDead = false;
  23. this.touching = null;
  24. this.lastHit = 0;
  25. this.teamId = 0;
  26. this.health = 5;
  27. this.maxHealth = 5;
  28. this.shotDelay = 10;
  29. this.init = function(systemColor, homeSystem) {
  30. this.teamId = homeSystem.teamId;
  31. this.controller.init();
  32. this.shipColor = systemColor;
  33. this.home = homeSystem;
  34. this.respawn();
  35. }
  36. this.update = function(delta) {
  37. this.shotDelay = Math.max(0, this.shotDelay - 1);
  38. if(this.isDead) {
  39. return;
  40. }
  41. if(this.health <= 0) {
  42. this.die();
  43. return;
  44. }
  45. this.acceleration.x = 0;
  46. this.acceleration.y = 0;
  47. if(this.isAccelerating) {
  48. this.angleRadians = this.targetAngle;
  49. this.acceleration.x = this.acceleration.speed * Math.cos(this.angleRadians);
  50. this.acceleration.y = this.acceleration.speed * Math.sin(this.angleRadians);
  51. if(this.touching != null) {
  52. this.touching = null;
  53. var liftoffSpeed = 2.0;
  54. this.velocity.x = liftoffSpeed * Math.cos(this.angleRadians);
  55. this.velocity.y = liftoffSpeed * Math.sin(this.angleRadians);
  56. }
  57. }
  58. this.velocity.x = Math.max(Math.min(this.velocity.x, this.maxSpeed), -this.maxSpeed);
  59. this.velocity.y = Math.max(Math.min(this.velocity.y, this.maxSpeed), -this.maxSpeed);
  60. var nearestSystem = game.getNearestSystem(game, this);
  61. if(nearestSystem != null) {
  62. nearestSystem.addGravity(this);
  63. for(var index in nearestSystem.planets) {
  64. var planet = nearestSystem.planets[index];
  65. planet.addGravity(this);
  66. }
  67. } else {
  68. throw new Error("Ship lost in space", ship);
  69. }
  70. this.velocity.x += this.acceleration.x;
  71. this.velocity.y += this.acceleration.y;
  72. if(this.touching != null) {
  73. var angle = game.calculateAngleTo(this.touching, this) + Math.PI;
  74. var dist = game.calculateDistanceTo(this.touching, this);
  75. var magnitude = 0;
  76. if(this.touching.radius + (this.width / 2) > dist) {
  77. this.angleRadians = angle;
  78. this.targetAngle = angle;
  79. magnitude = this.touching.radius - dist;
  80. var landedVector = {x: 0, y: 0};
  81. landedVector.x = (magnitude + (this.width / 2)) * Math.cos(angle);
  82. landedVector.y = (magnitude + (this.height / 2)) * Math.sin(angle);
  83. this.position.x += landedVector.x;
  84. this.position.y += landedVector.y;
  85. this.velocity.x = 0;
  86. this.velocity.y = 0;
  87. this.touching.claim(this);
  88. }
  89. } else {
  90. this.position.x += this.velocity.x * delta;
  91. this.position.y += this.velocity.y * delta;
  92. }
  93. if(this.position.x > 62880) {
  94. this.position.x = -62880;
  95. } else if (this.position.x < -62880) {
  96. this.position.x = 62880;
  97. }
  98. if(this.position.y > 62880) {
  99. this.position.y = -62880;
  100. } else if (this.position.y < -62880) {
  101. this.position.y = 62880;
  102. }
  103. }
  104. this.control = function() {
  105. this.controller.makeDecisions(this);
  106. }
  107. this.setSpawn = function(planet) {
  108. this.spawn = planet;
  109. }
  110. this.respawn = function() {
  111. let self = this;
  112. if(this.spawn == null || this.spawn.teamId != this.teamId) {
  113. var homePlanets = [];
  114. for(var index in game.planets) {
  115. var planet = game.planets[index];
  116. if(planet.teamId == this.teamId && planet.type == "habitable") {
  117. homePlanets.push(planet);
  118. }
  119. }
  120. this.setSpawn(homePlanets[parseInt(homePlanets.length * Math.random())]);
  121. }
  122. this.position.x = this.spawn.position.x;
  123. this.position.y = this.spawn.position.y;
  124. if(!this.spawn.canSpawnShip()) {
  125. this.spawn = null;
  126. setTimeout(function() {self.respawn();}, 1000);
  127. return;
  128. }
  129. var angle = (2 * Math.PI) * Math.random();
  130. this.position.x = this.spawn.position.x + (this.spawn.radius * Math.cos(angle));
  131. this.position.y = this.spawn.position.y + (this.spawn.radius * Math.sin(angle));
  132. this.health = this.maxHealth;
  133. this.angleRadians = angle;
  134. this.isAccelerating = false;
  135. this.isDead = false;
  136. this.controller.reset(this);
  137. this.shotDelay = 0;
  138. this.spawn.spawnShip();
  139. }
  140. this.die = function() {
  141. this.health = 0;
  142. if(!this.isDead) {
  143. this.velocity.x /= 4;
  144. this.velocity.y /= 4;
  145. //spawn debris
  146. for(var i = 0; i < 5; i++) {
  147. this.targetAngle = (2 * Math.PI) * Math.random();
  148. game.spawnBullet(this);
  149. }
  150. var ship = this;
  151. setTimeout(function() {ship.respawn();}, 3000);
  152. this.isDead = true;
  153. }
  154. }
  155. this.idle = function() {
  156. this.isAccelerating = false;
  157. }
  158. this.toggleAccelerate = function() {
  159. if(this.isAccelerating) {
  160. this.idle();
  161. } else {
  162. this.accelerate();
  163. }
  164. }
  165. this.accelerate = function() {
  166. this.isAccelerating = true;
  167. }
  168. this.shoot = function() {
  169. if(this.isDead) {
  170. return;
  171. }
  172. if(this.shotDelay == 0) {
  173. game.spawnBullet(this);
  174. this.shotDelay = 5;
  175. }
  176. };
  177. this.turnLeft = function() {
  178. if(this.touching != null) {
  179. return;
  180. }
  181. this.targetAngle -= this.turnRate;
  182. };
  183. this.turnRight = function() {
  184. if(this.touching != null) {
  185. return;
  186. }
  187. this.targetAngle += this.turnRate;
  188. };
  189. this.preRender = function(context, angle) {
  190. if(angle == null) {
  191. angle = 0;
  192. }
  193. context.fillStyle = this.shipColor;
  194. context.strokeStyle = this.shipColor;
  195. context.lineWidth = 4;
  196. context.save();
  197. context.translate(this.width / 2, this.height / 2);
  198. context.rotate(angle);
  199. context.beginPath();
  200. context.moveTo(this.width / 2, 0);
  201. context.lineTo(-(this.width / 2), -(this.height / 3));
  202. context.lineTo(-(this.width / 2), this.height / 3);
  203. context.lineTo(this.width / 2, 0);
  204. context.fill();
  205. context.restore();
  206. }
  207. this.draw = function(context) {
  208. if(this.spriteContext == null) {
  209. this.spriteCanvas = document.createElement("canvas");
  210. this.spriteCanvas.width = this.width;
  211. this.spriteCanvas.height = this.height;
  212. this.spriteContext = this.spriteCanvas.getContext("2d");
  213. this.preRender(this.spriteContext);
  214. }
  215. if(this.isDead) {
  216. return;
  217. }
  218. var truePos = {x: 0, y: 0};
  219. truePos.x = this.position.x;
  220. truePos.y = this.position.y;
  221. context.save();
  222. context.translate(truePos.x, truePos.y);
  223. context.rotate(this.targetAngle);
  224. if(this.isAccelerating) {
  225. context.fillStyle = "#7777FF";
  226. context.beginPath();
  227. context.moveTo(-this.width - 5, 0);
  228. context.lineTo(-this.width / 2, 3);
  229. context.lineTo(-this.width / 2, -3);
  230. context.lineTo(-this.width - 5, 0);
  231. context.fill();
  232. }
  233. context.drawImage(this.spriteCanvas, 0, 0, this.spriteCanvas.width, this.spriteCanvas.height,
  234. -this.spriteCanvas.width / 2, -this.spriteCanvas.height /2 , this.width, this.height);
  235. context.strokeStyle = "#00FF00";
  236. if(this.isTakingDamage) {
  237. context.strokeStyle = "#FF0000";
  238. this.isTakingDamage = false;
  239. }
  240. /*context.lineWidth = 1;
  241. context.beginPath();
  242. context.arc(0, 0, this.width / 2, 0, 2 * Math.PI);
  243. context.stroke();*/
  244. context.restore();
  245. context.save();
  246. context.translate(truePos.x, truePos.y);
  247. context.font = "16px sans-serif";
  248. context.textAlign = "center";
  249. context.fillStyle = "#DDDDDD";
  250. context.strokeStyle = "#333333";
  251. context.lineWidth = 2;
  252. var textMetrics = context.measureText("Player " + this.id);
  253. var textWidth = textMetrics.width;
  254. context.fillText("Player " + this.id, 0, 0);
  255. context.restore();
  256. this.controller.debugDraw(this, context);
  257. }
  258. this.takeDamage = function(damageAmount, ownerId) {
  259. this.isTakingDamage = true;
  260. this.health -= damageAmount;
  261. this.lastHit = ownerId;
  262. }
  263. this.checkHit = function(ship) {
  264. var distance = Math.sqrt(Math.pow(ship.position.x - this.position.x, 2) + Math.pow(ship.position.y - this.position.y, 2));
  265. if(this.id != ship.id && ship.width / 2 >= distance) {
  266. //ship.takeDamage(1);
  267. this.takeDamage(1);
  268. this.lastHit = ship.id;
  269. }
  270. }
  271. };