feat:(game) fixed drifting mechanics and improved postprocessing effects

skidmarks
Alex 2024-01-22 19:46:07 +01:00
parent 602536bc23
commit cb8052e1d3
3 changed files with 230 additions and 180 deletions

View File

@ -38,7 +38,6 @@ function App() {
<Suspense fallback={null}> <Suspense fallback={null}>
<Physics <Physics
gravity={[0, -90, 0]} gravity={[0, -90, 0]}
predictionDistance={0.001}
> >
<KeyboardControls map={map}> <KeyboardControls map={map}>
<Experience /> <Experience />

View File

@ -4,7 +4,7 @@ import { RigidBody } from '@react-three/rapier'
import { PlayerController } from './PlayerController' import { PlayerController } from './PlayerController'
import { Track } from './models/Spafrancorchamps-REALISTIC' import { Track } from './models/Spafrancorchamps-REALISTIC'
import { Paris } from './models/Tour_paris_promenade' import { Paris } from './models/Tour_paris_promenade'
import { EffectComposer, N8AO, Bloom, DepthOfField, TiltShift2, HueSaturation, SMAA } from '@react-three/postprocessing' import { EffectComposer, N8AO, Bloom, DepthOfField, TiltShift2, HueSaturation, SMAA, ChromaticAberration, Vignette } from '@react-three/postprocessing'
export const Experience = () => { export const Experience = () => {
return ( return (
@ -34,24 +34,28 @@ export const Experience = () => {
<EffectComposer <EffectComposer
multisampling={0} multisampling={0}
disableNormalPass disableNormalPass
disableSSAO
disableDepthPass
> >
<SMAA /> <SMAA />
{/* <N8AO distanceFalloff={1} aoRadius={1} intensity={4} /> */} <N8AO distanceFalloff={1} aoRadius={1} intensity={3} />
<Bloom <Bloom
luminanceThreshold={0} luminanceThreshold={0}
mipmapBlur mipmapBlur
luminanceSmoothing={0.01} luminanceSmoothing={0.01}
intensity={0.5} intensity={0.5}
/> />
<DepthOfField {/* <DepthOfField
target={[0, 0, 13]} target={[0, 0, 12]}
focalLength={0.3} focalLength={10}
bokehScale={20} bokehScale={20}
// height={700} resolutionScale={1}
resolutionScale={0.3} /> */}
/> <TiltShift2/>
{/* <TiltShift2/> */} <ChromaticAberration offset={[0.001, 0.001]} />
<HueSaturation saturation={0.1} /> <HueSaturation saturation={0.1} />
<Vignette eskil={false} offset={0.1} darkness={0.4} />
</EffectComposer> </EffectComposer>
</> </>
) )

View File

@ -1,247 +1,314 @@
import { Controls } from '../App' import { Controls } from "../App";
import { RigidBody, useRapier } from '@react-three/rapier' import { BallCollider, RigidBody, useRapier } from "@react-three/rapier";
import { useKeyboardControls, PerspectiveCamera, ContactShadows, Sphere } from '@react-three/drei' import {
import { useFrame, useThree } from '@react-three/fiber' useKeyboardControls,
import { useRef, useState, useEffect, useCallback } from 'react' PerspectiveCamera,
import * as THREE from 'three' ContactShadows,
import { Model } from './models/Racing_kart' Sphere,
import { FrontRightWheel } from './models/Front_Right_Wheel' OrbitControls,
import { FrontLeftWheel } from './models/Front_Left_Wheel' } from "@react-three/drei";
import { RearWheels } from './models/Rear_wheels' import { useFrame, useThree } from "@react-three/fiber";
import gsap from 'gsap' import { useRef, useState, useEffect, useCallback } from "react";
import { Mario } from './models/Mario_kart' import * as THREE from "three";
import { Particles1 } from './Particles1' import { Model } from "./models/Racing_kart";
import { DriftParticlesLeft } from './DriftParticlesLeft' import { FrontRightWheel } from "./models/Front_Right_Wheel";
import { DriftParticlesRight } from './DriftParticlesRight' import { FrontLeftWheel } from "./models/Front_Left_Wheel";
import FakeGlowMaterial from './FakeGlow/FakeGlowMaterial' import { RearWheels } from "./models/Rear_wheels";
import gsap from "gsap";
import { Mario } from "./models/Mario_kart";
import { Particles1 } from "./Particles1";
import { DriftParticlesLeft } from "./DriftParticlesLeft";
import { DriftParticlesRight } from "./DriftParticlesRight";
import FakeGlowMaterial from "./FakeGlow/FakeGlowMaterial";
export const PlayerController = () => { export const PlayerController = () => {
const upPressed = useKeyboardControls((state) => state[Controls.up]) const upPressed = useKeyboardControls((state) => state[Controls.up]);
const downPressed = useKeyboardControls((state) => state[Controls.down]) const downPressed = useKeyboardControls((state) => state[Controls.down]);
const leftPressed = useKeyboardControls((state) => state[Controls.left]) const leftPressed = useKeyboardControls((state) => state[Controls.left]);
const rightPressed = useKeyboardControls((state) => state[Controls.right]) const rightPressed = useKeyboardControls((state) => state[Controls.right]);
const jumpPressed = useKeyboardControls((state) => state[Controls.jump]) const jumpPressed = useKeyboardControls((state) => state[Controls.jump]);
const [isOnGround, setIsOnGround] = useState(false) const [isOnGround, setIsOnGround] = useState(false);
const body = useRef() const body = useRef();
const kart = useRef() const kart = useRef();
const cam = useRef() const cam = useRef();
const initialSpeed = 0 const initialSpeed = 0;
const maxSpeed = 30 const maxSpeed = 30;
const boostSpeed = 50 const boostSpeed = 50;
const acceleration = 0.1 const acceleration = 0.1;
const decceleration = 0.2 const decceleration = 0.2;
const damping = 0.001 const damping = -0.1;
const MaxSteeringSpeed = 0.01 const MaxSteeringSpeed = 0.01;
const [currentSteeringSpeed, setCurrentSteeringSpeed] = useState(0) const [currentSteeringSpeed, setCurrentSteeringSpeed] = useState(0);
const [currentSpeed, setCurrentSpeed] = useState(initialSpeed) const [currentSpeed, setCurrentSpeed] = useState(initialSpeed);
const camMaxOffset = 0.5 const camMaxOffset = 0.5;
let steeringAngle = 0 let steeringAngle = 0;
const isOnFloor = useRef(false) const isOnFloor = useRef(false);
const jumpForce = useRef(0) const jumpForce = useRef(0);
const jumpIsHeld = useRef(false) const jumpIsHeld = useRef(false);
const driftDirection = useRef(0) const driftDirection = useRef(0);
const driftLeft = useRef(false) const driftLeft = useRef(false);
const driftRight = useRef(false) const driftRight = useRef(false);
const driftForce = useRef(0) const driftForce = useRef(0);
const mario = useRef() const mario = useRef();
const accumulatedDriftPower = useRef(0) const accumulatedDriftPower = useRef(0);
const blueTurboThreshold = 10 const blueTurboThreshold = 10;
const orangeTurboThreshold = 30 const orangeTurboThreshold = 30;
const purpleTurboThreshold = 60 const purpleTurboThreshold = 60;
const [turboColor, setTurboColor] = useState(0xffffff) const [turboColor, setTurboColor] = useState(0xffffff);
const boostDuration = useRef(0) const boostDuration = useRef(0);
const isBoosting = useRef(false) const isBoosting = useRef(false);
let targetXPosition = 0 let targetXPosition = 0;
let targetZPosition = 8 let targetZPosition = 8;
const [steeringAngleWheels, setSteeringAngleWheels] = useState(0) const [steeringAngleWheels, setSteeringAngleWheels] = useState(0);
const [scale, setScale] = useState(0) const [scale, setScale] = useState(0);
useFrame(({ pointer, clock }) => { useFrame(({ pointer, clock }) => {
const time = clock.getElapsedTime() const time = clock.getElapsedTime();
if (!body.current && !mario.current) return if (!body.current && !mario.current) return;
// HANDLING AND STEERING // HANDLING AND STEERING
const kartRotation = kart.current.rotation.y - driftDirection.current * driftForce.current const kartRotation =
const forwardDirection = new THREE.Vector3(-Math.sin(kartRotation), 0, -Math.cos(kartRotation)) kart.current.rotation.y - driftDirection.current * driftForce.current;
const forwardDirection = new THREE.Vector3(
-Math.sin(kartRotation),
0,
-Math.cos(kartRotation)
);
console.log(forwardDirection);
if (leftPressed && currentSpeed > 0) { if (leftPressed && currentSpeed > 0) {
steeringAngle = currentSteeringSpeed steeringAngle = currentSteeringSpeed;
targetXPosition = -camMaxOffset targetXPosition = -camMaxOffset;
} else if (rightPressed && currentSpeed > 0) { } else if (rightPressed && currentSpeed > 0) {
steeringAngle = -currentSteeringSpeed steeringAngle = -currentSteeringSpeed;
targetXPosition = camMaxOffset targetXPosition = camMaxOffset;
} else { } else {
steeringAngle = 0 steeringAngle = 0;
targetXPosition = 0 targetXPosition = 0;
1 1;
} }
// mouse steering // mouse steering
steeringAngle = currentSteeringSpeed * -pointer.x
targetXPosition = -camMaxOffset * -pointer.x
if(!driftLeft.current && !driftRight.current){
steeringAngle = currentSteeringSpeed * -pointer.x;
targetXPosition = -camMaxOffset * -pointer.x;
}
else if (driftLeft.current && !driftRight.current) {
steeringAngle = currentSteeringSpeed * -(pointer.x - 0.5);
targetXPosition = -camMaxOffset * -pointer.x;
}
else if (driftRight.current && !driftLeft.current) {
steeringAngle = currentSteeringSpeed * -(pointer.x + 0.5);
targetXPosition = -camMaxOffset * -pointer.x;
}
// ACCELERATING // ACCELERATING
if (upPressed && currentSpeed < maxSpeed) { if (upPressed && currentSpeed < maxSpeed) {
// Accelerate the kart within the maximum speed limit // Accelerate the kart within the maximum speed limit
setCurrentSpeed(Math.min(currentSpeed + acceleration, maxSpeed)) setCurrentSpeed(Math.min(currentSpeed + acceleration, maxSpeed));
} else if (upPressed && currentSpeed > maxSpeed && boostDuration.current > 0) { } else if (
setCurrentSpeed(Math.max(currentSpeed - decceleration, maxSpeed)) upPressed &&
currentSpeed > maxSpeed &&
boostDuration.current > 0
) {
setCurrentSpeed(Math.max(currentSpeed - decceleration, maxSpeed));
} }
if (upPressed) { if (upPressed) {
if (currentSteeringSpeed < MaxSteeringSpeed) { if (currentSteeringSpeed < MaxSteeringSpeed) {
setCurrentSteeringSpeed(Math.min(currentSteeringSpeed + 0.0001, MaxSteeringSpeed)) setCurrentSteeringSpeed(
Math.min(currentSteeringSpeed + 0.0001, MaxSteeringSpeed)
);
} }
} }
// REVERSING // REVERSING
if (downPressed && currentSpeed < -maxSpeed) { if (downPressed && currentSpeed < -maxSpeed) {
setCurrentSpeed(Math.max(currentSpeed - acceleration, -maxSpeed)) setCurrentSpeed(Math.max(currentSpeed - acceleration, -maxSpeed));
} }
// DECELERATING // DECELERATING
else if (!upPressed && !downPressed) { else if (!upPressed && !downPressed) {
if (currentSteeringSpeed > 0) { if (currentSteeringSpeed > 0) {
setCurrentSteeringSpeed(Math.max(currentSteeringSpeed - 0.00005, 0)) setCurrentSteeringSpeed(Math.max(currentSteeringSpeed - 0.00005, 0));
} else if (currentSteeringSpeed < 0) { } else if (currentSteeringSpeed < 0) {
setCurrentSteeringSpeed(Math.min(currentSteeringSpeed + 0.00005, 0)) setCurrentSteeringSpeed(Math.min(currentSteeringSpeed + 0.00005, 0));
} }
setCurrentSpeed(Math.max(currentSpeed - decceleration, 0)) setCurrentSpeed(Math.max(currentSpeed - decceleration, 0));
} }
// Update the kart's rotation based on the steering angle // Update the kart's rotation based on the steering angle
kart.current.rotation.y += steeringAngle kart.current.rotation.y += steeringAngle;
// Apply damping to simulate slowdown when no keys are pressed // Apply damping to simulate slowdown when no keys are pressed
body.current.applyImpulse( body.current.applyImpulse(
{ {
x: -body.current.linvel().x * (1 - damping), x: -body.current.linvel().x * (1 - damping),
y: 0, y: 0,
z: -body.current.linvel().z * (1 - damping) z: -body.current.linvel().z * (1 - damping),
}, },
true true
) );
const bodyPosition = body.current.translation() const bodyPosition = body.current.translation();
kart.current.position.set(bodyPosition.x, bodyPosition.y - 1, bodyPosition.z) kart.current.position.set(
bodyPosition.x,
bodyPosition.y - 0.5,
bodyPosition.z
);
// JUMPING // JUMPING
if (jumpPressed && isOnFloor.current && !jumpIsHeld.current) { if (jumpPressed && isOnFloor.current && !jumpIsHeld.current) {
jumpForce.current += 11 jumpForce.current += 10;
isOnFloor.current = false isOnFloor.current = false;
jumpIsHeld.current = true jumpIsHeld.current = true;
} }
if (!isOnFloor.current && jumpForce.current > 0) { if (!isOnFloor.current && jumpForce.current > 0) {
jumpForce.current -= 1 jumpForce.current -= 1;
} }
if (!jumpPressed) { if (!jumpPressed) {
jumpIsHeld.current = false jumpIsHeld.current = false;
driftDirection.current = 0 driftDirection.current = 0;
driftForce.current = 0 driftForce.current = 0;
driftLeft.current = false driftLeft.current = false;
driftRight.current = false driftRight.current = false;
} }
// DRIFTING // DRIFTING
if (jumpIsHeld.current && currentSteeringSpeed > 0 && pointer.x < -0.24 && !driftRight.current) { if (
driftLeft.current = true jumpIsHeld.current &&
currentSteeringSpeed > 0 &&
pointer.x < -0.24 &&
!driftRight.current
) {
driftLeft.current = true;
} }
if (jumpIsHeld.current && currentSteeringSpeed > 0 && pointer.x > 0.24 && !driftLeft.current) { if (
driftRight.current = true jumpIsHeld.current &&
currentSteeringSpeed > 0 &&
pointer.x > 0.24 &&
!driftLeft.current
) {
driftRight.current = true;
} }
if (!jumpIsHeld.current && !driftLeft.current && !driftRight.current) { if (!jumpIsHeld.current && !driftLeft.current && !driftRight.current) {
mario.current.rotation.y = THREE.MathUtils.lerp(mario.current.rotation.y, 0, 0.001) mario.current.rotation.y = THREE.MathUtils.lerp(
setTurboColor(0xffffff) mario.current.rotation.y,
accumulatedDriftPower.current = 0 0,
0.0001
);
setTurboColor(0xffffff);
accumulatedDriftPower.current = 0;
} }
if (driftLeft.current) { if (driftLeft.current) {
driftDirection.current = 1 driftDirection.current = 1;
driftForce.current = 0.4 driftForce.current = 0.4;
mario.current.rotation.y = THREE.MathUtils.lerp(mario.current.rotation.y, steeringAngle * 50 + 0.5, 0.1) mario.current.rotation.y = THREE.MathUtils.lerp(
accumulatedDriftPower.current += 0.1 * (steeringAngle + 1) mario.current.rotation.y,
steeringAngle * 50 + 0.5,
0.05
);
accumulatedDriftPower.current += 0.1 * (steeringAngle + 1);
} }
if (driftRight.current) { if (driftRight.current) {
driftDirection.current = -1 driftDirection.current = -1;
driftForce.current = 0.4 driftForce.current = 0.4;
mario.current.rotation.y = THREE.MathUtils.lerp(mario.current.rotation.y, -(-steeringAngle * 50 + 0.5), 0.1) mario.current.rotation.y = THREE.MathUtils.lerp(
accumulatedDriftPower.current += 0.1 * (-steeringAngle + 1) mario.current.rotation.y,
-(-steeringAngle * 50 + 0.5),
0.05
);
accumulatedDriftPower.current += 0.1 * (-steeringAngle + 1);
} }
if (!driftLeft.current && !driftRight.current) { if (!driftLeft.current && !driftRight.current) {
mario.current.rotation.y = THREE.MathUtils.lerp(mario.current.rotation.y, steeringAngle * 30, 0.1) mario.current.rotation.y = THREE.MathUtils.lerp(
setScale(0) mario.current.rotation.y,
steeringAngle * 30,
0.05
);
setScale(0);
} }
if (accumulatedDriftPower.current > blueTurboThreshold) { if (accumulatedDriftPower.current > blueTurboThreshold) {
setTurboColor(0x00ffff) setTurboColor(0x00ffff);
boostDuration.current = 50 boostDuration.current = 50;
} }
if (accumulatedDriftPower.current > orangeTurboThreshold) { if (accumulatedDriftPower.current > orangeTurboThreshold) {
setTurboColor(0xffcf00) setTurboColor(0xffcf00);
boostDuration.current = 100 boostDuration.current = 100;
} }
if (accumulatedDriftPower.current > purpleTurboThreshold) { if (accumulatedDriftPower.current > purpleTurboThreshold) {
setTurboColor(0xff00ff) setTurboColor(0xff00ff);
boostDuration.current = 250 boostDuration.current = 250;
} }
if (driftLeft.current || driftRight.current) { if (driftLeft.current || driftRight.current) {
const oscillation = Math.sin(time * 1000) * 0.1 const oscillation = Math.sin(time * 1000) * 0.1;
const vibration = oscillation + 0.9 const vibration = oscillation + 0.9;
setScale(vibration) setScale(vibration);
} }
// RELEASING DRIFT // RELEASING DRIFT
if (boostDuration.current > 1 && !jumpIsHeld.current) { if (boostDuration.current > 1 && !jumpIsHeld.current) {
setCurrentSpeed(boostSpeed) setCurrentSpeed(boostSpeed);
boostDuration.current -= 1 boostDuration.current -= 1;
targetZPosition = 10 targetZPosition = 10;
} else if (boostDuration.current <= 1) { } else if (boostDuration.current <= 1) {
targetZPosition = 8 targetZPosition = 8;
} }
// CAMERA WORK // CAMERA WORK
cam.current.updateMatrixWorld() cam.current.updateMatrixWorld();
cam.current.position.x = THREE.MathUtils.lerp(cam.current.position.x, targetXPosition, 0.01) cam.current.position.x = THREE.MathUtils.lerp(
cam.current.position.x,
targetXPosition,
0.01
);
cam.current.position.z = THREE.MathUtils.lerp(cam.current.position.z, targetZPosition, 0.01) cam.current.position.z = THREE.MathUtils.lerp(
cam.current.updateMatrixWorld() cam.current.position.z,
targetZPosition,
0.01
);
body.current.applyImpulse( body.current.applyImpulse(
{ {
x: forwardDirection.x * currentSpeed, x: forwardDirection.x * currentSpeed,
y: 0 + jumpForce.current, y: 0 + jumpForce.current,
z: forwardDirection.z * currentSpeed z: forwardDirection.z * currentSpeed,
}, },
true true
) );
// Update the kart's rotation based on the steering angle // Update the kart's rotation based on the steering angle
setSteeringAngleWheels(steeringAngle * 25) setSteeringAngleWheels(steeringAngle * 25);
}) });
return ( return (
<group> <group>
<RigidBody <RigidBody
ref={body} ref={body}
type='dynamic' colliders={false}
colliders={'ball'}
position={[0, 20, 0]} position={[0, 20, 0]}
centerOfMass={[0, -1, 0]} centerOfMass={[0, -1, 0]}
onCollisionEnter={(event) => { mass={3}
isOnFloor.current = true
}}
> >
<mesh transparent> <BallCollider
<sphereGeometry args={[1, 6, 6]} /> args={[0.5]}
<meshStandardMaterial mass={3}
color='blue' onCollisionEnter={(event) => {
transparent isOnFloor.current = true;
opacity={0} }}
/> />
</mesh> onCollisionEnter=
{(event) => {
isOnFloor.current = false;
}}
</RigidBody> </RigidBody>
<group ref={kart}> <group ref={kart}>
@ -250,25 +317,14 @@ export const PlayerController = () => {
currentSpeed={currentSpeed} currentSpeed={currentSpeed}
steeringAngleWheels={steeringAngleWheels} steeringAngleWheels={steeringAngleWheels}
/> />
{/* <pointLight <pointLight
position={[0.6, 0.05, 0.5]} position={[0.6, 0.05, 0.5]}
intensity={scale} intensity={scale}
color={turboColor} color={turboColor}
distance={1} distance={1}
/> */}
<Sphere
args={[1, 16, 16]}
position={[0.6, 0.05, 0.5]}
>
<FakeGlowMaterial
glowCenter={0.1}
edgeIntensity={6.2}
/> />
</Sphere>
<mesh <mesh position={[0.6, 0.05, 0.5]} scale={scale}>
position={[0.6, 0.05, 0.5]}
scale={scale}
>
<sphereGeometry args={[0.1, 16, 16]} /> <sphereGeometry args={[0.1, 16, 16]} />
<meshStandardMaterial <meshStandardMaterial
emissive={turboColor} emissive={turboColor}
@ -284,10 +340,7 @@ export const PlayerController = () => {
color={turboColor} color={turboColor}
distance={1} distance={1}
/> />
<mesh <mesh position={[-0.6, 0.05, 0.5]} scale={scale}>
position={[-0.6, 0.05, 0.5]}
scale={scale}
>
<sphereGeometry args={[0.1, 16, 16]} /> <sphereGeometry args={[0.1, 16, 16]} />
<meshStandardMaterial <meshStandardMaterial
emissive={turboColor} emissive={turboColor}
@ -298,14 +351,8 @@ export const PlayerController = () => {
/> />
</mesh> </mesh>
<DriftParticlesLeft <DriftParticlesLeft turboColor={turboColor} scale={scale} />
turboColor={turboColor} <DriftParticlesRight turboColor={turboColor} scale={scale} />
scale={scale}
/>
<DriftParticlesRight
turboColor={turboColor}
scale={scale}
/>
</group> </group>
{/* <ContactShadows frames={1} /> */} {/* <ContactShadows frames={1} /> */}
@ -317,5 +364,5 @@ export const PlayerController = () => {
/> />
</group> </group>
</group> </group>
) );
} };