useGamepad
Alex 2024-01-26 14:07:58 +01:00
parent faad40aa9d
commit a8cf0d1ca4
6 changed files with 193 additions and 61 deletions

25
package-lock.json generated
View File

@ -13,10 +13,10 @@
"@react-three/postprocessing": "^2.15.11",
"@react-three/rapier": "^1.2.1",
"gsap": "^3.12.5",
"joymap": "^2.2.4",
"leva": "^0.9.35",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-gamepad": "^1.0.3",
"three": "^0.160.1",
"zustand": "^4.5.0"
},
@ -1862,6 +1862,11 @@
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"node_modules/fast-memoize": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz",
"integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw=="
},
"node_modules/fflate": {
"version": "0.6.10",
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz",
@ -2140,6 +2145,16 @@
"@types/react": "*"
}
},
"node_modules/joymap": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/joymap/-/joymap-2.2.4.tgz",
"integrity": "sha512-5N0VMbym49AwrfUz0vD6tE++I50SFjBYtwcJsdgE086GgAraGB2YQFsgVj+cG2fd8eUFmK+8U36Ecud3/UYTRg==",
"dependencies": {
"@babel/runtime": "^7.9.2",
"fast-memoize": "^2.5.2",
"lodash": "^4.17.15"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@ -2583,14 +2598,6 @@
"react": ">= 16.8"
}
},
"node_modules/react-gamepad": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/react-gamepad/-/react-gamepad-1.0.3.tgz",
"integrity": "sha512-gMwITmfoHtCaMFpDaEshcjeibHAgynXD28NnS2pa+dG+stwNoN66YDVizN7GfyIrYiW5Ft1ubRxs6/2xW9sRhQ==",
"peerDependencies": {
"react": ">=15.0.0"
}
},
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",

View File

@ -14,10 +14,10 @@
"@react-three/postprocessing": "^2.15.11",
"@react-three/rapier": "^1.2.1",
"gsap": "^3.12.5",
"joymap": "^2.2.4",
"leva": "^0.9.35",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-gamepad": "^1.0.3",
"three": "^0.160.1",
"zustand": "^4.5.0"
},

View File

@ -22,6 +22,7 @@ import { PointParticle } from "./Particles/PointParticle";
import { FlameParticles } from "./Particles/FlameParticles";
import { useStore } from "./store";
import { Cylinder } from "@react-three/drei";
import { useGamepad } from "./useGamepad";
export const PlayerController = () => {
const upPressed = useKeyboardControls((state) => state[Controls.up]);
@ -63,14 +64,16 @@ export const PlayerController = () => {
let targetZPosition = 8;
const [steeringAngleWheels, setSteeringAngleWheels] = useState(0);
const engineSound = useRef();
const { buttonA, joystick, RB } = useGamepad();
const [scale, setScale] = useState(0);
const { actions, addPastPosition } = useStore();
useFrame(({ pointer, clock }, delta) => {
const time = clock.getElapsedTime();
if (!body.current && !mario.current) return;
// console.log(buttonA, joystick);
// HANDLING AND STEERING
const kartRotation =
kart.current.rotation.y - driftDirection.current * driftForce.current;
@ -79,8 +82,6 @@ export const PlayerController = () => {
0,
-Math.cos(kartRotation)
);
actions.setBodyPosition(body.current.translation());
actions.setBodyRotation(kart.current.rotation);
if (leftPressed && currentSpeed > 0) {
steeringAngle = currentSteeringSpeed;
@ -95,6 +96,7 @@ export const PlayerController = () => {
}
// mouse steering
const steer = joystick[0] * 0.8;
if (!driftLeft.current && !driftRight.current) {
steeringAngle = currentSteeringSpeed * -pointer.x;
@ -106,6 +108,19 @@ export const PlayerController = () => {
steeringAngle = currentSteeringSpeed * -(pointer.x + 0.5);
targetXPosition = -camMaxOffset * -pointer.x;
}
if (steer) {
if (!driftLeft.current && !driftRight.current) {
steeringAngle = currentSteeringSpeed * -joystick[0];
targetXPosition = -camMaxOffset * -joystick[0];
} else if (driftLeft.current && !driftRight.current) {
steeringAngle = currentSteeringSpeed * -(joystick[0] - 1);
targetXPosition = -camMaxOffset * -joystick[0];
} else if (driftRight.current && !driftLeft.current) {
steeringAngle = currentSteeringSpeed * -(joystick[0] + 1);
targetXPosition = -camMaxOffset * -joystick[0];
}
}
// ACCELERATING
if (upPressed && currentSpeed < maxSpeed) {
@ -133,6 +148,33 @@ export const PlayerController = () => {
);
}
}
if (buttonA && currentSpeed < maxSpeed) {
// Accelerate the kart within the maximum speed limit
setCurrentSpeed(
Math.min(currentSpeed + acceleration * delta * 144, maxSpeed)
);
} else if (
buttonA &&
currentSpeed > maxSpeed &&
boostDuration.current > 0
) {
setCurrentSpeed(
Math.max(currentSpeed - decceleration * delta * 144, maxSpeed)
);
}
if (buttonA) {
if (currentSteeringSpeed < MaxSteeringSpeed) {
setCurrentSteeringSpeed(
Math.min(
currentSteeringSpeed + 0.0001 * delta * 144,
MaxSteeringSpeed
)
);
}
}
// REVERSING
if (downPressed && currentSpeed < -maxSpeed) {
setCurrentSpeed(
@ -140,7 +182,7 @@ export const PlayerController = () => {
);
}
// DECELERATING
else if (!upPressed && !downPressed) {
else if (!buttonA && !downPressed) {
if (currentSteeringSpeed > 0) {
setCurrentSteeringSpeed(
Math.max(currentSteeringSpeed - 0.00005 * delta * 144, 0)
@ -177,23 +219,46 @@ export const PlayerController = () => {
jumpForce.current += 10;
isOnFloor.current = false;
jumpIsHeld.current = true;
} else if (RB && isOnFloor.current && !jumpIsHeld.current) {
jumpForce.current += 10;
isOnFloor.current = false;
jumpIsHeld.current = true;
}
if (!isOnFloor.current && jumpForce.current > 0) {
jumpForce.current -= 1 * delta * 144;
}
if (!jumpPressed) {
if (!jumpPressed && !RB) {
jumpIsHeld.current = false;
driftDirection.current = 0;
driftForce.current = 0;
driftLeft.current = false;
driftRight.current = false;
}
console.log(jumpIsHeld.current);
// DRIFTING
// if (
// jumpIsHeld.current &&
// currentSteeringSpeed > 0 &&
// pointer.x < -0.1 &&
// !driftRight.current
// ) {
// driftLeft.current = true;
// }
// if (
// jumpIsHeld.current &&
// currentSteeringSpeed > 0 &&
// pointer.x > 0.1 &&
// !driftLeft.current
// ) {
// driftRight.current = true;
// }
if (steer) {
if (
jumpIsHeld.current &&
currentSteeringSpeed > 0 &&
pointer.x < -0.1 &&
steer < -0.1 &&
!driftRight.current
) {
driftLeft.current = true;
@ -201,11 +266,12 @@ export const PlayerController = () => {
if (
jumpIsHeld.current &&
currentSteeringSpeed > 0 &&
pointer.x > 0.1 &&
steer > 0.1 &&
!driftLeft.current
) {
driftRight.current = true;
}
}
if (!jumpIsHeld.current && !driftLeft.current && !driftRight.current) {
mario.current.rotation.y = THREE.MathUtils.lerp(
@ -324,7 +390,7 @@ export const PlayerController = () => {
<RigidBody
ref={body}
colliders={false}
position={[8, 20, -96]}
position={[8, 100, -96]}
centerOfMass={[0, -1, 0]}
mass={3}
ccd
@ -335,12 +401,8 @@ export const PlayerController = () => {
onCollisionEnter={(event) => {
isOnFloor.current = true;
}}
// onCollisionExit={(event) => {
// isOnFloor.current = false
// }}
/>
</RigidBody>
<group ref={kart} rotation={[0, Math.PI / 2, 0]}>
<group ref={mario}>
<Mario
@ -348,13 +410,6 @@ export const PlayerController = () => {
steeringAngleWheels={steeringAngleWheels}
isBoosting={isBoosting}
/>
{/* <pointLight
position={[0.6, 0.05, 0.5]}
intensity={scale}
color={turboColor}
distance={1}
/> */}
<mesh position={[0.6, 0.05, 0.5]} scale={scale}>
<sphereGeometry args={[0.05, 16, 16]} />
<meshStandardMaterial
@ -365,12 +420,6 @@ export const PlayerController = () => {
opacity={0.4}
/>
</mesh>
{/* <pointLight
position={[-0.6, 0.05, 0.5]}
intensity={scale}
color={turboColor}
distance={1}
/> */}
<mesh position={[-0.6, 0.05, 0.5]} scale={scale}>
<sphereGeometry args={[0.05, 16, 16]} />
<meshStandardMaterial
@ -381,15 +430,6 @@ export const PlayerController = () => {
opacity={0.4}
/>
</mesh>
{/* <Cylinder
args={[0.1, 0, 1, 128, 64, true]}
position={[-0.6, 0.05, 0.5]}
rotation={[Math.PI / 3, 0 , 0]}
>
<meshStandardMaterial side={THREE.DoubleSide} />
</Cylinder> */}
{/* <Flame/> */}
<FlameParticles isBoosting={isBoosting} />
<DriftParticlesLeft turboColor={turboColor} scale={scale} />
<DriftParticlesRight turboColor={turboColor} scale={scale} />
@ -414,15 +454,12 @@ export const PlayerController = () => {
turboColor={turboColor}
/>
</group>
{/* <ContactShadows frames={1} /> */}
<PerspectiveCamera
makeDefault
position={[0, 2, 8]}
fov={50}
ref={cam}
/>
{/* <PositionalAudio ref={engineSound} url="./sounds/engine.wav" autoplay loop distance={10}/> */}
</group>
</group>
);

View File

@ -57,7 +57,7 @@ function setItemAt(instances, bodyPosition, bodyRotation, index) {
.add(bodyPosition);
// Apply the offset to position the skid marks behind the body
console.log(bodyPosition);
// console.log(bodyPosition);
o.position.copy(bodyPosition.x, bodyPosition.y + 2, bodyPosition.z);
o.rotation.set(0, bodyRotation, 0);

View File

@ -6,6 +6,39 @@ export const useStore = create((set, get) => ({
bodyPosition: [0, 0, 0],
bodyRotation: [0, 0, 0],
pastPositions: [],
LeftAxis: [0, 0],
buttons : {
A: false,
B: false,
X: false,
Y: false,
LB: false,
RB: false,
LT: false,
RT: false,
Back: false,
Start: false,
LeftStick: false,
RightStick: false,
Up: false,
Down: false,
Left: false,
Right: false,
},
setLeftAxis: (axis) => {
set({ LeftAxis: axis });
},
setButtons: (button, value) => {
set((state) => ({
buttons: {
...state.buttons,
[button]: value,
},
}));
},
getButtons: () => {
return get().buttons;
},
addPastPosition: (position) => {
set((state) => ({
pastPositions: [position, ...state.pastPositions.slice(0, 499)],

View File

@ -0,0 +1,55 @@
import { useState, useEffect } from 'react';
export const useGamepad = () => {
const [gamepadInfo, setGamepadInfo] = useState({ connected: false, buttonA: false, joystick: [0, 0], RB: false });
// Function to update gamepad state
const updateGamepadState = () => {
const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];
const gamepad = gamepads[0]; // Assuming the first gamepad
if (gamepad) {
const newGamepadInfo = {
connected: true,
buttonA: gamepad.buttons[0].pressed,
RB: gamepad.buttons[5].pressed,
joystick: [gamepad.axes[0], gamepad.axes[1]]
};
// Update state only if there's a change
if (JSON.stringify(newGamepadInfo) !== JSON.stringify(gamepadInfo)) {
setGamepadInfo(newGamepadInfo);
}
} else {
if (gamepadInfo.connected) {
setGamepadInfo({ connected: false, buttonA: false, joystick: [0, 0], RB: false });
}
}
};
useEffect(() => {
const gamepadConnected = () => {
console.log('Gamepad connected!');
updateGamepadState();
};
const gamepadDisconnected = () => {
console.log('Gamepad disconnected!');
setGamepadInfo({ connected: false, buttonA: false, joystick: [0, 0], RB: false });
};
window.addEventListener('gamepadconnected', gamepadConnected);
window.addEventListener('gamepaddisconnected', gamepadDisconnected);
// Polling the gamepad state
const interval = setInterval(updateGamepadState, 100);
return () => {
window.removeEventListener('gamepadconnected', gamepadConnected);
window.removeEventListener('gamepaddisconnected', gamepadDisconnected);
clearInterval(interval);
};
}, [gamepadInfo]);
return gamepadInfo;
};