diff --git a/app/components/NDS.vue b/app/components/NDS.vue index 4d6bd34..d3c77a3 100644 --- a/app/components/NDS.vue +++ b/app/components/NDS.vue @@ -25,6 +25,12 @@ const BOTTOM_SCREEN = "Object_28"; // buttons const CROSS_BUTTON = "Object_21"; +const X_BUTTON = "Object_6"; +const A_BUTTON = "Object_32"; +const Y_BUTTON = "Object_4"; +const B_BUTTON = "Object_30"; +const SELECT_BUTTON = "Object_17"; +const START_BUTTON = "Object_11"; const meshes = new Map(); @@ -96,10 +102,17 @@ const physicalButtonsDown = new Set(); let mousePressedButton: string | null = null; const keyButtonMappings: [key: string, physicalButton: string][] = [ + // D-pad ["ArrowUp", "UP"], ["ArrowDown", "DOWN"], ["ArrowLeft", "LEFT"], ["ArrowRight", "RIGHT"], + ["d", "A"], + ["s", "B"], + ["w", "X"], + ["a", "Y"], + [" ", "SELECT"], + ["Enter", "START"], ]; const keyToButton = new Map(keyButtonMappings); @@ -119,6 +132,7 @@ onRender(({ delta }) => { if (topScreenTexture) topScreenTexture.needsUpdate = true; if (bottomScreenTexture) bottomScreenTexture.needsUpdate = true; + // cross const crossButton = meshes.get(CROSS_BUTTON); if (crossButton) { const PRESS_ANGLE = Math.PI / 28; @@ -137,16 +151,49 @@ onRender(({ delta }) => { currentRotation.lerp(targetRotation, lerpFactor); crossButton.rotation.setFromVector3(currentRotation); } + + // action buttons + const PRESS_SPEED = 100; + + const ACTION_BUTTONS = [ + { mesh: meshes.get(X_BUTTON), name: "X", offset: -0.0015 }, + { mesh: meshes.get(A_BUTTON), name: "A", offset: -0.0015 }, + { mesh: meshes.get(Y_BUTTON), name: "Y", offset: -0.0015 }, + { mesh: meshes.get(B_BUTTON), name: "B", offset: -0.0015 }, + { mesh: meshes.get(SELECT_BUTTON), name: "SELECT", offset: -0.0007 }, + { mesh: meshes.get(START_BUTTON), name: "START", offset: -0.0007 }, + ] as const; + + for (const { mesh, name, offset } of ACTION_BUTTONS) { + if (!mesh) continue; + + const targetY = physicalButtonsDown.has(name) ? offset : 0; + const lerpFactor = Math.min(delta * PRESS_SPEED, 1); + mesh.position.y += (targetY - mesh.position.y) * lerpFactor; + } }); +const pressButton = (button: string) => { + if (mousePressedButton) { + physicalButtonsDown.delete(mousePressedButton); + const prevKey = buttonToKey.get(mousePressedButton); + if (prevKey) { + window.dispatchEvent(new KeyboardEvent("keyup", { key: prevKey })); + } + } + + physicalButtonsDown.add(button); + mousePressedButton = button; + + const key = buttonToKey.get(button); + if (key) { + window.dispatchEvent(new KeyboardEvent("keydown", { key })); + } +}; + const handleClick = (event: MouseEvent) => { if (!scene.value) return; - console.log( - camera.activeCamera.value?.getWorldPosition(new THREE.Vector3()), - camera.activeCamera.value?.rotation, - ); - const domElement = renderer.instance.domElement; const rect = domElement.getBoundingClientRect(); @@ -208,24 +255,27 @@ const handleClick = (event: MouseEvent) => { else if (localPos.z >= MIN_DIST) button = "DOWN"; else if (localPos.x <= -MIN_DIST) button = "LEFT"; - if (button) { - if (mousePressedButton) { - physicalButtonsDown.delete(mousePressedButton); - const prevKey = buttonToKey.get(mousePressedButton); - if (prevKey) { - window.dispatchEvent(new KeyboardEvent("keyup", { key: prevKey })); - } - } + if (button) pressButton(button); + break; + } - physicalButtonsDown.add(button); - mousePressedButton = button; - - const key = buttonToKey.get(button); - if (key) { - window.dispatchEvent(new KeyboardEvent("keydown", { key })); - } - } + case X_BUTTON: + case A_BUTTON: + case Y_BUTTON: + case B_BUTTON: + case SELECT_BUTTON: + case START_BUTTON: { + const BUTTON_MAP = { + [X_BUTTON]: "X", + [A_BUTTON]: "A", + [Y_BUTTON]: "Y", + [B_BUTTON]: "B", + [SELECT_BUTTON]: "SELECT", + [START_BUTTON]: "START", + } as const; + const button = BUTTON_MAP[intersection.object.name]; + if (button) pressButton(button); break; } } diff --git a/app/pages/index.vue b/app/pages/index.vue index 38489b5..ffc3f7a 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -1,5 +1,4 @@