commit
bfccc00f4d
|
@ -43,7 +43,7 @@ function App() {
|
|||
<KeyboardControls map={map}>
|
||||
<Experience />
|
||||
</KeyboardControls>
|
||||
{/* <Stats /> */}
|
||||
<Stats />
|
||||
</Physics>
|
||||
</Suspense>
|
||||
</Canvas>
|
||||
|
|
|
@ -3,23 +3,23 @@ import { Particles3 } from "./Particles3";
|
|||
|
||||
export const DriftParticlesLeft = ({turboColor,scale, ...props}) => {
|
||||
|
||||
if(scale < 0.8) {
|
||||
return null;
|
||||
}
|
||||
// if(scale < 0.8) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
return (
|
||||
<group {...props}>
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
{/* <Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} /> */}
|
||||
|
||||
<Particles3 turboColor={turboColor} scale={scale} />
|
||||
{/* <Particles3 turboColor={turboColor} scale={scale} /> */}
|
||||
|
||||
</group>
|
||||
)
|
||||
|
|
|
@ -3,24 +3,13 @@ import { Particles4 } from "./Particles4";
|
|||
|
||||
export const DriftParticlesRight = ({turboColor,scale, ...props}) => {
|
||||
|
||||
if(scale < 0.8) {
|
||||
return null;
|
||||
}
|
||||
// if(scale < 0.8) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
return (
|
||||
<group {...props}>
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
|
||||
<Particles4 turboColor={turboColor} scale={scale} />
|
||||
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
|
||||
</group>
|
||||
)
|
||||
|
|
|
@ -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 (
|
||||
<>
|
||||
<PlayerController />
|
||||
<Skid />
|
||||
{/* <PlayerControllerAgain /> */}
|
||||
<Ground position={[0, 0, 0]} />
|
||||
<Environment
|
||||
|
|
|
@ -1,22 +1,21 @@
|
|||
import React, { useState, useEffect, useRef } from "react";
|
||||
import React, { useRef, useMemo } from "react";
|
||||
import { useLoader, useFrame } from "@react-three/fiber";
|
||||
import * as THREE from "three";
|
||||
|
||||
export const FlameParticle = ({ position, png, turboColor, delay = 0 }) => {
|
||||
export const FlameParticle = ({ position, png, isBoosting, delay = 0 }) => {
|
||||
const texture = useLoader(THREE.TextureLoader, png);
|
||||
const pointsRef = useRef();
|
||||
const [size, setSize] = useState(1);
|
||||
const [opacity, setOpacity] = useState(1);
|
||||
const [initialized, setInitialized] = useState(false);
|
||||
const initialized = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
// Initialize after delay
|
||||
useMemo(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setInitialized(true);
|
||||
initialized.current = true;
|
||||
}, delay);
|
||||
return () => clearTimeout(timer);
|
||||
}, [delay]);
|
||||
|
||||
const points = React.useMemo(() => {
|
||||
const points = useMemo(() => {
|
||||
const geom = new THREE.BufferGeometry();
|
||||
geom.setAttribute(
|
||||
"position",
|
||||
|
@ -26,29 +25,41 @@ export const FlameParticle = ({ position, png, turboColor, delay = 0 }) => {
|
|||
}, [position]);
|
||||
|
||||
useFrame(({clock}, delta) => {
|
||||
if (!initialized) return;
|
||||
if (!initialized.current) return;
|
||||
|
||||
pointsRef.current.position.y += 0.03 * delta * 144;
|
||||
pointsRef.current.position.z += 0.06 * delta * 144;
|
||||
if(pointsRef.current.position.y > 0.4) {
|
||||
pointsRef.current.position.y = 0;
|
||||
pointsRef.current.position.z = 0;
|
||||
setOpacity(1);
|
||||
}
|
||||
if(opacity > 0) {
|
||||
setOpacity((opacity) => opacity - 0.05 * delta * 144);
|
||||
const pointsCurrent = pointsRef.current;
|
||||
|
||||
if (isBoosting) {
|
||||
// Update logic when boosting
|
||||
pointsCurrent.position.y += 0.03 * delta * 144;
|
||||
pointsCurrent.position.z += 0.06 * delta * 144;
|
||||
|
||||
if(pointsCurrent.position.y > 0.4) {
|
||||
pointsCurrent.position.y = 0;
|
||||
pointsCurrent.position.z = 0;
|
||||
pointsCurrent.material.opacity = 1;
|
||||
}
|
||||
|
||||
if(pointsCurrent.material.opacity > 0) {
|
||||
pointsCurrent.material.opacity -= 0.05 * delta * 144;
|
||||
}
|
||||
} else {
|
||||
// Reset position and opacity when not boosting
|
||||
pointsCurrent.position.y = 0;
|
||||
pointsCurrent.position.z = 0;
|
||||
pointsCurrent.material.opacity = 0;
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<points ref={pointsRef} geometry={points}>
|
||||
<pointsMaterial
|
||||
size={size}
|
||||
size={1}
|
||||
alphaMap={texture}
|
||||
transparent={true}
|
||||
depthWrite={false}
|
||||
color={turboColor}
|
||||
opacity={opacity}
|
||||
color={0x000000}
|
||||
opacity={1}
|
||||
toneMapped={false}
|
||||
/>
|
||||
</points>
|
||||
|
|
|
@ -2,9 +2,7 @@ import { FlameParticle } from "./FlameParticle";
|
|||
|
||||
export const FlameParticles = ({ isBoosting }) => {
|
||||
|
||||
if (!isBoosting) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<group>
|
||||
{/* bottom left */}
|
||||
|
@ -12,37 +10,37 @@ export const FlameParticles = ({ isBoosting }) => {
|
|||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_01.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={0}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_02.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={100}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_01.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={200}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_02.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={300}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_02.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={400}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_01.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={500}
|
||||
/>
|
||||
</group>
|
||||
|
@ -52,37 +50,37 @@ export const FlameParticles = ({ isBoosting }) => {
|
|||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_01.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={0}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_02.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={100}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_01.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={200}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_02.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={300}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_01.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={400}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_02.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={500}
|
||||
/>
|
||||
</group>
|
||||
|
@ -91,37 +89,37 @@ export const FlameParticles = ({ isBoosting }) => {
|
|||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_02.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={0}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_01.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={100}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_02.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={200}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_01.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={300}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_02.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={400}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_01.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={500}
|
||||
/>
|
||||
</group>
|
||||
|
@ -129,37 +127,37 @@ export const FlameParticles = ({ isBoosting }) => {
|
|||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_02.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={0}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_01.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={100}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_02.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={200}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_01.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={300}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_02.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={400}
|
||||
/>
|
||||
<FlameParticle
|
||||
position={[0, 0, 0]}
|
||||
png="./fire_01.png"
|
||||
turboColor={0xfea347}
|
||||
isBoosting={isBoosting}
|
||||
delay={500}
|
||||
/>
|
||||
</group>
|
||||
|
|
|
@ -1,55 +1,57 @@
|
|||
import { useRef } from "react";
|
||||
import { useRef, useMemo } from "react";
|
||||
import { useFrame } from "@react-three/fiber";
|
||||
import * as THREE from 'three';
|
||||
|
||||
export const Particles1 = ({ turboColor, scale, ...props }) => {
|
||||
const ref = useRef();
|
||||
const velocity = useRef({
|
||||
x: -Math.random() * 0.05,
|
||||
y: Math.random() * 0.05,
|
||||
z: Math.random() * 0.02,
|
||||
});
|
||||
const gravity = -0.003;
|
||||
export const Particles1 = ({ turboColor, scale, numParticles = 50, ...props }) => {
|
||||
const instancedMeshRef = useRef();
|
||||
const particlesData = useMemo(() => {
|
||||
return new Array(numParticles).fill().map(() => ({
|
||||
position: new THREE.Vector3(-0.6, 0.05, 0.5),
|
||||
velocity: new THREE.Vector3(-Math.random() * 0.05, Math.random() * 0.05, Math.random() * 0.02),
|
||||
gravity: -0.003
|
||||
}));
|
||||
}, [numParticles]);
|
||||
|
||||
useFrame((state, delta) => {
|
||||
let position = ref.current.position;
|
||||
let velocityVector = new THREE.Vector3(velocity.current.x, velocity.current.y, velocity.current.z);
|
||||
|
||||
// Adjust gravity and velocity based on delta
|
||||
velocity.current.y += gravity * delta * 144; // Multiply by 144 to scale for 144 FPS
|
||||
|
||||
// Scale velocity changes by delta
|
||||
position.x += velocity.current.x * delta * 144;
|
||||
position.y += velocity.current.y * delta * 144;
|
||||
position.z += velocity.current.z * delta * 144;
|
||||
|
||||
if (!velocityVector.equals(new THREE.Vector3(0, 0, 0))) {
|
||||
const alignmentQuaternion = new THREE.Quaternion();
|
||||
alignmentQuaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), velocityVector.normalize());
|
||||
ref.current.quaternion.slerp(alignmentQuaternion, 0.1);
|
||||
if (!instancedMeshRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (position.y < 0.05) {
|
||||
position.set(-0.6, 0.05, 0.5);
|
||||
velocity.current = {
|
||||
x: -Math.random() * 0.05,
|
||||
y: Math.random() * 0.05,
|
||||
z: Math.random() * 0.02,
|
||||
};
|
||||
// Manage visibility directly in the animation loop
|
||||
instancedMeshRef.current.visible = scale >= 0.8;
|
||||
|
||||
if (scale < 0.8) {
|
||||
return;
|
||||
}
|
||||
|
||||
ref.current.position.set(position.x, position.y, position.z);
|
||||
const deltaScaled = delta * 144; // Scale for 144 FPS
|
||||
particlesData.forEach((particle, i) => {
|
||||
particle.velocity.y += particle.gravity * deltaScaled;
|
||||
|
||||
particle.position.x += particle.velocity.x * deltaScaled;
|
||||
particle.position.y += particle.velocity.y * deltaScaled;
|
||||
particle.position.z += particle.velocity.z * deltaScaled;
|
||||
|
||||
if (particle.position.y < 0.05) {
|
||||
particle.position.set(-0.6, 0.05, 0.5);
|
||||
particle.velocity.set(-Math.random() * 0.05, Math.random() * 0.05, Math.random() * 0.02);
|
||||
}
|
||||
const matrix = new THREE.Matrix4();
|
||||
matrix.setPosition(particle.position);
|
||||
instancedMeshRef.current.setMatrixAt(i, matrix);
|
||||
});
|
||||
|
||||
instancedMeshRef.current.instanceMatrix.needsUpdate = true;
|
||||
});
|
||||
|
||||
|
||||
return (
|
||||
<mesh ref={ref} position={[-0.6, 0.05, 0.5]} scale={[scale, scale * 5, scale]}>
|
||||
<instancedMesh ref={instancedMeshRef} args={[null, null, numParticles]} visible={scale >= 0.8}>
|
||||
<sphereGeometry args={[0.01, 16, 16]} />
|
||||
<meshStandardMaterial
|
||||
emissive={turboColor}
|
||||
toneMapped={false}
|
||||
emissiveIntensity={5}
|
||||
/>
|
||||
</mesh>
|
||||
</instancedMesh>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,55 +1,57 @@
|
|||
import { useRef } from "react";
|
||||
import { useRef, useMemo } from "react";
|
||||
import { useFrame } from "@react-three/fiber";
|
||||
import * as THREE from 'three';
|
||||
|
||||
export const Particles2 = ({ turboColor, scale, ...props }) => {
|
||||
const ref = useRef();
|
||||
const velocity = useRef({
|
||||
x: Math.random() * 0.05,
|
||||
y: Math.random() * 0.05,
|
||||
z: Math.random() * 0.02,
|
||||
});
|
||||
const gravity = -0.003;
|
||||
export const Particles2 = ({ turboColor, scale, numParticles = 50, ...props }) => {
|
||||
const instancedMeshRef = useRef();
|
||||
const particlesData = useMemo(() => {
|
||||
return new Array(numParticles).fill().map(() => ({
|
||||
position: new THREE.Vector3(0.6, 0.05, 0.5),
|
||||
velocity: new THREE.Vector3(Math.random() * 0.05, Math.random() * 0.05, Math.random() * 0.02),
|
||||
gravity: -0.003
|
||||
}));
|
||||
}, [numParticles]);
|
||||
|
||||
useFrame((state, delta) => {
|
||||
let position = ref.current.position;
|
||||
let velocityVector = new THREE.Vector3(velocity.current.x, velocity.current.y, velocity.current.z);
|
||||
|
||||
// Adjust gravity and velocity based on delta
|
||||
velocity.current.y += gravity * delta * 144; // Multiply by 144 to scale for 144 FPS
|
||||
|
||||
// Scale velocity changes by delta
|
||||
position.x += velocity.current.x * delta * 144;
|
||||
position.y += velocity.current.y * delta * 144;
|
||||
position.z += velocity.current.z * delta * 144;
|
||||
|
||||
if (!velocityVector.equals(new THREE.Vector3(0, 0, 0))) {
|
||||
const alignmentQuaternion = new THREE.Quaternion();
|
||||
alignmentQuaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), velocityVector.normalize());
|
||||
ref.current.quaternion.slerp(alignmentQuaternion, 0.1);
|
||||
if (!instancedMeshRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (position.y < 0.05) {
|
||||
position.set(0.6, 0.05, 0.5);
|
||||
velocity.current = {
|
||||
x: Math.random() * 0.05,
|
||||
y: Math.random() * 0.05,
|
||||
z: Math.random() * 0.02,
|
||||
};
|
||||
// Manage visibility directly in the animation loop
|
||||
instancedMeshRef.current.visible = scale >= 0.8;
|
||||
|
||||
if (scale < 0.8) {
|
||||
return;
|
||||
}
|
||||
|
||||
ref.current.position.set(position.x, position.y, position.z);
|
||||
const deltaScaled = delta * 144; // Scale for 144 FPS
|
||||
particlesData.forEach((particle, i) => {
|
||||
particle.velocity.y += particle.gravity * deltaScaled;
|
||||
|
||||
particle.position.x += particle.velocity.x * deltaScaled;
|
||||
particle.position.y += particle.velocity.y * deltaScaled;
|
||||
particle.position.z += particle.velocity.z * deltaScaled;
|
||||
|
||||
if (particle.position.y < 0.05) {
|
||||
particle.position.set(0.6, 0.05, 0.5);
|
||||
particle.velocity.set(Math.random() * 0.05, Math.random() * 0.05, Math.random() * 0.02);
|
||||
}
|
||||
const matrix = new THREE.Matrix4();
|
||||
matrix.setPosition(particle.position);
|
||||
instancedMeshRef.current.setMatrixAt(i, matrix);
|
||||
});
|
||||
|
||||
instancedMeshRef.current.instanceMatrix.needsUpdate = true;
|
||||
});
|
||||
|
||||
|
||||
return (
|
||||
<mesh ref={ref} position={[0.6, 0.05, 0.5]} scale={[scale, scale * 5, scale]}>
|
||||
<instancedMesh ref={instancedMeshRef} args={[null, null, numParticles]} visible={scale >= 0.8}>
|
||||
<sphereGeometry args={[0.01, 16, 16]} />
|
||||
<meshStandardMaterial
|
||||
emissive={turboColor}
|
||||
toneMapped={false}
|
||||
emissiveIntensity={5}
|
||||
/>
|
||||
</mesh>
|
||||
</instancedMesh>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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 (
|
||||
<group>
|
||||
|
@ -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
|
||||
// }}
|
||||
|
||||
/>
|
||||
|
||||
</RigidBody>
|
||||
|
||||
<group
|
||||
ref={kart}
|
||||
rotation={[0, Math.PI / 2, 0]}
|
||||
>
|
||||
<group ref={kart} rotation={[0, Math.PI / 2, 0]}>
|
||||
<group ref={mario}>
|
||||
<Mario
|
||||
currentSpeed={currentSpeed}
|
||||
steeringAngleWheels={steeringAngleWheels}
|
||||
isBoosting={isBoosting}
|
||||
/>
|
||||
<pointLight
|
||||
{/* <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.1, 16, 16]} />
|
||||
<mesh position={[0.6, 0.05, 0.5]} scale={scale}>
|
||||
<sphereGeometry args={[0.05, 16, 16]} />
|
||||
<meshStandardMaterial
|
||||
emissive={turboColor}
|
||||
toneMapped={false}
|
||||
|
@ -304,17 +370,14 @@ export const PlayerController = () => {
|
|||
opacity={0.4}
|
||||
/>
|
||||
</mesh>
|
||||
<pointLight
|
||||
{/* <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.1, 16, 16]} />
|
||||
/> */}
|
||||
<mesh position={[-0.6, 0.05, 0.5]} scale={scale}>
|
||||
<sphereGeometry args={[0.05, 16, 16]} />
|
||||
<meshStandardMaterial
|
||||
emissive={turboColor}
|
||||
toneMapped={false}
|
||||
|
@ -323,34 +386,36 @@ 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}
|
||||
/>
|
||||
<DriftParticlesLeft turboColor={turboColor} scale={scale} />
|
||||
<DriftParticlesRight turboColor={turboColor} scale={scale} />
|
||||
<PointParticle
|
||||
position={[-0.6, 0.05, 0.5]}
|
||||
png='./circle.png'
|
||||
png="./circle.png"
|
||||
turboColor={turboColor}
|
||||
/>
|
||||
<PointParticle
|
||||
position={[0.6, 0.05, 0.5]}
|
||||
png='./circle.png'
|
||||
png="./circle.png"
|
||||
turboColor={turboColor}
|
||||
/>
|
||||
<PointParticle
|
||||
position={[-0.6, 0.05, 0.5]}
|
||||
png='./star.png'
|
||||
png="./star.png"
|
||||
turboColor={turboColor}
|
||||
/>
|
||||
<PointParticle
|
||||
position={[0.6, 0.05, 0.5]}
|
||||
png='./star.png'
|
||||
png="./star.png"
|
||||
turboColor={turboColor}
|
||||
/>
|
||||
</group>
|
||||
|
@ -365,5 +430,5 @@ export const PlayerController = () => {
|
|||
{/* <PositionalAudio ref={engineSound} url="./sounds/engine.wav" autoplay loop distance={10}/> */}
|
||||
</group>
|
||||
</group>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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 (
|
||||
<instancedMesh ref={ref} args={[undefined, undefined, count]}>
|
||||
<planeGeometry args={[size, size * 2]} />
|
||||
<meshBasicMaterial color={0x4d4d4d} transparent opacity={opacity} depthWrite={false} />
|
||||
<meshBasicMaterial
|
||||
color={0x000000}
|
||||
transparent
|
||||
opacity={opacity}
|
||||
depthWrite={false}
|
||||
side={BackSide}
|
||||
/>
|
||||
</instancedMesh>
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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],
|
||||
}));
|
||||
},
|
||||
|
||||
|
||||
|
||||
}
|
||||
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;
|
||||
},
|
||||
},
|
||||
}));
|
Loading…
Reference in New Issue