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.

Level.js 2.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import structures from "./structures.js";
  2. export default class Level {
  3. constructor(canvas) {
  4. this.canvas = canvas;
  5. this.ctx = canvas.getContext("2d");
  6. this.lastTime = null;
  7. this.raf = null;
  8. this.minPhysFPS = 20;
  9. this.minFPS = 5;
  10. this.backgroundColor = "#87CEFA";
  11. this.entities = [];
  12. this.colliders = [];
  13. this.structures = [];
  14. this.evts = [];
  15. }
  16. spawnEntity(ent, x, y) {
  17. ent.bounds.pos.set(x, y);
  18. this.entities.push(ent);
  19. if (ent.has("collider"))
  20. this.colliders.push(ent);
  21. ent._init();
  22. }
  23. spawnStructure(structure, x, y) {
  24. structure.bounds.pos.set(x, y);
  25. this.structures.push(structure);
  26. structure.init();
  27. }
  28. physics(dt) {
  29. this.entities.forEach(ent =>
  30. ent._update(dt));
  31. this.entities.forEach(ent =>
  32. ent._postUpdate(dt));
  33. // Collide with structures
  34. this.structures.forEach(s => {
  35. if (!s.attrs.wall && !s.attrs.platform)
  36. return;
  37. this.colliders.forEach(ent => {
  38. let bounds = s.collidesWith(ent.bounds);
  39. if (!bounds)
  40. return;
  41. ent.t.collider.collideStructure(s, bounds);
  42. });
  43. });
  44. // Collide with entities
  45. this.colliders.forEach(ent => {
  46. this.colliders.forEach(ent2 => {
  47. if (ent === ent2 || !ent.bounds.intersects(ent2.bounds))
  48. return;
  49. ent.t.collider.collideEntity(ent2);
  50. });
  51. });
  52. }
  53. draw() {
  54. this.ctx.resetTransform();
  55. this.ctx.beginPath();
  56. this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
  57. this.entities.forEach(ent => ent.draw(this.ctx));
  58. this.structures.forEach(struct => struct.draw(this.ctx));
  59. }
  60. update(time) {
  61. if (this.lastTime != null) {
  62. let dt = (time - this.lastTime) / 1000;
  63. if (1 / dt < this.minFPS) {
  64. console.log(
  65. "Too long between updates ("+dt.toFixed(2)+"s, "+
  66. (1 / dt).toFixed(2)+"FPS). Skipping.");
  67. } else {
  68. // We accept really low FPSes,
  69. // but if the FPS gets too low, we want to run multiple
  70. // physics steps in the frame.
  71. let physdt = dt;
  72. let nSteps = 1;
  73. while (1 / physdt < this.minPhysFPS) {
  74. physdt /= 2;
  75. nSteps *= 2;
  76. }
  77. if (nSteps > 1) {
  78. console.log(
  79. "Too long between frames for physics ("+dt.toFixed(2)+"s). "+
  80. "Running "+nSteps+" simulations in one frame.");
  81. }
  82. for (let i = 0; i < nSteps; ++i)
  83. this.physics(physdt);
  84. }
  85. this.draw();
  86. }
  87. this.lastTime = time;
  88. this.raf = requestAnimationFrame(this.update.bind(this));
  89. }
  90. start() {
  91. this.canvas.style.background = this.backgroundColor;
  92. if (this.raf == null) {
  93. this.lastTime = null;
  94. this.update();
  95. console.log("Started.");
  96. }
  97. }
  98. stop() {
  99. if (this.raf != null) {
  100. cancelAnimationFrame(this.raf);
  101. this.raf = null;
  102. console.log("Stopped.");
  103. }
  104. }
  105. }