/**
* Calls the init functions to initialize the interactions
*/
function initInteractions() {
initTriggerFlightSimulator();
initPutChairOnTable();
initOpenCloset();
initSwitchLight();
initInfoDiv();
initAdjustBlackboardHeight()
}
/**
* Initializes the info div
*/
function initInfoDiv() {
// create the div (at the top left corner)
infoDiv = document.createElement("div");
infoDiv.id = "info-div";
infoDiv.innerHTML = "";
document.body.appendChild(infoDiv);
// get all positions of the chair and add them to the info table
sceneObjects.chairs.forEach(chair => {
infoTable.push({
x: chair.position.x,
z: chair.position.z,
text: "Click on the chair to put it on the table or on the floor"
});
});
// get all positions of the closets and add them to the info table
sceneObjects.closets.forEach(closet => {
infoTable.push({
x: closet.position.x,
z: closet.position.z + 0.5,
text: "Click on the closet to open it"
});
});
// get all light switches
infoTable.push({
x: sceneObjects.lightSwitchOne.position.x,
z: sceneObjects.lightSwitchOne.position.z,
text: "Click on the light switch to turn on/off the lights"
});
infoTable.push({
x: sceneObjects.monitor.position.x,
z: sceneObjects.monitor.position.z - 0.5,
text: "Click on the monitor to start the flight simulator"
});
// blackboard
infoTable.push({
x: sceneObjects.blackboard.position.x + 2,
z: sceneObjects.blackboard.position.z + 1,
text: "Move the boards with the mouse up and down to adjust the height"
});
}
/**
* Adds the on click event listener to monitor to start the flight simulator
*/
function initTriggerFlightSimulator() {
if (sceneObjects.monitor === undefined) return;
domEvents.addEventListener(sceneObjects.monitor, "click", () => {
if (camera.position.distanceTo(sceneObjects.monitor.position) > maxInteractionDistance) return;
location.href = "/flight-simulator";
});
}
/**
* Adds the mouse event listener to the blackboard to adjust the height
*/
function initAdjustBlackboardHeight() {
if (sceneObjects.blackboard === undefined) return;
// get the individual boards and their chalk trays
blackboard.board1 = sceneObjects.blackboard.children.find(child => child.name === "Board1")
blackboard.chalkTray1 = sceneObjects.blackboard.children.find(child => child.name === "Kreideablage1")
blackboard.board2 = sceneObjects.blackboard.children.find(child => child.name === "Board2")
blackboard.chalkTray2 = sceneObjects.blackboard.children.find(child => child.name === "Kreideablage2")
if (blackboard.board1 === null || blackboard.chalkTray1 === null || blackboard.board2 === null || blackboard.chalkTray2 === null) return;
blackboard.distanceBetweenBoardAndChalkTray = blackboard.chalkTray1.position.y - blackboard.board1.position.y;
domEvents.addEventListener(blackboard.board1, "mousedown", () => {
if (camera.position.distanceTo(sceneObjects.blackboard.position) > maxInteractionDistance * 2) return;
isMouseDown = isMouseOnBlackboardBoard2 = false;
isMouseOnBlackboardBoard1 = true;
});
domEvents.addEventListener(blackboard.board2, "mousedown", () => {
if (camera.position.distanceTo(sceneObjects.blackboard.position) > maxInteractionDistance * 2) return;
isMouseDown = isMouseOnBlackboardBoard1 = false;
isMouseOnBlackboardBoard2 = true;
});
// add a mouse move listener to the window to adjust the height of the blackboards
// if the mouse is on the blackboard the blackboard is moved up and down and the speed is calculated
window.addEventListener("mousemove", event => {
if (!isMouseOnBlackboardBoard1) return;
let y = blackboard.board1.position.y - event.movementY * deltaTime * 0.3;
let speed = (y - blackboard.board1.position.y) / deltaTime;
if (speed !== 0) blackboard.speeds[0] = speed;
if (y < blackboard.boardYmin) y = blackboard.boardYmin;
if (y > blackboard.boardYmax) y = blackboard.boardYmax;
blackboard.board1.position.y = y;
blackboard.chalkTray1.position.y = y + blackboard.distanceBetweenBoardAndChalkTray;
});
window.addEventListener("mousemove", event => {
if (!isMouseOnBlackboardBoard2) return;
let y = blackboard.board2.position.y - event.movementY * deltaTime * 0.3;
let speed = (y - blackboard.board2.position.y) / deltaTime;
if (speed !== 0) blackboard.speeds[1] = speed;
if (y < blackboard.boardYmin) y = blackboard.boardYmin;
if (y > blackboard.boardYmax) y = blackboard.boardYmax;
blackboard.board2.position.y = y;
blackboard.chalkTray2.position.y = y + blackboard.distanceBetweenBoardAndChalkTray;
});
}
/**
* Initializes the light switchers
*/
function initSwitchLight() {
if (sceneObjects.lightSwitchOne === undefined || sceneObjects.lightSwitchTwo === undefined || sceneObjects.lightSwitchThree === undefined) return
// add the event listeners
domEvents.addEventListener(sceneObjects.lightSwitchOne, "click", () => {
if (camera.position.distanceTo(sceneObjects.lightSwitchOne.position) > maxInteractionDistance) return;
sceneObjects.bulbLights.forEach(light => {
if (light.name === "1") {
light.visible = !light.visible;
if (light.visible) {
sceneObjects.lightSwitchOne.children.find(child => child.name === "Lightswitch").rotation.x += degToRad(3.5);
} else {
sceneObjects.lightSwitchOne.children.find(child => child.name === "Lightswitch").rotation.x -= degToRad(3.5);
}
}
});
});
domEvents.addEventListener(sceneObjects.lightSwitchTwo, "click", () => {
if (camera.position.distanceTo(sceneObjects.lightSwitchTwo.position) > maxInteractionDistance) return;
sceneObjects.bulbLights.forEach(light => {
if (light.name === "2") {
light.visible = !light.visible;
if (light.visible) {
sceneObjects.lightSwitchTwo.children.find(child => child.name === "Lightswitch").rotation.x += degToRad(3.5);
} else {
sceneObjects.lightSwitchTwo.children.find(child => child.name === "Lightswitch").rotation.x -= degToRad(3.5);
}
}
});
});
domEvents.addEventListener(sceneObjects.lightSwitchThree, "click", () => {
if (camera.position.distanceTo(sceneObjects.lightSwitchThree.position) > maxInteractionDistance) return;
sceneObjects.bulbLights.forEach(light => {
if (light.name === "3") {
light.visible = !light.visible;
if (light.visible) {
sceneObjects.lightSwitchThree.children.find(child => child.name === "Lightswitch").rotation.x += degToRad(3.5);
} else {
sceneObjects.lightSwitchThree.children.find(child => child.name === "Lightswitch").rotation.x -= degToRad(3.5);
}
}
});
});
}
/**
* Adds the on click event listener to the chairs and determines the direction of the chair for the animation
*/
function initPutChairOnTable() {
if (sceneObjects.chairs === undefined) return
sceneObjects.chairs.forEach(chair => {
chair.isOnTable = false;
// moveDirection: 1 for positive x 2 for negative x 3 for positive z 4 for negative z
switch (chair.rotation.y) {
case 0:
chair.moveDirection = 1;
break;
case Math.PI / 2:
chair.moveDirection = 2;
break;
case Math.PI:
chair.moveDirection = 3;
break;
case -Math.PI / 2:
chair.moveDirection = 4;
default:
break;
}
// add the event listener
domEvents.addEventListener(chair, "click", () => {
if (camera.position.distanceTo(chair.position) > maxInteractionDistance) return;
if (chairAnimation.activeChair !== null) return;
chairAnimation.activeChair = chair;
chairAnimation.initialPosition = chair.position.clone();
chairAnimation.up = !chair.isOnTable;
});
});
}
/**
* Adds the on click event listener to the closets
*/
function initOpenCloset() {
if (sceneObjects.closets === undefined) return
sceneObjects.closets.forEach(closet => {
closet.isOpen = false;
domEvents.addEventListener(closet, "click", () => {
if (camera.position.distanceTo(closet.position) > maxInteractionDistance) return;
if (closetAnimation.activeCloset !== null) return;
// check if one closet is already open
let anyClosetIsOpen = false;
sceneObjects.closets.forEach(closet => {
if (closet.isOpen) anyClosetIsOpen = true;
});
if (anyClosetIsOpen && !closet.isOpen) return;
closetAnimation.activeCloset = closet;
closetAnimation.open = !closet.isOpen;
});
});
}
/**
* Is called every frame and handles animation of chairs
* There are 3 steps in the animation:
* 1. Move the chair backwards
* 2. Move the chair up
* 3. Move the chair forwards
*/
function handleAnimateChairs() {
if (chairAnimation.activeChair === null) return;
chairAnimation.timeSinceAnimationStart = chairAnimation.timeSinceAnimationStart + deltaTime;
let chair = chairAnimation.activeChair;
let initPos = chairAnimation.initialPosition;
let animationComplete = false;
const distanceBack = 0.3;
const distanceUp = 0.4;
const animationDuration = 1; // 3 in total
const distanceFraction = chairAnimation.timeSinceAnimationStart / animationDuration;
// 4 different directions * 3 steps = 12 cases (deep nesting)
switch (chair.moveDirection) {
case 1:
if (chairAnimation.up) {
if (chair.position.z < initPos.z + distanceBack && chairAnimation.moveStep == 1) {
chair.position.z = initPos.z + distanceBack * distanceFraction;
} else if (chair.position.z >= initPos.z + distanceBack && chairAnimation.moveStep == 1) {
chair.position.z = initPos.z + distanceBack;
chairAnimation.moveStep = 2;
} else if (chair.position.y < initPos.y + distanceUp && chairAnimation.moveStep == 2) {
chair.position.y = initPos.y + distanceUp * (distanceFraction - 1);
} else if (chair.position.y >= initPos.y + distanceUp && chairAnimation.moveStep == 2) {
chair.position.y = initPos.y + distanceUp;
chairAnimation.moveStep = 3;
} else if (chair.position.z > initPos.z && chairAnimation.moveStep == 3) {
chair.position.z = initPos.z + distanceBack - (distanceBack * (distanceFraction - 2));
} else if (chair.position.z <= initPos.z && chairAnimation.moveStep == 3) {
chair.position.z = initPos.z;
animationComplete = true;
}
} else {
if (chair.position.z < initPos.z + distanceBack && chairAnimation.moveStep == 1) {
chair.position.z = initPos.z + distanceBack * distanceFraction;
} else if (chair.position.z >= initPos.z + distanceBack && chairAnimation.moveStep == 1) {
chair.position.z = initPos.z + distanceBack;
chairAnimation.moveStep = 2;
} else if (chair.position.y > initPos.y - distanceUp && chairAnimation.moveStep == 2) {
chair.position.y = initPos.y - distanceUp * (distanceFraction - 1);
} else if (chair.position.y <= initPos.y - distanceUp && chairAnimation.moveStep == 2) {
chair.position.y = initPos.y - distanceUp;
chairAnimation.moveStep = 3;
} else if (chair.position.z > initPos.z && chairAnimation.moveStep == 3) {
chair.position.z = initPos.z + distanceBack - (distanceBack * (distanceFraction - 2));
} else if (chair.position.z <= initPos.z && chairAnimation.moveStep == 3) {
chair.position.z = initPos.z;
animationComplete = true;
}
}
break;
case 2:
if (chairAnimation.up) {
if (chair.position.x < initPos.x + distanceBack && chairAnimation.moveStep == 1) {
chair.position.x = initPos.x + distanceBack * distanceFraction;
} else if (chair.position.x >= initPos.x + distanceBack && chairAnimation.moveStep == 1) {
chair.position.x = initPos.x + distanceBack;
chairAnimation.moveStep = 2;
} else if (chair.position.y < initPos.y + distanceUp && chairAnimation.moveStep == 2) {
chair.position.y = initPos.y + distanceUp * (distanceFraction - 1);
} else if (chair.position.y >= initPos.y + distanceUp && chairAnimation.moveStep == 2) {
chair.position.y = initPos.y + distanceUp;
chairAnimation.moveStep = 3;
} else if (chair.position.x > initPos.x && chairAnimation.moveStep == 3) {
chair.position.x = initPos.x + distanceBack - (distanceBack * (distanceFraction - 2));
} else if (chair.position.x <= initPos.x && chairAnimation.moveStep == 3) {
chair.position.x = initPos.x;
animationComplete = true;
}
} else {
if (chair.position.x < initPos.x + distanceBack && chairAnimation.moveStep == 1) {
chair.position.x = initPos.x + distanceBack * distanceFraction;
} else if (chair.position.x >= initPos.x + distanceBack && chairAnimation.moveStep == 1) {
chair.position.x = initPos.x + distanceBack;
chairAnimation.moveStep = 2;
} else if (chair.position.y > initPos.y - distanceUp && chairAnimation.moveStep == 2) {
chair.position.y = initPos.y - distanceUp * (distanceFraction - 1);
} else if (chair.position.y <= initPos.y - distanceUp && chairAnimation.moveStep == 2) {
chair.position.y = initPos.y - distanceUp;
chairAnimation.moveStep = 3;
} else if (chair.position.x > initPos.x && chairAnimation.moveStep == 3) {
chair.position.x = initPos.x + distanceBack - (distanceBack * (distanceFraction - 2));
} else if (chair.position.x <= initPos.x && chairAnimation.moveStep == 3) {
chair.position.x = initPos.x;
animationComplete = true;
}
}
break;
case 3:
if (chairAnimation.up) {
if (chair.position.z > initPos.z - distanceBack && chairAnimation.moveStep == 1) {
chair.position.z = initPos.z - distanceBack * distanceFraction;
} else if (chair.position.z <= initPos.z - distanceBack && chairAnimation.moveStep == 1) {
chair.position.z = initPos.z - distanceBack;
chairAnimation.moveStep = 2;
} else if (chair.position.y < initPos.y + distanceUp && chairAnimation.moveStep == 2) {
chair.position.y = initPos.y + distanceUp * (distanceFraction - 1);
} else if (chair.position.y >= initPos.y + distanceUp && chairAnimation.moveStep == 2) {
chair.position.y = initPos.y + distanceUp;
chairAnimation.moveStep = 3;
} else if (chair.position.z < initPos.z && chairAnimation.moveStep == 3) {
chair.position.z = initPos.z - distanceBack + (distanceBack * (distanceFraction - 2));
} else if (chair.position.z >= initPos.z && chairAnimation.moveStep == 3) {
chair.position.z = initPos.z;
animationComplete = true;
}
} else {
if (chair.position.z > initPos.z - distanceBack && chairAnimation.moveStep == 1) {
chair.position.z = initPos.z - distanceBack * distanceFraction;
} else if (chair.position.z <= initPos.z - distanceBack && chairAnimation.moveStep == 1) {
chair.position.z = initPos.z - distanceBack;
chairAnimation.moveStep = 2;
} else if (chair.position.y > initPos.y - distanceUp && chairAnimation.moveStep == 2) {
chair.position.y = initPos.y - distanceUp * (distanceFraction - 1);
} else if (chair.position.y <= initPos.y - distanceUp && chairAnimation.moveStep == 2) {
chair.position.y = initPos.y - distanceUp;
chairAnimation.moveStep = 3;
} else if (chair.position.z < initPos.z && chairAnimation.moveStep == 3) {
chair.position.z = initPos.z - distanceBack + (distanceBack * (distanceFraction - 2));
} else if (chair.position.z >= initPos.z && chairAnimation.moveStep == 3) {
chair.position.z = initPos.z;
animationComplete = true;
}
}
break;
case 4:
if (chairAnimation.up) {
if (chair.position.x > initPos.x - distanceBack && chairAnimation.moveStep == 1) {
chair.position.x = initPos.x - distanceBack * distanceFraction;
} else if (chair.position.x <= initPos.x - distanceBack && chairAnimation.moveStep == 1) {
chair.position.x = initPos.x - distanceBack;
chairAnimation.moveStep = 2;
} else if (chair.position.y < initPos.y + distanceUp && chairAnimation.moveStep == 2) {
chair.position.y = initPos.y + distanceUp * (distanceFraction - 1);
} else if (chair.position.y >= initPos.y + distanceUp && chairAnimation.moveStep == 2) {
chair.position.y = initPos.y + distanceUp;
chairAnimation.moveStep = 3;
} else if (chair.position.x < initPos.x && chairAnimation.moveStep == 3) {
chair.position.x = initPos.x - distanceBack + (distanceBack * (distanceFraction - 2));
} else if (chair.position.x >= initPos.x && chairAnimation.moveStep == 3) {
chair.position.x = initPos.x;
animationComplete = true;
}
} else {
if (chair.position.x > initPos.x - distanceBack && chairAnimation.moveStep == 1) {
chair.position.x = initPos.x - distanceBack * distanceFraction;
} else if (chair.position.x <= initPos.x - distanceBack && chairAnimation.moveStep == 1) {
chair.position.x = initPos.x - distanceBack;
chairAnimation.moveStep = 2;
} else if (chair.position.y > initPos.y - distanceUp && chairAnimation.moveStep == 2) {
chair.position.y = initPos.y - distanceUp * (distanceFraction - 1);
} else if (chair.position.y <= initPos.y - distanceUp && chairAnimation.moveStep == 2) {
chair.position.y = initPos.y - distanceUp;
chairAnimation.moveStep = 3;
} else if (chair.position.x < initPos.x && chairAnimation.moveStep == 3) {
chair.position.x = initPos.x - distanceBack + (distanceBack * (distanceFraction - 2));
} else if (chair.position.x >= initPos.x && chairAnimation.moveStep == 3) {
chair.position.x = initPos.x;
animationComplete = true;
}
}
break;
default:
break;
}
if (animationComplete) {
chair.isOnTable = chairAnimation.up;
chairAnimation = {
activeChair: null,
initialPosition: null,
moveStep: 1,
up: true,
timeSinceAnimationStart: 0
};
}
}
/**
* Is called every frame and handles the animation of the closets
*/
function handleAnimateClosets() {
if (closetAnimation.activeCloset === null) return;
closetAnimation.timeSinceAnimationStart = closetAnimation.timeSinceAnimationStart + deltaTime;
let door1 = closetAnimation.activeCloset.children.find(child => child.name === "Closet_Door_1");
let door2 = closetAnimation.activeCloset.children.find(child => child.name === "Closet_Door_2");
let animationComplete = false;
const animationDuration = 1;
const distanceFraction = closetAnimation.timeSinceAnimationStart / animationDuration;
let door1RotationAroundY = - Math.PI * 0.8
let door2RotationAroundY = Math.PI * 0.8
// door2 of the second closet can only be opened a little bit because of the wall
if (closetAnimation.activeCloset === sceneObjects.closets[1]) door2RotationAroundY = Math.PI * 0.45;
if (closetAnimation.open) {
if (door1.rotation.y > door1RotationAroundY) {
door1.rotation.y = door1RotationAroundY * distanceFraction;
} else if (door1.rotation.y <= door1RotationAroundY) {
door1.rotation.y = door1RotationAroundY;
animationComplete = true;
}
if (door2.rotation.y < door2RotationAroundY) {
door2.rotation.y = door2RotationAroundY * distanceFraction;
} else if (door2.rotation.y >= door2RotationAroundY) {
door2.rotation.y = door2RotationAroundY;
animationComplete = true;
}
} else {
if (door1.rotation.y < 0) {
door1.rotation.y = door1RotationAroundY - (door1RotationAroundY * distanceFraction);
} else if (door1.rotation.y >= 0) {
door1.rotation.y = 0;
animationComplete = true;
}
if (door2.rotation.y > 0) {
door2.rotation.y = door2RotationAroundY - (door2RotationAroundY * distanceFraction);
} else if (door2.rotation.y <= 0) {
door2.rotation.y = 0;
animationComplete = true;
}
}
if (animationComplete) {
closetAnimation.activeCloset.isOpen = !closetAnimation.activeCloset.isOpen;
closetAnimation = {
activeCloset: null,
timeSinceAnimationStart: 0,
open: true
};
}
}
/**
* Is called every frame and handles the information div about the interactions
*/
function handleInfoDiv() {
const triggerDistance = 1.2;
let isNearSomething = false;
infoTable.forEach(function (entry) {
if (isNearSomething) return;
// get distance between camera and object (x and z)
const distance = Math.sqrt(Math.pow(camera.position.x - entry.x, 2) + Math.pow(camera.position.z - entry.z, 2));
// if distance is smaller than 10 show the info div
if (distance < triggerDistance) {
infoDiv.innerHTML = entry.text;
infoDiv.style.visibility = "visible";
isNearSomething = true;
}
});
// if nothing is near the camera hide the info div
if (!isNearSomething) {
infoDiv.innerHTML = "";
infoDiv.style.visibility = "hidden";
}
}
/**
* Is called every frame and moves the blackboard boards if there is a fast movement by the user
*/
function handleBlackboardInertia() {
if (sceneObjects.blackboard === undefined) return;
const inertiaFactor = 2.5;
const bounceRepulsionFactor = 0.7;
const maxSpeed = 2;
blackboard.speeds.forEach((v, i) => {
if (v === 0) return;
if (isMouseOnBlackboardBoard1 && i === 0) return;
if (isMouseOnBlackboardBoard2 && i === 1) return;
let board = i === 0 ? blackboard.board1 : blackboard.board2;
let chalkTray = i === 0 ? blackboard.chalkTray1 : blackboard.chalkTray2;
// maximum speed guard
if (Math.abs(v) > maxSpeed) v = v > 0 ? maxSpeed : -maxSpeed;
// friction
if (v > 0) {
v = v - inertiaFactor * deltaTime;
if (v < 0) v = 0;
} else {
v = v + inertiaFactor * deltaTime;
if (v > 0) v = 0;
}
// bounce repulsion
let y = board.position.y + v * deltaTime;
if (y < blackboard.boardYmin || y > blackboard.boardYmax) {
v = - bounceRepulsionFactor * v;
y = board.position.y + v * deltaTime;
}
// update position and speed
board.position.y = y;
chalkTray.position.y = y + blackboard.distanceBetweenBoardAndChalkTray;
blackboard.speeds[i] = v;
});
}