I am making a 3D walkable world. Implemented the keyboard movement using wasd and space and mouse movement. I have no problem with the mouse movement, but when pressing the keys on the keyboard it doesnt work. I have seen the example multiple times and it works, but for me it doesnt seem so.
I have a useKeyboardInput.js where I add the event listeners and it registers when i`m pressing the key.
import { useCallback, useEffect, useState } from "react";
export const useKeyboardInput = (keysToListen = []) => {
const getKeys = useCallback(() => {
const lowerCaseArray = [];
const hookReturn = {};
keysToListen.forEach((key) => {
const lowerCaseKey = key.toLowerCase();
lowerCaseArray.push(lowerCaseKey);
hookReturn[lowerCaseKey] = false;
});
return {
lowerCaseArray,
hookReturn,
};
}, [keysToListen]);
const [keysPressed, setPressedKeys] = useState(getKeys().hookReturn);
useEffect(() => {
const handleKeyDown = (e) => {
const lowerKey = e.key.toLowerCase();
if (getKeys().lowerCaseArray.includes(lowerKey)) {
setPressedKeys((keysPressed) => ({ ...keysPressed, [lowerKey]: true }));
}
console.log("Pressed Key is: " + e.key);
};
const handleKeyUp = (e) => {
const lowerKey = e.key.toLowerCase();
if (getKeys().lowerCaseArray.includes(lowerKey)) {
setPressedKeys((keysPressed) => ({
...keysPressed,
[lowerKey]: false,
}));
}
};
document.addEventListener("keydown", handleKeyDown);
document.addEventListener("keyup", handleKeyUp);
return () => {
document.removeEventListener("keydown", handleKeyDown);
document.removeEventListener("keyup", handleKeyUp);
};
}, [keysToListen, getKeys]);
console.log("KeysPressed is: " + JSON.stringify(keysPressed));
return keysPressed;
};
And then i have the Player.js where i am using the hooks for keyboard and mouse.
import { useSphere } from "@react-three/cannon";
import React, { useEffect, useRef, useState } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import { Vector3 } from "three";
import { useKeyboardInput } from "../Hooks/useKeyboardInput";
import { useMouseInput } from "../Hooks/useMouseInput";
import { useVariable } from "../Hooks/useVariable";
import { Bullet } from "./Bullet";
import { Raycaster } from "three";
/** Player movement constants */
const speed = 300;
const bulletSpeed = 30;
const bulletCoolDown = 300;
const jumpSpeed = 5;
const jumpCoolDown = 400;
export const Player = () => {
/** Player collider */
const [sphereRef, api] = useSphere(() => ({
mass: 100,
fixedRotation: true,
position: [0, 1, 0],
args: [0.2],
material: {
friction: 0,
},
}));
/** Bullets */
const [bullets, setBullets] = useState([]);
/** Input hooks */
const pressed = useKeyboardInput(["w", "a", "s", "d", " "]);
const pressedMouse = useMouseInput();
/** Converts the input state to ref so they can be used inside useFrame */
const input = useVariable(pressed);
const mouseInput = useVariable(pressedMouse);
/** Player movement constants */
const { camera, scene } = useThree();
/** Player state */
const state = useRef({
timeToShoot: 0,
timeTojump: 0,
vel: [0, 0, 0],
jumping: false,
});
useEffect(() => {
api.velocity.subscribe((v) => (state.current.vel = v));
}, [api]);
/** Player loop */
useFrame((_, delta) => {
/** Handles movement */
console.log("Input.current is: " + JSON.stringify(input.current));
const { w, s, a, d } = input.current;
const space = input.current[" "];
let velocity = new Vector3(0, 0, 0);
let cameraDirection = new Vector3();
camera.getWorldDirection(cameraDirection);
let forward = new Vector3();
forward.setFromMatrixColumn(camera.matrix, 0);
forward.crossVectors(camera.up, forward);
let right = new Vector3();
right.setFromMatrixColumn(camera.matrix, 0);
let [horizontal, vertical] = [0, 0];
if (w == true) {
vertical += 1;
console.log("Pressed w");
} else if (s == true) {
vertical -= 1;
console.log("Pressed s");
} else if (d == true) {
horizontal += 1;
console.log("Pressed d");
} else if (a == true) {
horizontal -= 1;
console.log("Pressed a");
}
console.log(
"Horizontal is: " + horizontal + " and vertical is: " + vertical
);
if (horizontal !== 0 && vertical !== 0) {
velocity
.add(forward.clone().multiplyScalar(speed * vertical))
.add(right.clone().multiplyScalar(speed * horizontal));
velocity.clampLength(-speed, speed);
} else if (horizontal !== 0) {
velocity.add(right.clone().multiplyScalar(speed * horizontal));
} else if (vertical !== 0) {
velocity.add(forward.clone().multiplyScalar(speed * vertical));
}
console.log("velocity is: " + JSON.stringify(velocity));
/** Updates player velocity */
api.velocity.set(
velocity.x * delta,
state.current.vel[1],
velocity.z * delta
);
/** Updates camera position */
camera.position.set(
sphereRef.current.position.x,
sphereRef.current.position.y + 1,
sphereRef.current.position.z
);
/** Handles jumping */
if (state.current.jumping && state.current.vel[1] < 0) {
/** Ground check */
const raycaster = new Raycaster(
sphereRef.current.position,
new Vector3(0, -1, 0),
0,
0.2
);
const intersects = raycaster.intersectObjects(scene.children);
if (intersects.length !== 0) {
state.current.jumping = false;
}
}
if (space && !state.current.jumping) {
const now = Date.now();
if (now > state.current.timeTojump) {
state.current.timeTojump = now + jumpCoolDown;
state.current.jumping = true;
api.velocity.set(state.current.vel[0], jumpSpeed, state.current.vel[2]);
}
}
/** Handles shooting */
const bulletDirection = cameraDirection.clone().multiplyScalar(bulletSpeed);
const bulletPosition = camera.position
.clone()
.add(cameraDirection.clone().multiplyScalar(2));
if (mouseInput.current.left) {
const now = Date.now();
if (now >= state.current.timeToShoot) {
state.current.timeToShoot = now + bulletCoolDown;
setBullets((bullets) => [
...bullets,
{
id: now,
position: [bulletPosition.x, bulletPosition.y, bulletPosition.z],
forward: [bulletDirection.x, bulletDirection.y, bulletDirection.z],
},
]);
}
}
});
return (
<>
{/** Renders bullets */}
{bullets.map((bullet) => {
return (
<Bullet
key={bullet.id}
velocity={bullet.forward}
position={bullet.position}
/>
);
})}
</>
);
};
It registers the keys that are being pressed but nothing happens.