0% found this document useful (0 votes)
9 views7 pages

In Put Handler

The document outlines the implementation of input handling for a game, including mouse and keyboard controls for player movement, camera orbiting, and jumping or flying mechanics. It features a MutationObserver to manage game input activation based on the visibility of a title overlay and includes functions to update player presence in a multiplayer environment. Additionally, it handles audio context management for background music and sound effects during gameplay.

Uploaded by

davidsiserman035
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views7 pages

In Put Handler

The document outlines the implementation of input handling for a game, including mouse and keyboard controls for player movement, camera orbiting, and jumping or flying mechanics. It features a MutationObserver to manage game input activation based on the visibility of a title overlay and includes functions to update player presence in a multiplayer environment. Additionally, it handles audio context management for background music and sound effects during gameplay.

Uploaded by

davidsiserman035
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 7

import { room } from './websim.

js';
import { playJumpSound, audioContext, playBackgroundMusic } from './audio.js';
// Import playerCharacters to check ground state before jumping
// Import isSupported from gameLogic.js for checking if player is on a supported
surface that allows jumping
import { playerCharacters, epsilon, isSupported, deleteLastPlacedBlock,
toggleBuildMode as toggleBuildModeGameLogic, toggleBuildColorPicker } from
'./gameLogic.js';
import { renderer } from './sceneSetup.js';
// Import settings to check fly mode state
import { settings } from './settings.js';

// Controls variables (local player only)


let orbitRadius = 15;
let orbitAngle = 0;
let orbitPitch = 0.25;
let lastMouseX = 0;
let lastMouseY = 0;
let isRightClickDragging = false;

// Movement keys state (local player only)


const keys = { w: false, a: false, s: false, d: false };

// Flag to check if game input should be active (i.e., if the title overlay is
hidden)
let gameInputActive = false;

// Listener in index.html will set titleOverlay display to 'none' when join is


clicked
// We use a MutationObserver to detect this change and activate game input.
const titleOverlay = document.getElementById('title-overlay');
const observer = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
if (mutation.attributeName === 'style') {
const currentDisplay = window.getComputedStyle(titleOverlay).display;
if (currentDisplay === 'none') {
gameInputActive = true;
console.log("Input Handler: Game input active.");
// Ensure the renderer canvas is focusable or receives events
correctly
// This might involve setting tabindex or similar, but browser
default often works if it's the main element.
} else {
gameInputActive = false;
// Optionally reset keys state if overlay becomes visible again
// This ensures the player doesn't start moving if they re-enter
the game
// without pressing keys again after visiting forums/etc.
let keysWereActive = false;
for(const key in keys) {
if (keys[key]) {
keys[key] = false;
keysWereActive = true;
}
}
// Also reset flyUp, flyDown, and isJumping when game input
becomes inactive
let presenceChanged = false;
const localPlayerPresence = room.presence[room.clientId];
if(localPlayerPresence?.flyUp) {
presenceChanged = true;
}
if(localPlayerPresence?.isJumping) {
presenceChanged = true;
}
if(localPlayerPresence?.flyDown) {
presenceChanged = true;
}

// Only update presence if keys state actually changed or


jump/flyUp/flyDown was active
// Check if room and client id are available before updating
presence
if ((keysWereActive || presenceChanged) && room && room.clientId
&& room.presence[room.clientId]) {
// Build update object based on what needs resetting
const updateData = {};
if (keysWereActive) updateData.keys = { ...keys };
if(presenceChanged) {
updateData.isJumping = false;
updateData.flyUp = false;
updateData.flyDown = false;
}
if (Object.keys(updateData).length > 0) {
room.updatePresence(updateData);
console.log("Input Handler: Game Input Inactive -
Resetting presence state:", updateData);
}
} else {
// If room not available, at least reset local keys state
for(const key in keys) keys[key] = false;
}
console.log("Input Handler: Game input inactive.");
}
}
});
});

// Start observing the style attribute of the title overlay


observer.observe(titleOverlay, { attributes: true });

// Listeners for camera controls


window.addEventListener('mousedown', (e) => {
// Only process if game input is active AND the event target is the renderer's
canvas
if (!gameInputActive || e.target !== renderer.domElement) {
return;
}

if (e.button === 2) { // Right click


isRightClickDragging = true;
lastMouseX = e.clientX;
lastMouseY = e.clientY;
// Prevent default context menu
e.preventDefault();
}
});

window.addEventListener('mouseup', (e) => {


// Only process if game input is active AND the event target is the renderer's
canvas or we were dragging from the canvas
// Check e.target !== renderer.domElement is less strict on mouseup to allow
finishing drag even if cursor leaves canvas briefly
if (!gameInputActive) return;
if (e.button === 2) {
isRightClickDragging = false;
}
});

window.addEventListener('mousemove', (e) => {


// Only process if game input is active AND we are currently dragging
if (!gameInputActive || !isRightClickDragging) {
return;
}

const deltaX = e.clientX - lastMouseX;


const deltaY = e.clientY - lastMouseY;
orbitAngle -= deltaX * 0.005;
orbitPitch += deltaY * 0.005;
const maxPitch = Math.PI / 2 - 0.1;
const minPitch = -maxPitch;
orbitPitch = Math.min(maxPitch, Math.max(minPitch, orbitPitch));
lastMouseX = e.clientX;
lastMouseY = e.clientY;
});

window.addEventListener('contextmenu', (e) => {


// Prevent context menu only if game input is active AND the event target is
the renderer's canvas
if (gameInputActive && e.target === renderer.domElement) {
e.preventDefault();
}
});

window.addEventListener('wheel', (e) => {


// Only process if game input is active AND the event target is the renderer's
canvas
if (!gameInputActive || e.target !== renderer.domElement) {
return;
}

if (e.deltaY < 0) orbitRadius = Math.max(5, orbitRadius - 1);


else orbitRadius = Math.min(50, orbitRadius + 1);
e.preventDefault(); // Prevent page scroll
});

// Listeners for player movement and jump/fly


document.addEventListener('keydown', (e) => {
// Prevent game actions if typing in chat or forums input/textarea
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
// Only process game input if active
if (!gameInputActive) return;

// Check if room and local player presence are available before processing game
input
if (!room || !room.clientId || !room.presence[room.clientId]) {
// console.warn("Input Handler: Websim room or local presence not available,
skipping keydown.");
return;
}

const localPlayerPresence = room.presence[room.clientId];


const localCharacter = playerCharacters[room.clientId]; // Get local character
reference

// Handle 'C' key for toggling color picker in build mode


if (e.key === 'c' || e.key === 'C') {
if (settings.buildModeActive) { // Check if build mode is active (gameLogic
will manage this flag)
toggleBuildColorPicker(); // Call function from gameLogic.js
e.preventDefault();
return; // Don't process other C-key actions if any
}
}

// Handle directional keys (W, A, S, D)


if (keys.hasOwnProperty(e.key)) {
if (!keys[e.key]) {
keys[e.key] = true;
// Update presence only when key state changes
// Ensure current presence keys are available before spreading
const currentKeys = localPlayerPresence.keys || {};
const updatedKeys = { ...currentKeys, [e.key]: true };
room.updatePresence({ keys: updatedKeys });
console.log("Input Handler: Key Down - Updating presence keys:",
updatedKeys); // Log presence update
}
}

// Handle Delete key OR 'V' key for deleting the most recent block
if (e.code === 'Delete' || e.key === 'v' || e.key === 'V') {
console.log(`INPUT: ${e.code || e.key} key pressed, attempting to delete last
block`);
// Call the imported function
const deleted = deleteLastPlacedBlock();
if (deleted) {
console.log('INPUT: Successfully requested deletion of last placed
block');
} else {
console.log('INPUT: No blocks to delete or deletion failed (check console
for details)');
}
e.preventDefault(); // Prevent default delete/V action
return;
}

// Handle Space key for Jump or Fly Up


if (e.code === 'Space') {
// Check if local fly mode is enabled from settings
const flyModeEnabled = settings.flyMode;

if (flyModeEnabled) {
// If in fly mode, pressing Space makes player go up
console.log("Input Handler: Fly mode active, Spacebar pressed,
initiating upward movement."); // Log fly initiation
// Update presence to signal upward movement, ensure flyDown is off
if (!localPlayerPresence.flyUp || localPlayerPresence.flyDown) { //
Update if flyUp is not true OR if flyDown is true
room.updatePresence({ flyUp: true, flyDown: false }); // Ensure
only one direction is active
console.log("Input Handler: Updating presence for flyUp: true,
flyDown: false");
}
e.preventDefault(); // Prevent default spacebar action
} else {
// If not in fly mode, Spacebar is for jumping (existing logic)
// Check if the player is currently not jumping AND is supported
// We read the jump state from the player's own presence data
const charIsSupported = localCharacter && isSupported(localCharacter); //
Use the exported isSupported function

if (!localPlayerPresence.isJumping && charIsSupported) { // Check against


isSupported
console.log("Input Handler: Not in fly mode, Spacebar pressed,
initiating jump."); // Log jump initiation
// Trigger the jump state change in presence
room.updatePresence({ isJumping: true });
// Broadcast event for sound effect for others
// Only send event if Websim is connected
if (room.send) {
room.send({ type: 'jump', clientId: room.clientId });
} else {
console.warn("Websim send function not available, cannot broadcast
jump event.");
}

// Play local sound immediately


// Play sound when jump is *initiated* from the ground
playJumpSound();
e.preventDefault(); // Prevent default spacebar action (like page
scroll)
} else {
// Optional: Log why jump didn't happen
// console.log("Input Handler: Spacebar pressed, but cannot jump.",
{ isJumping: localPlayerPresence.isJumping, isSupported: charIsSupported });
}
}
}

// Handle Shift key for Fly Down


if (e.code === 'ShiftLeft' || e.code === 'ShiftRight') {
const flyModeEnabled = settings.flyMode;

if (flyModeEnabled) {
console.log("Input Handler: Fly mode active, Shift pressed, initiating
downward movement."); // Log fly down initiation
// Update presence to signal downward movement, ensure flyUp is off
if (!localPlayerPresence.flyDown || localPlayerPresence.flyUp) { //
Update if flyDown is not true OR if flyUp is true
room.updatePresence({ flyDown: true, flyUp: false }); // Ensure only
one direction is active
console.log("Input Handler: Updating presence for flyDown: true,
flyUp: false");
}
e.preventDefault(); // Prevent default shift key action (e.g., selecting
text)
}
}
});

document.addEventListener('keyup', (e) => {


// Prevent game actions if typing in chat or forums input/textarea
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
// Only process game input if active
if (!gameInputActive) return;

// Check if room and local player presence are available before processing game
input
if (!room || !room.clientId || !room.presence[room.clientId]) {
// console.warn("Input Handler: Websim room or local presence not available,
skipping keyup.");
return;
}

const localPlayerPresence = room.presence[room.clientId];

// Handle directional keys (W, A, S, D)


if (keys.hasOwnProperty(e.key)) {
if (keys[e.key]) {
keys[e.key] = false;
// Update presence only when key state changes
// Ensure current presence keys are available before spreading
const currentKeys = localPlayerPresence.keys || {};
const updatedKeys = { ...currentKeys, [e.key]: false };
room.updatePresence({ keys: updatedKeys });
console.log("Input Handler: Key Up - Updating presence keys:",
updatedKeys); // Log presence update
}
}

// Handle Space key up for stopping Fly Up


if (e.code === 'Space') {
const flyModeEnabled = settings.flyMode;

if (flyModeEnabled) {
console.log("Input Handler: Fly mode active, Spacebar released,
stopping upward movement."); // Log stop fly
if (localPlayerPresence.flyUp) { // Only update if state changes
room.updatePresence({ flyUp: false });
console.log("Input Handler: Updating presence for flyUp: false");
}
}
// If not in fly mode, keyup for Space doesn't do anything specific after
initiating a jump (jump is physics-based)
}

// Handle Shift key up for stopping Fly Down


if (e.code === 'ShiftLeft' || e.code === 'ShiftRight') {
const flyModeEnabled = settings.flyMode;

if (flyModeEnabled) {
console.log("Input Handler: Fly mode active, Shift released, stopping
downward movement."); // Log stop fly down
if (localPlayerPresence.flyDown) { // Only update if state changes
room.updatePresence({ flyDown: false });
console.log("Input Handler: Updating presence for flyDown:
false");
}
}
}
});

document.body.addEventListener('click', () => {
// Resume AudioContext if suspended
// Ensure audioContext exists before accessing its state
if (audioContext && audioContext.state === 'suspended') {
console.log("Input Handler: AudioContext suspended, attempting to
resume...");
audioContext.resume().then(() => {
console.log('Input Handler: AudioContext resumed.');
// Once resumed, attempt to play background music
playBackgroundMusic();
}).catch(e => console.error("Input Handler: Failed to resume audio
context:", e));
} else if (audioContext && audioContext.state === 'running') {
// If already running, ensure music is playing (the function itself handles
if it's already playing)
playBackgroundMusic();
} else {
console.log("Input Handler: AudioContext not available or in unexpected
state:", audioContext?.state);
}
});

// Export keys, orbit controls, but not local jump state variables as they are
managed by presence/gameLogic
export { keys, orbitRadius, orbitAngle, orbitPitch, gameInputActive };

You might also like