vertecs
Version:
A typescript entity-component-system framework
87 lines (68 loc) • 2.89 kB
text/typescript
import { PerspectiveCamera, Scene } from "three";
// @ts-ignore
import { CSS3DRenderer } from "three/addons/renderers/CSS3DRenderer.js";
import { vec3 } from "ts-gl-matrix";
import { Component, Entity, System } from "../../core";
import ThreeCss3dComponent from "./ThreeCss3dComponent";
import ThreeSystem from "../ThreeSystem";
import { Transform } from "../../math";
export default class ThreeCss3dSystem extends System<
[ThreeCss3dComponent, Transform]
> {
#renderer: CSS3DRenderer;
#scene: Scene;
#threeSystem: ThreeSystem;
#camera: PerspectiveCamera;
public constructor(threeSystem: ThreeSystem, tps?: number) {
super([ThreeCss3dComponent, Transform], tps, [ThreeSystem]);
this.#threeSystem = threeSystem;
this.#camera = new PerspectiveCamera(
90,
window.innerWidth / window.innerHeight,
1,
2000
);
this.#renderer = new CSS3DRenderer();
this.#renderer.setSize(window.innerWidth, window.innerHeight);
this.#scene = new Scene();
// For some reason, the css renderer is 100x bigger than the webgl renderer so we need to scale it down
this.#scene.scale.set(0.01, 0.01, 0.01);
const container = document.getElementById("hud");
if (!container) {
throw new Error("No element with id 'app' found");
}
container.appendChild(this.#renderer.domElement);
}
public onEntityEligible(
entity: Entity,
components: [ThreeCss3dComponent, Transform]
) {
const { css3dObject } = entity.getComponent(ThreeCss3dComponent)!;
this.#scene.add(css3dObject);
}
public onEntityNoLongerEligible(
entity: Entity,
components: [ThreeCss3dComponent, Transform]
) {
const [threeCss3dComponent] = components;
this.#scene.remove(threeCss3dComponent.css3dObject);
}
protected onLoop(
components: [ThreeCss3dComponent, Transform][],
entities: Entity[],
deltaTime: number
): void {
this.#camera.position.copy(this.#threeSystem.camera.position);
this.#camera.quaternion.copy(this.#threeSystem.camera.quaternion);
for (let i = 0; i < components.length; i++) {
const [css3dComponent, transform] = components[i];
const worldPosition = transform.getWorldPosition();
// Position is multiplied by 100 because the css renderer is 100x bigger than the webgl renderer
css3dComponent.css3dObject.position.x = worldPosition[0] * 100;
css3dComponent.css3dObject.position.y = worldPosition[1] * 100;
css3dComponent.css3dObject.position.z = worldPosition[2] * 100;
css3dComponent.css3dObject.lookAt(this.#camera.position);
}
this.#renderer.render(this.#scene, this.#camera);
}
}