3js-game-framework
Version:
3js-game-framework is a lightweight and flexible framework designed to streamline the creation of 3D games and interactive applications using Three.js
153 lines • 6.48 kB
JavaScript
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import constants from "../constants";
export class TJSGame {
/**
*
* @param options - TGame Options
*/
constructor(options = {}) {
this.animationLoopEnabled = true;
this.setupLights = (lightsOptions) => {
if (!(lightsOptions === null || lightsOptions === void 0 ? void 0 : lightsOptions.disableDefaults)) {
// Ambient light
const ambientLight = new THREE.AmbientLight(0x404040); // soft white light
this.scene.add(ambientLight);
// Directional light
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(-5, 5, 10);
directionalLight.castShadow = true;
this.scene.add(directionalLight);
}
if (Array.isArray(lightsOptions === null || lightsOptions === void 0 ? void 0 : lightsOptions.lights)) {
lightsOptions.lights.forEach((light) => this.scene.add(light));
}
};
this.gameObjects = new Set();
this.clock = new THREE.Clock();
this.animationLoopEnabled = options.disableAnimationLoop ? false : true;
this.SCREEN_WIDTH = Math.floor(window.innerWidth);
this.SCREEN_HEIGHT = Math.floor(window.innerHeight);
this.gameObjectMap = new Map();
this.setupScene(options.scene);
this.setupLights(options.lights);
this.setupRenderer();
this.setupCamera(options.camera);
this.addResizeListener();
}
addResizeListener() {
window.addEventListener("resize", () => {
this.SCREEN_WIDTH = Math.floor(window.innerWidth);
this.SCREEN_HEIGHT = Math.floor(window.innerHeight);
//@ts-ignore
this.camera.aspect = this.SCREEN_WIDTH / this.SCREEN_HEIGHT;
//@ts-ignore
this.camera.updateProjectionMatrix();
this.renderer.setSize(this.SCREEN_WIDTH, this.SCREEN_HEIGHT);
});
}
setupScene(sceneOptions) {
this.scene = new THREE.Scene();
this.scene.background =
(sceneOptions === null || sceneOptions === void 0 ? void 0 : sceneOptions.background) || constants.scene.background;
if (sceneOptions === null || sceneOptions === void 0 ? void 0 : sceneOptions.addAxisHelper) {
const axesHelper = new THREE.AxesHelper(50);
this.scene.add(axesHelper);
}
}
setupCamera(cameraOptions) {
const cameraDefaults = constants.camera;
this.camera = new THREE.PerspectiveCamera((cameraOptions === null || cameraOptions === void 0 ? void 0 : cameraOptions.fov) || cameraDefaults.fov, this.SCREEN_WIDTH / this.SCREEN_HEIGHT, (cameraOptions === null || cameraOptions === void 0 ? void 0 : cameraOptions.near) || cameraDefaults.near, (cameraOptions === null || cameraOptions === void 0 ? void 0 : cameraOptions.far) || cameraDefaults.far);
// Set camera position
const cameraPosition = (cameraOptions === null || cameraOptions === void 0 ? void 0 : cameraOptions.position) || cameraDefaults.position;
this.camera.position.set(cameraPosition[0], cameraPosition[1], cameraPosition[2]);
if (cameraOptions === null || cameraOptions === void 0 ? void 0 : cameraOptions.enableOrbitControls) {
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
this.controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled
this.controls.dampingFactor = 0.25;
this.controls.screenSpacePanning = false;
this.controls.maxPolarAngle = Math.PI / 2;
this.controls.update();
}
}
setupRenderer() {
var _a;
this.renderer = new THREE.WebGLRenderer();
this.renderer.setSize(this.SCREEN_WIDTH, this.SCREEN_HEIGHT);
(_a = document === null || document === void 0 ? void 0 : document.body) === null || _a === void 0 ? void 0 : _a.appendChild(this.renderer.domElement);
}
/**
* Start the game and all game objects
*/
start() {
this.clock.start();
for (let gameObject of this.gameObjects) {
gameObject.start();
}
if (this.animationLoopEnabled)
this.animate();
}
/**
* Animation loop
*/
animate() {
requestAnimationFrame(this.animate.bind(this));
this.update(this.clock.getDelta());
}
/**
* Add GameObject to the TSGame
* @param gameObject - GameObject to be added to the game
*/
addGameObject(gameObject) {
if (this.clock.running)
gameObject.start();
this.gameObjects.add(gameObject);
let name = (gameObject === null || gameObject === void 0 ? void 0 : gameObject.name) || gameObject.constructor.name;
if (this.gameObjectMap.has(name)) {
name = `${name}-${Math.floor(Math.random() * 1000)}`;
`GameObject with name ${gameObject.name} already exists. Generated new ${name}.`;
}
if (name !== gameObject.name) {
console.warn();
gameObject.name = name;
}
this.gameObjectMap.set(name, gameObject);
}
/**
* Remove GameObject from the TSGame
* @param gameObject - GameObject to be removed from the game
*/
removeGameObject(gameObject) {
if (this.clock.running)
gameObject.end();
this.gameObjects.delete(gameObject);
}
/**
* Get GameObject by name
* @param name - Name of the GameObject
* @returns GameObject
*/
getGameObject(name) {
return this.gameObjectMap.get(name);
}
/**
* All updates will be done here
* @param dt - Delta time since last update
*/
update(dt) {
for (let gameObject of this.gameObjects) {
gameObject.update(dt);
}
if (this.controls)
this.controls.update(); // only required if controls.enableDamping = true, or if controls.autoRotate = true
this.renderer.render(this.scene, this.camera);
}
/**
* To be invoked when the game ends
*/
end() {
this.gameObjects.forEach((gameObject) => gameObject.end());
this.clock.stop();
}
}
//# sourceMappingURL=TJSGame.js.map