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.

index.js 4.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. function randint(min, max) {
  2. return Math.floor(Math.random() * (max - min + 1)) + min;
  3. }
  4. function random(min, max) {
  5. return Math.random() * (max - min) + min;
  6. }
  7. class Vec2 {
  8. constructor(x, y) {
  9. this.x = x;
  10. this.y = y;
  11. }
  12. length() {
  13. return Math.sqrt((this.x * this.x) + (this.y * this.y));
  14. }
  15. clone() {
  16. return new Vec2(this.x, this.y);
  17. }
  18. set(x, y) {
  19. this.x = x;
  20. this.y = y;
  21. return this;
  22. }
  23. add(x, y) {
  24. this.x += x;
  25. this.y += y;
  26. return this;
  27. }
  28. scale(num) {
  29. this.x *= num;
  30. this.y *= num;
  31. return this;
  32. }
  33. normalize() {
  34. var len = this.length();
  35. if (len === 0) {
  36. this.x = 1;
  37. this.y = 0;
  38. } else {
  39. this.scale(1 / len);
  40. }
  41. return this;
  42. }
  43. rotate(rad) {
  44. let x = this.x;
  45. let y = this.y;
  46. this.x = x * Math.cos(rad) - y * Math.sin(rad);
  47. this.y = y * Math.cos(rad) + x * Math.sin(rad);
  48. return this;
  49. }
  50. }
  51. class Rectangle {
  52. constructor(x, y, width, height) {
  53. this.x = x;
  54. this.y = y;
  55. this.width = width;
  56. this.height = height;
  57. }
  58. }
  59. class Entity {
  60. constructor(x, y, width, height, id, game) {
  61. this.width = width;
  62. this.height = height;
  63. this.mass = width * height;
  64. this.forceScalar = 1/this.mass;
  65. this.id = id;
  66. this.game = game;
  67. this.pos = new Vec2(x, y);
  68. this.vel = new Vec2(0, 0);
  69. this.vforce = new Vec2(0, 0);
  70. }
  71. get boundingRect() {
  72. return new Rectangle(this.pos.x, this.pos.y, this.width, this.height);
  73. }
  74. move(dt) {
  75. this.vforce.scale(this.forceScalar * dt);
  76. this.vel.add(this.vforce.x, this.vforce.y);
  77. this.pos.add(this.vel.x * dt, this.vel.y * dt);
  78. this.vforce.set(0, 0);
  79. }
  80. force(x, y) {
  81. this.vforce.x += x;
  82. this.vforce.y += y;
  83. }
  84. impulse(x, y) {
  85. this.vel.x += x;
  86. this.vel.y += y;
  87. }
  88. init() {}
  89. update() {}
  90. send() {}
  91. despawn() {
  92. delete this.game.entities[this.id];
  93. delete this.game.players[this.id];
  94. this.game.players.forEach((p) => p.sock.send("despawn", {
  95. id: this.id
  96. }));
  97. }
  98. }
  99. class Bullet extends Entity {
  100. constructor(pos, vel, ownerId, id, game) {
  101. super(pos.x, pos.y, 5, 5, id, game);
  102. this.ownerId = ownerId;
  103. this.vel = vel;
  104. setTimeout(() => this.despawn(), 4000);
  105. }
  106. send() {
  107. this.game.players.forEach((p) => p.sock.send("set", {
  108. type: "bullet",
  109. id: this.id,
  110. ownerId: this.ownerId,
  111. pos: this.pos,
  112. vel: this.vel,
  113. }));
  114. }
  115. }
  116. class Player extends Entity {
  117. constructor(sock, id, game) {
  118. super(0, 0, 25, 60, id, game);
  119. this.sock = sock;
  120. this.keys = {};
  121. this.dead = false;
  122. this.rot = 0;
  123. this.rotForce = 0;
  124. this.rotVel = 0;
  125. this.canShoot = true;
  126. sock.on("request", (req) => {
  127. if (req.url == "get_id") {
  128. req.reply({
  129. id: this.id
  130. });
  131. } else if (req.url == "keydown") {
  132. this.keys[req.data.key] = true;
  133. } else if (req.url == "keyup") {
  134. this.keys[req.data.key] = false;
  135. }
  136. });
  137. sock.on("close", () => this.despawn());
  138. }
  139. update(dt) {
  140. let f = new Vec2(0, 0);
  141. if (this.keys.up)
  142. f.set(0, -0.1);
  143. if (this.keys.down)
  144. f.set(0, 0.1);
  145. if (this.keys.left)
  146. this.rotForce -= 0.005;
  147. if (this.keys.right)
  148. this.rotForce += 0.005;
  149. if (this.keys.shoot && this.canShoot) {
  150. let vel = new Vec2(0, -1).rotate(this.rot);
  151. let b = new Bullet(this.pos, vel, this.id, this.game.id, this.game);
  152. this.game.spawn(b);
  153. this.canShoot = false;
  154. setTimeout(() => this.canShoot = true, 100);
  155. }
  156. f.rotate(this.rot);
  157. this.force(f.x, f.y);
  158. }
  159. move(dt) {
  160. super.move(dt);
  161. this.rotForce *= this.forceScalar * dt;
  162. this.rotVel += this.rotForce;
  163. this.rot += this.rotVel * dt;
  164. this.rotForce = 0;
  165. }
  166. send() {
  167. this.game.players.forEach((p) => p.sock.send("set", {
  168. type: "player",
  169. id: this.id,
  170. pos: this.pos,
  171. vel: this.vel,
  172. rot: this.rot,
  173. rotVel: this.rotVel
  174. }));
  175. }
  176. }
  177. export default class Game {
  178. constructor() {
  179. this.entities = [];
  180. this.players = [];
  181. this.timeout = null;
  182. this.prevTime = null;
  183. this.fps = 10;
  184. this.id = 1;
  185. }
  186. newPlayer(sock) {
  187. let p = new Player(sock, this.id, this);
  188. this.players[this.id] = p;
  189. this.spawn(p);
  190. }
  191. spawn(ent) {
  192. this.entities[this.id] = ent;
  193. this.id += 1;
  194. }
  195. start() {
  196. this.prevTime = new Date().getTime();
  197. this.update();
  198. }
  199. stop() {
  200. clearTimeout(this.timeout);
  201. }
  202. update() {
  203. let dt = new Date().getTime() - this.prevTime;
  204. this.prevTime = new Date().getTime();
  205. this.entities.forEach((e) => {
  206. if (e.dead)
  207. delete this.entities[e.id];
  208. else
  209. e.move(dt);
  210. });
  211. this.entities.forEach((e) => e.update());
  212. this.entities.forEach((e) => e.send(this.players));
  213. this.timeout = setTimeout(this.update.bind(this), 1000/this.fps);
  214. }
  215. }