UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

194 lines (152 loc) 4.99 kB
import { OrthographicCamera, Scene } from "three"; import { WebGLRendererPool } from "../../../engine/graphics/render/RendererPool.js"; import { SignalBinding } from "../../../core/events/signal/SignalBinding.js"; import Vector2 from "../../../core/geom/Vector2.js"; import { assert } from "../../../core/assert.js"; export class MinimapWorldGL { /** * * @param {Vector2} canvasSize * @param {Rectangle} worldBounds */ constructor({ canvasSize, worldBounds }) { /** * * @type {boolean} */ this.renderNeedsUpdate = false; /** * * @type {Vector2} */ this.canvasSize = canvasSize; /** * * @type {Rectangle} */ this.worldBounds = worldBounds; /** * * @type {MinimapWorldLayer[]} */ this.layers = []; /** * * @type {number} */ this.animationFrameCallbackId = -1; /** * * @type {Scene} */ this.scene = new Scene(); /** * * @type {OrthographicCamera} */ this.camera = new OrthographicCamera(-1, 1, -1, 1, 0.1, 10); this.updateCameraFocus(); /** * * @type {WebGLRenderer | null} */ this.renderer = null; /** * * @type {HTMLCanvasElement} */ this.domElement = null; /** * * @type {SignalBinding[]} */ this.signalBindings = [ new SignalBinding(canvasSize.onChanged, (x, y) => { if (this.renderer !== null) { this.renderer.setSize(x, y); this.renderNeedsUpdate = true; this.layers.forEach(l => l.setViewportSize(x, y)); } }), new SignalBinding(worldBounds.size.onChanged, this.updateCameraFocus, this), new SignalBinding(worldBounds.position.onChanged, this.updateCameraFocus, this) ]; } /** * * @param {MinimapWorldLayer} l */ addLayer(l) { this.layers.push(l); this.scene.add(l.object); } updateCameraFocus() { const camera = this.camera; assert.defined(camera, 'this.camera'); const worldBounds = this.worldBounds; const w = worldBounds.size.x; const h = worldBounds.size.y; camera.left = -w / 2; camera.right = +w / 2; camera.top = -h / 2; camera.bottom = +h / 2; const v2worldCenter = new Vector2( worldBounds.position.x + w / 2, worldBounds.position.y + h / 2 ); camera.position.set(v2worldCenter.x, -2, v2worldCenter.y); camera.lookAt(v2worldCenter.x, 0, v2worldCenter.y); camera.updateProjectionMatrix(); camera.updateMatrixWorld(); } startup() { const renderer = this.renderer = WebGLRendererPool.global.get(); renderer.setClearColor(0, 0); renderer.setSize(this.canvasSize.x, this.canvasSize.y); this.layers.forEach(o => { o.startup(); o.setViewportSize(this.canvasSize.x, this.canvasSize.y); }); this.signalBindings.forEach(b => b.link()); this.updateCameraFocus(); this.renderNeedsUpdate = true; this.domElement = renderer.domElement; this.isRunning = true; const self = this; function animationUpdateCycle() { self.animationFrameCallbackId = requestAnimationFrame(animationUpdateCycle); self.update(); } if (this.animationFrameCallbackId === -1) { this.animationFrameCallbackId = requestAnimationFrame(animationUpdateCycle); } } shutdown() { this.signalBindings.forEach(b => b.unlink()); this.layers.forEach(o => o.shutdown()); WebGLRendererPool.global.release(this.renderer); if (this.animationFrameCallbackId !== -1) { cancelAnimationFrame(this.animationFrameCallbackId); this.animationFrameCallbackId = -1; } } render() { this.renderer.render(this.scene, this.camera); this.renderNeedsUpdate = false; } update() { const layers = this.layers; const layer_count = layers.length; for (let i = 0; i < layer_count; i++) { const layer = layers[i]; layer.update(this.camera); if (layer.needsRender) { this.renderNeedsUpdate = true; layer.needsRender = false; } } if (this.renderNeedsUpdate) { this.render(); } } }