aboutsummaryrefslogtreecommitdiff
path: root/src/index.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/index.ts')
-rw-r--r--src/index.ts169
1 files changed, 169 insertions, 0 deletions
diff --git a/src/index.ts b/src/index.ts
new file mode 100644
index 0000000..a25502d
--- /dev/null
+++ b/src/index.ts
@@ -0,0 +1,169 @@
+import * as THREE from "three";
+import { WEBGL } from "three/examples/jsm/WebGL";
+import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
+import { PointerLockControls } from "three/examples/jsm/controls/PointerLockControls";
+
+import { CollisionCaster } from "./collisionCaster";
+
+const clock: THREE.Clock = new THREE.Clock(true);
+const acceleration: number = 9.8;
+const speed: number = 50;
+const mass: number = 100;
+
+let controls: PointerLockControls, renderer: THREE.WebGLRenderer, camera: THREE.PerspectiveCamera, scene: THREE.Scene, raycaster: THREE.Raycaster;
+let movementDirection: Map<String, boolean> = new Map<String, boolean>();
+let direction = new THREE.Vector3();
+let velocity = new THREE.Vector3();
+let clips = [];
+
+const initialize = () => {
+ renderer = new THREE.WebGLRenderer({ antialias: true });
+ renderer.setSize(window.innerWidth, window.innerHeight);
+ renderer.setPixelRatio(window.devicePixelRatio);
+ renderer.shadowMap.type = THREE.PCFSoftShadowMap;
+ renderer.shadowMap.enabled = true;
+
+ document.body.appendChild(renderer.domElement);
+
+ scene = new THREE.Scene();
+
+ initializeBackground();
+ initializeStructures();
+ initializeLighting();
+ initializeViewer();
+
+ render();
+}
+
+const initializeBackground = () => {
+ const loader = new THREE.CubeTextureLoader();
+ const texture = loader.load([
+ '../assets/skybox/skyright.png',
+ '../assets/skybox/skyleft.png',
+ '../assets/skybox/skytop.png',
+ '../assets/skybox/skybottom.png',
+ '../assets/skybox/skycenter.png',
+ '../assets/skybox/skyveryright.png',
+ ]);
+
+ scene.background = texture;
+}
+
+const initializeStructures = () => {
+ const ground: THREE.Mesh = new THREE.Mesh(new THREE.PlaneGeometry(1000, 1000, 10, 10), new THREE.MeshPhongMaterial({ depthWrite: false, visible: false }));
+ ground.rotation.x = - Math.PI / 2;
+ ground.position.set(0, 0, 0);
+ ground.receiveShadow = true;
+ clips.push(ground);
+ scene.add(ground);
+
+ const loader = new GLTFLoader();
+ loader.load("../assets/scene.glb", (data) => { scene.add(data.scene); });
+}
+
+const initializeLighting = () => {
+ const intensity: number = 1;
+ const ambientLight: THREE.AmbientLight = new THREE.AmbientLight(0xFFFFFF, intensity);
+ const hemilight: THREE.HemisphereLight = new THREE.HemisphereLight(0x5D6DFF, 0xD99D80, intensity);
+ const dirlight: THREE.DirectionalLight = new THREE.DirectionalLight(0xFFFFFF, intensity);
+ dirlight.position.set(5, 10, 2);
+
+ scene.add(ambientLight);
+ scene.add(hemilight);
+ scene.add(dirlight);
+ scene.add(dirlight.target);
+}
+
+const initializeViewer = () => {
+ const fov = 45;
+ const aspect = 1920 / 1080;
+ camera = new THREE.PerspectiveCamera(fov, aspect);
+ camera.position.set(0, 0, 0);
+
+ controls = new PointerLockControls(camera, renderer.domElement);
+ controls.getObject().position.set(10, 1, 0);
+
+ scene.add(controls.getObject());
+}
+
+const applyMovement = (delta: number) => {
+ const left = (movementDirection["a"] || movementDirection["ArrowLeft"]) ? true : false;
+ const right = (movementDirection["d"] || movementDirection["ArrowRight"]) ? true : false;
+ const forward = (movementDirection["w"] || movementDirection["ArrowUp"]) ? true : false;
+ const backward = (movementDirection["s"] || movementDirection["ArrowDown"]) ? true : false;
+
+ velocity.x -= velocity.x * acceleration * delta;
+ velocity.z -= velocity.z * acceleration * delta;
+
+ direction.z = Number(forward) - Number(backward);
+ direction.x = Number(right) - Number(left);
+ direction.normalize();
+
+ if (forward || backward) velocity.z -= direction.z * speed * delta;
+ if (left || right) velocity.x -= direction.x * speed * delta;
+
+ controls.moveForward(- velocity.z * delta);
+ controls.moveRight(- velocity.x * delta);
+}
+
+const applyPhysics = (delta) => {
+ const collision = new CollisionCaster(camera.position, 0.4, clips);
+
+ if (collision.down != 0) {
+ if (collision.down < 0.2) camera.position.setY(camera.position.y + 0.1);
+ } else {
+ camera.position.setY(camera.position.y - acceleration * delta);
+ }
+}
+
+const render = () => {
+ requestAnimationFrame(render);
+
+ const delta = clock.getDelta();
+
+ if (controls.isLocked) {
+ applyMovement(delta);
+ applyPhysics(delta);
+ }
+
+ renderer.render(scene, camera);
+}
+
+const changeMovement = (event: KeyboardEvent, down: boolean) => {
+ const exclude = ["F5", "F11", "F12", "Escape", "Control", "LeftShift", "Tab"];
+
+ if (exclude.includes(event.key)) return;
+
+ event.stopPropagation();
+ event.preventDefault();
+
+ movementDirection[event.key] = down;
+}
+
+const togglePointerLock = () => {
+ if (controls.isLocked) {
+ controls.unlock();
+ (document.querySelector("#pause") as HTMLElement).style.display = "block";
+ } else {
+ controls.lock();
+ (document.querySelector("#pause") as HTMLElement).style.display = "none";
+ }
+}
+
+const onWindowResize = () => {
+ renderer.setSize(window.innerWidth, window.innerHeight);
+ camera.aspect = window.innerWidth / window.innerHeight;
+ camera.updateProjectionMatrix();
+}
+
+window.addEventListener("keydown", (event) => { changeMovement(event, true); }, false);
+window.addEventListener("keyup", (event) => { changeMovement(event, false); }, false);
+window.addEventListener("click", togglePointerLock, false);
+window.addEventListener("resize", onWindowResize, false);
+
+if (WEBGL.isWebGLAvailable()) {
+ initialize();
+} else {
+ const warning = WEBGL.getWebGLErrorMessage();
+ document.body.appendChild(warning);
+}