render-engine.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import * as three from "three-js";
  2. import { actor } from "./actor.js";
  3. class render_engine {
  4. #renderer;
  5. #scene;
  6. #camera;
  7. #canvas;
  8. #actors;
  9. #player;
  10. #looped;
  11. constructor(canvas, context, player) {
  12. if (!(canvas instanceof HTMLCanvasElement)) {
  13. throw new TypeError("Canvas must be an HTMLCanvasElement.");
  14. }
  15. if (!(context instanceof WebGLRenderingContext)) {
  16. throw new TypeError("Context must be WebGL RenderingContext.");
  17. }
  18. if (!(player instanceof actor)) {
  19. throw new TypeError("Player must be an actor.");
  20. }
  21. this.#actors = {};
  22. this.#player = player;
  23. this.#canvas = canvas;
  24. this.#scene = new three.Scene();
  25. this.#scene.background = new three.Color(0x101010);
  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. #resize_canvas() {
  41. this.#canvas.width = window.innerWidth;
  42. this.#canvas.height = window.innerHeight;
  43. this.#renderer.setSize(this.#canvas.width, this.#canvas.height);
  44. }
  45. #update_camera() {
  46. this.#camera.aspect = this.#canvas.width / this.#canvas.height;
  47. this.#camera.updateProjectionMatrix();
  48. }
  49. run() {
  50. this.#looped = true;
  51. this.#init();
  52. this.#loop();
  53. }
  54. stop() {
  55. this.#looped = false;
  56. }
  57. #loop() {
  58. if (!this.#looped) {
  59. return;
  60. }
  61. const start = performance.now();
  62. this.#render();
  63. const stop = performance.now();
  64. const tooked = stop - start;
  65. const new_frame = 1000 / 60 - tooked;
  66. if (new_frame <= 0) {
  67. setTimeout(() => { this.#loop(); }, 1);
  68. return;
  69. }
  70. setTimeout(() => { this.#loop(); }, new_frame);
  71. }
  72. #init() {
  73. const geometry = new three.BoxGeometry(1, 1, 1);
  74. const material = new three.MeshStandardMaterial({ color: 0x009000 });
  75. this.#actors.cube = new three.Mesh(geometry, material);
  76. this.#actors.cube.position.x = 10;
  77. this.#actors.cube.position.y = 0;
  78. this.#actors.cube.position.z = 10;
  79. const light = new three.HemisphereLight(0x707070);
  80. light.position.x = 0;
  81. light.position.y = 10;
  82. light.position.z = 0;
  83. this.#scene.add(this.#actors.cube);
  84. this.#scene.add(light);
  85. this.#camera.position.y = 0;
  86. this.#player.rotate = 270;
  87. }
  88. #sync_camera() {
  89. this.#player.update();
  90. this.#camera.position.x = this.#player.x;
  91. this.#camera.position.z = this.#player.y;
  92. this.#camera.rotation.y
  93. = three.MathUtils.degToRad(this.#player.rotate);
  94. }
  95. #render() {
  96. this.#sync_camera();
  97. this.#actors.cube.rotation.x += 0.01;
  98. this.#actors.cube.rotation.y += 0.01;
  99. this.#renderer.render(this.#scene, this.#camera);
  100. }
  101. }
  102. export { render_engine };