render-engine.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import * as three from "three-js";
  2. import { actor } from "./actor.js";
  3. import { factor } from "./factor.js";
  4. class render_engine {
  5. #renderer;
  6. #scene;
  7. #camera;
  8. #canvas;
  9. #actors;
  10. #player;
  11. #looped;
  12. constructor(canvas, context, player) {
  13. if (!(canvas instanceof HTMLCanvasElement)) {
  14. throw new TypeError("Canvas must be an HTMLCanvasElement.");
  15. }
  16. if (!(context instanceof WebGL2RenderingContext)) {
  17. throw new TypeError("Context must be WebGL RenderingContext.");
  18. }
  19. if (!(player instanceof actor)) {
  20. throw new TypeError("Player must be an actor.");
  21. }
  22. this.#actors = new Array();
  23. this.#player = player;
  24. this.#canvas = canvas;
  25. this.#scene = new three.Scene();
  26. this.#camera = new three.PerspectiveCamera(75, 1, 0.1, 1000);
  27. this.#renderer = new three.WebGLRenderer({
  28. canvas: this.#canvas,
  29. context: context
  30. });
  31. this.#renderer.shadowMap.enable = true;
  32. this.#renderer.shadowMap.type = three.BasicShadowMap;
  33. this.#resize_canvas();
  34. this.#update_camera();
  35. window.addEventListener("resize", () => {
  36. this.#resize_canvas();
  37. this.#update_camera();
  38. });
  39. }
  40. get player() {
  41. return this.#player;
  42. }
  43. get canvas() {
  44. return this.#canvas;
  45. }
  46. set background(target) {
  47. if (typeof(target) !== "number") {
  48. throw new TypeError("Background must be an number.");
  49. }
  50. this.#scene.background = target;
  51. }
  52. get background() {
  53. return this.#scene.background;
  54. }
  55. #resize_canvas() {
  56. this.#canvas.width = window.innerWidth;
  57. this.#canvas.height = window.innerHeight;
  58. this.#renderer.setSize(this.#canvas.width, this.#canvas.height);
  59. }
  60. #update_camera() {
  61. this.#camera.aspect = this.#canvas.width / this.#canvas.height;
  62. this.#camera.updateProjectionMatrix();
  63. }
  64. run() {
  65. this.#looped = true;
  66. this.#loop();
  67. }
  68. stop() {
  69. this.#looped = false;
  70. }
  71. #loop() {
  72. if (!this.#looped) {
  73. return;
  74. }
  75. const start = performance.now();
  76. this.#render();
  77. const stop = performance.now();
  78. const tooked = stop - start;
  79. const new_frame = 1000 / 60 - tooked;
  80. if (new_frame <= 0) {
  81. setTimeout(() => { this.#loop(); }, 1);
  82. return;
  83. }
  84. setTimeout(() => { this.#loop(); }, new_frame);
  85. }
  86. add_factor(target) {
  87. if (!(target instanceof factor)) {
  88. throw new TypeError("New factor must be in factor class.");
  89. }
  90. this.#actors.push(target);
  91. this.#scene.add(target.mesh);
  92. }
  93. #sync_camera() {
  94. this.#player.update();
  95. this.#camera.position.x = this.#player.x;
  96. this.#camera.position.z = this.#player.y;
  97. this.#camera.rotation.y
  98. = three.MathUtils.degToRad(this.#player.rotate);
  99. }
  100. #render() {
  101. this.#sync_camera();
  102. this.#actors.forEach(actor => {
  103. actor.loop();
  104. });
  105. this.#renderer.render(this.#scene, this.#camera);
  106. }
  107. }
  108. export { render_engine };