diff --git a/src/components/Experience.jsx b/src/components/Experience.jsx index 3e8af61..4ccad88 100644 --- a/src/components/Experience.jsx +++ b/src/components/Experience.jsx @@ -6,11 +6,13 @@ import { Track } from './models/Spafrancorchamps-REALISTIC' import { Paris } from './models/Tour_paris_promenade' import { EffectComposer, N8AO, Bloom, DepthOfField, TiltShift2, HueSaturation, SMAA, ChromaticAberration, Vignette } from '@react-three/postprocessing' import { PlayerControllerAgain } from './PlayerControllerAgain' +import { Skid } from './Skid' export const Experience = () => { return ( <> + {/* */} { alphaMap={texture} transparent={true} depthWrite={false} - color={turboColor} + color={0x000000} opacity={opacity} toneMapped={false} /> diff --git a/src/components/PlayerController.jsx b/src/components/PlayerController.jsx index 50b22b9..bc4781f 100644 --- a/src/components/PlayerController.jsx +++ b/src/components/PlayerController.jsx @@ -1,254 +1,328 @@ -import { Controls } from '../App' -import { BallCollider, RigidBody, useRapier } from '@react-three/rapier' -import { useKeyboardControls, PerspectiveCamera, ContactShadows, Sphere, OrbitControls, Trail, PositionalAudio } from '@react-three/drei' -import { useFrame, useThree } from '@react-three/fiber' -import { useRef, useState, useEffect, useCallback } from 'react' -import * as THREE from 'three' -import { Model } from './models/Racing_kart' -import { FrontRightWheel } from './models/Front_Right_Wheel' -import { FrontLeftWheel } from './models/Front_Left_Wheel' -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' -import { PointParticle } from './PointParticle' -import { FlameParticle } from './FlameParticle' -import { FlameParticles } from './FlameParticles' +import { Controls } from "../App"; +import { BallCollider, RigidBody, useRapier, vec3 } from "@react-three/rapier"; +import { + useKeyboardControls, + PerspectiveCamera, + ContactShadows, + Sphere, + OrbitControls, + Trail, + PositionalAudio, +} from "@react-three/drei"; +import { useFrame, useThree } from "@react-three/fiber"; +import { useRef, useState, useEffect, useCallback } from "react"; +import * as THREE from "three"; +import { Model } from "./models/Racing_kart"; +import { FrontRightWheel } from "./models/Front_Right_Wheel"; +import { FrontLeftWheel } from "./models/Front_Left_Wheel"; +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"; +import { PointParticle } from "./PointParticle"; +import { FlameParticle } from "./FlameParticle"; +import { FlameParticles } from "./FlameParticles"; +import { useStore } from "./store"; +import { Cylinder } from "@react-three/drei"; export const PlayerController = () => { - const upPressed = useKeyboardControls((state) => state[Controls.up]) - const downPressed = useKeyboardControls((state) => state[Controls.down]) - const leftPressed = useKeyboardControls((state) => state[Controls.left]) - const rightPressed = useKeyboardControls((state) => state[Controls.right]) - const jumpPressed = useKeyboardControls((state) => state[Controls.jump]) - const [isOnGround, setIsOnGround] = useState(false) - const body = useRef() - const kart = useRef() - const cam = useRef() - const initialSpeed = 0 - const maxSpeed = 30 - const boostSpeed = 50 - const acceleration = 0.1 - const decceleration = 0.2 - const damping = -0.1 - const MaxSteeringSpeed = 0.01 - const [currentSteeringSpeed, setCurrentSteeringSpeed] = useState(0) - const [currentSpeed, setCurrentSpeed] = useState(initialSpeed) - const camMaxOffset = 1 - let steeringAngle = 0 - const isOnFloor = useRef(false) - const jumpForce = useRef(0) - const jumpIsHeld = useRef(false) - const driftDirection = useRef(0) - const driftLeft = useRef(false) - const driftRight = useRef(false) - const driftForce = useRef(0) - const mario = useRef() - const accumulatedDriftPower = useRef(0) - const blueTurboThreshold = 10 - const orangeTurboThreshold = 30 - const purpleTurboThreshold = 60 - const [turboColor, setTurboColor] = useState(0xffffff) - const boostDuration = useRef(0) - const [isBoosting, setIsBoosting] = useState(false) - let targetXPosition = 0 - let targetZPosition = 8 - const [steeringAngleWheels, setSteeringAngleWheels] = useState(0) - const engineSound = useRef() + const upPressed = useKeyboardControls((state) => state[Controls.up]); + const downPressed = useKeyboardControls((state) => state[Controls.down]); + const leftPressed = useKeyboardControls((state) => state[Controls.left]); + const rightPressed = useKeyboardControls((state) => state[Controls.right]); + const jumpPressed = useKeyboardControls((state) => state[Controls.jump]); + const [isOnGround, setIsOnGround] = useState(false); + const body = useRef(); + const kart = useRef(); + const cam = useRef(); + const initialSpeed = 0; + const maxSpeed = 30; + const boostSpeed = 50; + const acceleration = 0.1; + const decceleration = 0.2; + const damping = -0.1; + const MaxSteeringSpeed = 0.01; + const [currentSteeringSpeed, setCurrentSteeringSpeed] = useState(0); + const [currentSpeed, setCurrentSpeed] = useState(initialSpeed); + const camMaxOffset = 1; + let steeringAngle = 0; + const isOnFloor = useRef(false); + const jumpForce = useRef(0); + const jumpIsHeld = useRef(false); + const driftDirection = useRef(0); + const driftLeft = useRef(false); + const driftRight = useRef(false); + const driftForce = useRef(0); + const mario = useRef(); + const accumulatedDriftPower = useRef(0); + const blueTurboThreshold = 10; + const orangeTurboThreshold = 30; + const purpleTurboThreshold = 60; + const [turboColor, setTurboColor] = useState(0xffffff); + const boostDuration = useRef(0); + const [isBoosting, setIsBoosting] = useState(false); + let targetXPosition = 0; + let targetZPosition = 8; + const [steeringAngleWheels, setSteeringAngleWheels] = useState(0); + const engineSound = useRef(); - const [scale, setScale] = useState(0) + const [scale, setScale] = useState(0); + const { actions, addPastPosition } = useStore(); useFrame(({ pointer, clock }, delta) => { - const time = clock.getElapsedTime() - if (!body.current && !mario.current) return + const time = clock.getElapsedTime(); + if (!body.current && !mario.current) return; // HANDLING AND STEERING - const kartRotation = kart.current.rotation.y - driftDirection.current * driftForce.current - const forwardDirection = new THREE.Vector3(-Math.sin(kartRotation), 0, -Math.cos(kartRotation)) + const kartRotation = + kart.current.rotation.y - driftDirection.current * driftForce.current; + const forwardDirection = new THREE.Vector3( + -Math.sin(kartRotation), + 0, + -Math.cos(kartRotation) + ); + actions.setBodyPosition(body.current.translation()); + actions.setBodyRotation(kart.current.rotation); if (leftPressed && currentSpeed > 0) { - steeringAngle = currentSteeringSpeed - targetXPosition = -camMaxOffset + steeringAngle = currentSteeringSpeed; + targetXPosition = -camMaxOffset; } else if (rightPressed && currentSpeed > 0) { - steeringAngle = -currentSteeringSpeed - targetXPosition = camMaxOffset + steeringAngle = -currentSteeringSpeed; + targetXPosition = camMaxOffset; } else { - steeringAngle = 0 - targetXPosition = 0 - 1 + steeringAngle = 0; + targetXPosition = 0; + 1; } // mouse steering if (!driftLeft.current && !driftRight.current) { - steeringAngle = currentSteeringSpeed * -pointer.x - targetXPosition = -camMaxOffset * -pointer.x + steeringAngle = currentSteeringSpeed * -pointer.x; + targetXPosition = -camMaxOffset * -pointer.x; } else if (driftLeft.current && !driftRight.current) { - steeringAngle = currentSteeringSpeed * -(pointer.x - 0.5) - targetXPosition = -camMaxOffset * -pointer.x + 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 + steeringAngle = currentSteeringSpeed * -(pointer.x + 0.5); + targetXPosition = -camMaxOffset * -pointer.x; } // ACCELERATING if (upPressed && currentSpeed < maxSpeed) { // Accelerate the kart within the maximum speed limit - setCurrentSpeed(Math.min(currentSpeed + acceleration * delta * 144, maxSpeed)) - } else if (upPressed && currentSpeed > maxSpeed && boostDuration.current > 0) { - setCurrentSpeed(Math.max(currentSpeed - decceleration * delta * 144, maxSpeed)) + setCurrentSpeed( + Math.min(currentSpeed + acceleration * delta * 144, maxSpeed) + ); + } else if ( + upPressed && + currentSpeed > maxSpeed && + boostDuration.current > 0 + ) { + setCurrentSpeed( + Math.max(currentSpeed - decceleration * delta * 144, maxSpeed) + ); } if (upPressed) { if (currentSteeringSpeed < MaxSteeringSpeed) { - setCurrentSteeringSpeed(Math.min(currentSteeringSpeed + 0.0001 * delta * 144, MaxSteeringSpeed)) + setCurrentSteeringSpeed( + Math.min( + currentSteeringSpeed + 0.0001 * delta * 144, + MaxSteeringSpeed + ) + ); } } // REVERSING if (downPressed && currentSpeed < -maxSpeed) { - setCurrentSpeed(Math.max(currentSpeed - acceleration * delta * 144, -maxSpeed)) + setCurrentSpeed( + Math.max(currentSpeed - acceleration * delta * 144, -maxSpeed) + ); } // DECELERATING else if (!upPressed && !downPressed) { if (currentSteeringSpeed > 0) { - setCurrentSteeringSpeed(Math.max(currentSteeringSpeed - 0.00005 * delta * 144, 0)) + setCurrentSteeringSpeed( + Math.max(currentSteeringSpeed - 0.00005 * delta * 144, 0) + ); } else if (currentSteeringSpeed < 0) { - setCurrentSteeringSpeed(Math.min(currentSteeringSpeed + 0.00005 * delta * 144, 0)) + setCurrentSteeringSpeed( + Math.min(currentSteeringSpeed + 0.00005 * delta * 144, 0) + ); } - setCurrentSpeed(Math.max(currentSpeed - decceleration * delta * 144, 0)) + setCurrentSpeed(Math.max(currentSpeed - decceleration * delta * 144, 0)); } // Update the kart's rotation based on the steering angle - kart.current.rotation.y += steeringAngle * delta * 144 + kart.current.rotation.y += steeringAngle * delta * 144; // Apply damping to simulate slowdown when no keys are pressed body.current.applyImpulse( { x: -body.current.linvel().x * (1 - damping) * delta * 144, y: 0, - z: -body.current.linvel().z * (1 - damping) * delta * 144 + z: -body.current.linvel().z * (1 - damping) * delta * 144, }, true - ) - const bodyPosition = body.current.translation() - kart.current.position.set(bodyPosition.x, bodyPosition.y - 0.5, bodyPosition.z) + ); + const bodyPosition = body.current.translation(); + kart.current.position.set( + bodyPosition.x, + bodyPosition.y - 0.5, + bodyPosition.z + ); // JUMPING if (jumpPressed && isOnFloor.current && !jumpIsHeld.current) { - jumpForce.current += 10 - isOnFloor.current = false - jumpIsHeld.current = true + jumpForce.current += 10; + isOnFloor.current = false; + jumpIsHeld.current = true; } if (!isOnFloor.current && jumpForce.current > 0) { - jumpForce.current -= 1 * delta * 144 + jumpForce.current -= 1 * delta * 144; } if (!jumpPressed) { - jumpIsHeld.current = false - driftDirection.current = 0 - driftForce.current = 0 - driftLeft.current = false - driftRight.current = false + jumpIsHeld.current = false; + driftDirection.current = 0; + driftForce.current = 0; + driftLeft.current = false; + driftRight.current = false; } // DRIFTING - if (jumpIsHeld.current && currentSteeringSpeed > 0 && pointer.x < -0.1 && !driftRight.current) { - driftLeft.current = true + 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 ( + jumpIsHeld.current && + currentSteeringSpeed > 0 && + pointer.x > 0.1 && + !driftLeft.current + ) { + driftRight.current = true; } if (!jumpIsHeld.current && !driftLeft.current && !driftRight.current) { - mario.current.rotation.y = THREE.MathUtils.lerp(mario.current.rotation.y, 0, 0.0001 * delta * 144) - setTurboColor(0xffffff) - accumulatedDriftPower.current = 0 + mario.current.rotation.y = THREE.MathUtils.lerp( + mario.current.rotation.y, + 0, + 0.0001 * delta * 144 + ); + setTurboColor(0xffffff); + accumulatedDriftPower.current = 0; } if (driftLeft.current) { - driftDirection.current = 1 - driftForce.current = 0.4 - mario.current.rotation.y = THREE.MathUtils.lerp(mario.current.rotation.y, steeringAngle * 50 + 0.5, 0.05 * delta * 144) - accumulatedDriftPower.current += 0.1 * (steeringAngle + 1) * delta * 144 + driftDirection.current = 1; + driftForce.current = 0.4; + mario.current.rotation.y = THREE.MathUtils.lerp( + mario.current.rotation.y, + steeringAngle * 50 + 0.5, + 0.05 * delta * 144 + ); + accumulatedDriftPower.current += 0.1 * (steeringAngle + 1) * delta * 144; } if (driftRight.current) { - driftDirection.current = -1 - driftForce.current = 0.4 - mario.current.rotation.y = THREE.MathUtils.lerp(mario.current.rotation.y, -(-steeringAngle * 50 + 0.5), 0.05 * delta * 144) - accumulatedDriftPower.current += 0.1 * (-steeringAngle + 1) * delta * 144 + driftDirection.current = -1; + driftForce.current = 0.4; + mario.current.rotation.y = THREE.MathUtils.lerp( + mario.current.rotation.y, + -(-steeringAngle * 50 + 0.5), + 0.05 * delta * 144 + ); + accumulatedDriftPower.current += 0.1 * (-steeringAngle + 1) * delta * 144; } if (!driftLeft.current && !driftRight.current) { - mario.current.rotation.y = THREE.MathUtils.lerp(mario.current.rotation.y, steeringAngle * 30, 0.05 * delta * 144) - setScale(0) + mario.current.rotation.y = THREE.MathUtils.lerp( + mario.current.rotation.y, + steeringAngle * 30, + 0.05 * delta * 144 + ); + setScale(0); } if (accumulatedDriftPower.current > blueTurboThreshold) { - setTurboColor(0x00ffff) - boostDuration.current = 50 + setTurboColor(0x00ffff); + boostDuration.current = 50; } if (accumulatedDriftPower.current > orangeTurboThreshold) { - setTurboColor(0xffcf00) - boostDuration.current = 100 + setTurboColor(0xffcf00); + boostDuration.current = 100; } if (accumulatedDriftPower.current > purpleTurboThreshold) { - setTurboColor(0xff00ff) - boostDuration.current = 250 + setTurboColor(0xff00ff); + boostDuration.current = 250; } if (driftLeft.current || driftRight.current) { - const oscillation = Math.sin(time * 1000) * 0.1 - const vibration = oscillation+ 0.9 + const oscillation = Math.sin(time * 1000) * 0.1; + const vibration = oscillation + 0.9; if (turboColor === 0xffffff) { - setScale(vibration * 0.8) + setScale(vibration * 0.8); } else { - setScale(vibration) + setScale(vibration); } } // RELEASING DRIFT if (boostDuration.current > 1 && !jumpIsHeld.current) { - setIsBoosting(true) + setIsBoosting(true); } else if (boostDuration.current <= 1) { - targetZPosition = 8 - setIsBoosting(false) + targetZPosition = 8; + setIsBoosting(false); } - if(isBoosting && boostDuration.current > 1){ - setCurrentSpeed(boostSpeed) - boostDuration.current -= 1 * delta * 144 - targetZPosition = 10 + if (isBoosting && boostDuration.current > 1) { + setCurrentSpeed(boostSpeed); + boostDuration.current -= 1 * delta * 144; + targetZPosition = 10; } else if (boostDuration.current <= 1) { - setIsBoosting(false) - targetZPosition = 8 + setIsBoosting(false); + targetZPosition = 8; } - // CAMERA WORK - cam.current.updateMatrixWorld() + cam.current.updateMatrixWorld(); - cam.current.position.x = THREE.MathUtils.lerp(cam.current.position.x, targetXPosition, 0.01 * delta * 144) + cam.current.position.x = THREE.MathUtils.lerp( + cam.current.position.x, + targetXPosition, + 0.01 * delta * 144 + ); - cam.current.position.z = THREE.MathUtils.lerp(cam.current.position.z, targetZPosition, 0.01 * delta * 144) + cam.current.position.z = THREE.MathUtils.lerp( + cam.current.position.z, + targetZPosition, + 0.01 * delta * 144 + ); body.current.applyImpulse( { x: forwardDirection.x * currentSpeed * delta * 144, y: 0 + jumpForce.current * delta * 144, - z: forwardDirection.z * currentSpeed * delta * 144 + z: forwardDirection.z * currentSpeed * delta * 144, }, true - ) + ); // Update the kart's rotation based on the steering angle - setSteeringAngleWheels(steeringAngle * 25) + setSteeringAngleWheels(steeringAngle * 25); // SOUND WORK // console.lowg(body.current.translation()) - }) + }); return ( @@ -264,38 +338,30 @@ export const PlayerController = () => { args={[0.5]} mass={3} onCollisionEnter={(event) => { - isOnFloor.current = true + isOnFloor.current = true; }} // onCollisionExit={(event) => { // isOnFloor.current = false // }} - /> - - + - + /> */} - - + + { opacity={0.4} /> - - - + /> */} + + { opacity={0.4} /> + + + + {/* */} - - + + @@ -365,5 +430,5 @@ export const PlayerController = () => { {/* */} - ) -} + ); +}; diff --git a/src/components/Skid.jsx b/src/components/Skid.jsx index c2f6d7b..06bb461 100644 --- a/src/components/Skid.jsx +++ b/src/components/Skid.jsx @@ -1,25 +1,22 @@ -import { Euler, Object3D, Vector3, Matrix4 } from 'three'; -import { useRef, useLayoutEffect } from 'react'; -import { useFrame } from '@react-three/fiber'; +import { Euler, Object3D, BackSide, Vector3 } from "three"; +import { useRef, useLayoutEffect } from "react"; +import { useFrame } from "@react-three/fiber"; +import { useStore } from "./store"; -import { getState, mutation, useStore } from '../store'; - -const e = new Euler(); -const m = new Matrix4(); const o = new Object3D(); -const v = new Vector3(); -export function Skid({ count = 500, opacity = 0.5, size = 0.4 }) { +export function Skid({ count = 500, opacity = 1, size = 0.4 }) { const ref = useRef(null); - const [chassisBody, wheels] = useStore((state) => [state.chassisBody, state.wheels]); + const [bodyPosition, bodyRotation] = useStore((state) => [ + state.bodyPosition, + state.bodyRotation, + ]); - let brake; let index = 0; useFrame(() => { - brake = getState().controls.brake; - if (chassisBody.current && wheels[2].current && wheels[3].current && brake && mutation.speed > 10) { - e.setFromRotationMatrix(m.extractRotation(chassisBody.current.matrix)); - setItemAt(ref.current, e, wheels[2].current, index++); + // console.log(bodyPosition, bodyRotation); + if (ref.current && bodyPosition && bodyRotation !== undefined) { + setItemAt(ref.current, bodyPosition, bodyRotation, index++); if (index === count) index = 0; } }); @@ -36,14 +33,34 @@ export function Skid({ count = 500, opacity = 0.5, size = 0.4 }) { return ( - + ); } -function setItemAt(instances, rotation, wheel, index) { - o.position.copy(wheel.getWorldPosition(v)); - o.rotation.copy(rotation); +function setItemAt(instances, bodyPosition, bodyRotation, index) { + // Calculate the backward offset + const backwardOffset = 0.5; // Adjust this value as needed + const forwardDirection = new Vector3( + -Math.sin(bodyRotation), + 0, + -Math.cos(bodyRotation) + ); + const backwardPosition = forwardDirection + .multiplyScalar(-backwardOffset) + .add(bodyPosition); + + // Apply the offset to position the skid marks behind the body + console.log(bodyPosition); + o.position.copy(bodyPosition.x, bodyPosition.y + 2, bodyPosition.z); + + o.rotation.set(0, bodyRotation, 0); o.scale.setScalar(1); o.updateMatrix(); instances.setMatrixAt(index, o.matrix); diff --git a/src/components/models/Mario_kart.jsx b/src/components/models/Mario_kart.jsx index b7489b2..7e8460c 100644 --- a/src/components/models/Mario_kart.jsx +++ b/src/components/models/Mario_kart.jsx @@ -26,9 +26,9 @@ export function Mario({ currentSpeed, steeringAngleWheels, isBoosting, ...props rearWheels.current.rotation.x += rotation frontWheels.current.rotation.y = steeringAngleWheels if (isBoosting){ - setScale(Math.min(scale + 0.1 * 144 * delta, 1)) + setScale(Math.min(scale + 0.05 * 144 * delta, 1)) } else { - setScale(Math.max(scale - 0.1 * 144 * delta, 0)) + setScale(Math.max(scale - 0.03 * 144 * delta, 0)) } }) return ( diff --git a/src/components/store.jsx b/src/components/store.jsx index c6f089e..da4455a 100644 --- a/src/components/store.jsx +++ b/src/components/store.jsx @@ -1,35 +1,48 @@ import { create } from "zustand"; export const useStore = create((set, get) => ({ - return : { - particles1: [], - particles2: [], - bodyPosition: [0, 0, 0], - bodyRotation: [0, 0, 0], - actions : { - addParticle1: (particle) => { - set((state) => ({ - particles1: [...state.particles1, particle], - })); - }, - removeParticle1: (particle) => { - set((state) => ({ - particles1: state.particles1.filter((p) => p.id !== particle.id), - })); - }, - addParticle2: (particle) => { - set((state) => ({ - particles2: [...state.particles2, particle], - })); - }, - removeParticle2: (particle) => { - set((state) => ({ - particles2: state.particles2.filter((p) => p.id !== particle.id), - })); - }, + particles1: [], + particles2: [], + bodyPosition: [0, 0, 0], + bodyRotation: [0, 0, 0], + pastPositions: [], + addPastPosition: (position) => { + set((state) => ({ + pastPositions: [position, ...state.pastPositions.slice(0, 499)], + })); + }, + actions: { + addParticle1: (particle) => { + set((state) => ({ + particles1: [...state.particles1, particle], + })); }, - - - - } -})); \ No newline at end of file + removeParticle1: (particle) => { + set((state) => ({ + particles1: state.particles1.filter((p) => p.id !== particle.id), + })); + }, + addParticle2: (particle) => { + set((state) => ({ + particles2: [...state.particles2, particle], + })); + }, + removeParticle2: (particle) => { + set((state) => ({ + particles2: state.particles2.filter((p) => p.id !== particle.id), + })); + }, + setBodyPosition: (position) => { + set({ bodyPosition: position }); + }, + setBodyRotation: (rotation) => { + set({ bodyRotation: rotation }); + }, + getBodyPosition: () => { + return get().bodyPosition; + }, + getBodyRotation: () => { + return get().bodyRotation; + }, + }, +}));