added item system
This commit is contained in:
1 parent
11be02d977
commit
77a14c7733
26 files changed
+676
-35
No files matched your search
Generated
+1
@@ -18,6 +18,7 @@
|
||||
"react-dom": "^18.2.0",
|
||||
"react-gamepad": "^1.0.3",
|
||||
"three": "^0.160.1",
|
||||
"three-mesh-bvh": "^0.7.0",
|
||||
"zustand": "^4.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"react-dom": "^18.2.0",
|
||||
"react-gamepad": "^1.0.3",
|
||||
"three": "^0.160.1",
|
||||
"three-mesh-bvh": "^0.7.0",
|
||||
"zustand": "^4.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Binary file not shown.
|
After Width: | Height: | Size: 7.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 9.9 KiB |
@@ -39,6 +39,7 @@ function App() {
|
||||
<Physics
|
||||
gravity={[0, -90, 0]}
|
||||
timeStep={'vary'}
|
||||
// debug
|
||||
>
|
||||
<KeyboardControls map={map}>
|
||||
<Experience />
|
||||
|
||||
@@ -1,21 +1,62 @@
|
||||
import { Environment, OrbitControls, PerspectiveCamera, Lightformer } from '@react-three/drei'
|
||||
import { Ground } from './Ground'
|
||||
import { PlayerController } from './PlayerController'
|
||||
import { Paris } from './models/tracks/Tour_paris_promenade'
|
||||
import { EffectComposer, N8AO, Bloom, TiltShift2, HueSaturation, SMAA, ChromaticAberration, Vignette } from '@react-three/postprocessing'
|
||||
import { Skid } from './Skid'
|
||||
import {
|
||||
Environment,
|
||||
OrbitControls,
|
||||
PerspectiveCamera,
|
||||
Lightformer,
|
||||
Bvh,
|
||||
} from "@react-three/drei";
|
||||
import { Ground } from "./Ground";
|
||||
import { PlayerController } from "./PlayerController";
|
||||
import { Paris } from "./models/tracks/Tour_paris_promenade";
|
||||
import {
|
||||
EffectComposer,
|
||||
N8AO,
|
||||
Bloom,
|
||||
TiltShift2,
|
||||
HueSaturation,
|
||||
SMAA,
|
||||
ChromaticAberration,
|
||||
Vignette,
|
||||
} from "@react-three/postprocessing";
|
||||
import { Skid } from "./Skid";
|
||||
import { Banana } from "./models/items/Banana_peel_mario_kart";
|
||||
import { ItemBox } from "./models/misc/Mario_kart_item_box";
|
||||
import { useStore } from "./store";
|
||||
import { Shell } from "./models/items/Mario_shell_red";
|
||||
|
||||
export const Experience = () => {
|
||||
const onCollide = (event) => {
|
||||
console.log(event);
|
||||
};
|
||||
const { bananas, shells } = useStore();
|
||||
|
||||
return (
|
||||
<>
|
||||
<PlayerController />
|
||||
<Paris position={[0, 0, 0]} />
|
||||
<Banana onCollide={onCollide} position={[-10, 1.8, -119]} />
|
||||
{/* <Shell position={[-20, 2, -119]} /> */}
|
||||
<ItemBox position={[-20, 2, -119]} />
|
||||
{/* <Skid /> */}
|
||||
<Ground position={[0, 0, 0]} />
|
||||
<Environment
|
||||
resolution={256}
|
||||
preset='lobby'
|
||||
<Environment resolution={256} preset="lobby" />
|
||||
|
||||
/>
|
||||
{bananas.map((banana) => (
|
||||
<Banana
|
||||
key={banana.id}
|
||||
position={banana.position}
|
||||
|
||||
// rotation={banana.rotation}
|
||||
/>
|
||||
))}
|
||||
|
||||
{shells.map((shell) => (
|
||||
<Shell
|
||||
key={shell.id}
|
||||
position={shell.position}
|
||||
rotation={shell.rotation}
|
||||
/>
|
||||
))}
|
||||
|
||||
<directionalLight
|
||||
position={[10, 50, -30]}
|
||||
@@ -25,17 +66,15 @@ export const Experience = () => {
|
||||
shadow-camera-left={-300}
|
||||
shadow-camera-right={300}
|
||||
shadow-camera-top={300}
|
||||
shadow-camera-bottom={-3000}
|
||||
shadow-camera-bottom={-300}
|
||||
castShadow
|
||||
/>
|
||||
|
||||
<Paris position={[0, 0, 0]} />
|
||||
<EffectComposer
|
||||
multisampling={0}
|
||||
disableNormalPass
|
||||
disableSSAO
|
||||
disableDepthPass
|
||||
|
||||
>
|
||||
<SMAA />
|
||||
<N8AO distanceFalloff={1} aoRadius={1} intensity={3} />
|
||||
@@ -46,11 +85,11 @@ export const Experience = () => {
|
||||
intensity={0.5}
|
||||
/>
|
||||
|
||||
<TiltShift2/>
|
||||
<TiltShift2 />
|
||||
<ChromaticAberration offset={[0.0006, 0.0006]} />
|
||||
<HueSaturation saturation={0.1} />
|
||||
<Vignette eskil={false} offset={0.1} darkness={0.4} />
|
||||
</EffectComposer>
|
||||
</>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,139 @@
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { Canvas, useLoader, useFrame, extend } from "@react-three/fiber";
|
||||
import * as THREE from "three";
|
||||
import { shaderMaterial } from "@react-three/drei";
|
||||
|
||||
export const HitParticle = ({ position, shouldLaunch }) => {
|
||||
const texture = useLoader(THREE.TextureLoader, "./particles/star_symbol.png");
|
||||
const pointsRef = useRef();
|
||||
const materialRef = useRef();
|
||||
const [size, setSize] = useState(3);
|
||||
const frames = useRef(50);
|
||||
|
||||
const gravity = -0.03;
|
||||
const velocity = useRef({
|
||||
x: (Math.random() - 0.5) * 33,
|
||||
y: (Math.random() + 0.3) * 4,
|
||||
});
|
||||
const points = React.useMemo(() => {
|
||||
const geom = new THREE.BufferGeometry();
|
||||
geom.setAttribute(
|
||||
"position",
|
||||
new THREE.Float32BufferAttribute(position, 3)
|
||||
);
|
||||
return geom;
|
||||
}, [position]);
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldLaunch) {
|
||||
if (pointsRef.current) {
|
||||
// Reset position
|
||||
pointsRef.current.position.set(0, 0, 0);
|
||||
|
||||
// Reset velocity
|
||||
velocity.current = {
|
||||
x: (Math.random() - 0.5) * 33,
|
||||
y: (Math.random() + 0.3) * 4,
|
||||
};
|
||||
|
||||
// Reset opacity if needed
|
||||
if (materialRef.current) {
|
||||
materialRef.current.opacity = 1;
|
||||
materialRef.current.size = 3;
|
||||
}
|
||||
|
||||
frames.current = 50;
|
||||
}
|
||||
}
|
||||
}, [shouldLaunch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (materialRef.current) {
|
||||
materialRef.current.color.multiplyScalar(15);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useFrame((_state, delta) => {
|
||||
if (pointsRef.current) {
|
||||
let position = pointsRef.current.position;
|
||||
|
||||
// Normalized time value for ease-out effect
|
||||
let t = 1 - Math.max(frames.current / 150, 0); // Ensure t is between 0 and 1
|
||||
let easeOutCubic = 1 - Math.pow(1 - t, 3);
|
||||
|
||||
// Apply the velocity to the position
|
||||
position.x += velocity.current.x * delta * easeOutCubic;
|
||||
position.y += velocity.current.y * delta * easeOutCubic;
|
||||
|
||||
// Adjust gravity based on delta
|
||||
velocity.current.y += gravity * delta * 144;
|
||||
|
||||
// Decrease frames
|
||||
frames.current -= 1;
|
||||
|
||||
if (materialRef.current) {
|
||||
// materialRef.current.size = 3 + Math.sin(frames.current * 0.1) * 2;
|
||||
materialRef.current.opacity = Math.abs(Math.sin(frames.current * 0.1));
|
||||
}
|
||||
// Reset the particle position and velocity when it goes too far
|
||||
if (frames.current < 0) {
|
||||
// if(materialRef.current.opacity > 0) {
|
||||
// Math.max(materialRef.current.opacity -= 0.01 * delta * 144, 0);
|
||||
// }
|
||||
if (materialRef.current.size > 0) {
|
||||
Math.max((materialRef.current.size -= 0.1 * delta * 144), 0);
|
||||
}
|
||||
}
|
||||
pointsRef.current.position.set(position.x, position.y, position.z);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<points ref={pointsRef} geometry={points}>
|
||||
<pointsMaterial
|
||||
ref={materialRef}
|
||||
size={size}
|
||||
alphaMap={texture}
|
||||
transparent={true}
|
||||
depthWrite={false}
|
||||
color={0xfafad2}
|
||||
opacity={1}
|
||||
/>
|
||||
|
||||
</points>
|
||||
);
|
||||
};
|
||||
|
||||
export const PointsShaderMaterial = shaderMaterial(
|
||||
{
|
||||
time: 0,
|
||||
tex: undefined,
|
||||
color: new THREE.Color(0xfafad2),
|
||||
},
|
||||
// Vertex Shader
|
||||
`
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
vUv = uv;
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||
}
|
||||
`,
|
||||
// Fragment Shader
|
||||
`
|
||||
varying vec2 vUv;
|
||||
uniform sampler2D tex;
|
||||
uniform vec3 color;
|
||||
uniform float time; // Using the declared 'time' uniform
|
||||
|
||||
void main() {
|
||||
vec2 uv = vUv;
|
||||
vec4 texColor = texture2D(tex, uv);
|
||||
|
||||
gl_FragColor = vec4(color, 1.0) * texColor * vec4(1.0, 1.0, 1.0, 1.0);
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
extend({ PointsShaderMaterial });
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { Canvas, useLoader, useFrame } from "@react-three/fiber";
|
||||
import * as THREE from "three";
|
||||
import gsap from "gsap";
|
||||
|
||||
|
||||
export const HitParticleTwo = ({ position, shouldLaunch}) => {
|
||||
const texture = useLoader(THREE.TextureLoader, "./particles/star_symbol.png");
|
||||
const pointsRef = useRef();
|
||||
const materialRef = useRef();
|
||||
const [size, setSize] = useState(1);
|
||||
const frames = useRef(100);
|
||||
|
||||
const gravity = -0.03;
|
||||
const velocity = useRef({
|
||||
x: (Math.random() - 0.5) * 16,
|
||||
y: (Math.random() + 0.3) *4,
|
||||
});
|
||||
const points = React.useMemo(() => {
|
||||
const geom = new THREE.BufferGeometry();
|
||||
geom.setAttribute(
|
||||
"position",
|
||||
new THREE.Float32BufferAttribute(position, 3)
|
||||
);
|
||||
return geom;
|
||||
}, [position]);
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldLaunch) {
|
||||
if (pointsRef.current) {
|
||||
// Reset position
|
||||
pointsRef.current.position.set(0, 0, 0);
|
||||
|
||||
// Reset velocity
|
||||
velocity.current = {
|
||||
x: (Math.random() - 0.5) * 16,
|
||||
y: (Math.random() + 0.3) * 4,
|
||||
};
|
||||
|
||||
// Reset opacity if needed
|
||||
if (materialRef.current) {
|
||||
materialRef.current.opacity = 1;
|
||||
}
|
||||
frames.current = 100;
|
||||
}
|
||||
}
|
||||
|
||||
}, [shouldLaunch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (materialRef.current) {
|
||||
materialRef.current.color.multiplyScalar(15);
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<points ref={pointsRef} geometry={points}>
|
||||
<pointsMaterial
|
||||
ref={materialRef}
|
||||
size={size}
|
||||
alphaMap={texture}
|
||||
transparent={true}
|
||||
depthWrite={false}
|
||||
color={0xFAFAD2}
|
||||
opacity={1}
|
||||
// toneMapped={false}
|
||||
/>
|
||||
</points>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
import React from 'react'
|
||||
import { HitParticle } from './HitParticle'
|
||||
|
||||
export const HitParticles = ({ position, shouldLaunch }) => {
|
||||
return (
|
||||
<>
|
||||
<HitParticle position={[0,0,0]} shouldLaunch={shouldLaunch}/>
|
||||
<HitParticle position={[0,0,0]} shouldLaunch={shouldLaunch}/>
|
||||
<HitParticle position={[0,0,0]} shouldLaunch={shouldLaunch}/>
|
||||
<HitParticle position={[0,0,0]} shouldLaunch={shouldLaunch}/>
|
||||
<HitParticle position={[0,0,0]} shouldLaunch={shouldLaunch}/>
|
||||
<HitParticle position={[0,0,0]} shouldLaunch={shouldLaunch}/>
|
||||
<HitParticle position={[0,0,0]} shouldLaunch={shouldLaunch}/>
|
||||
<HitParticle position={[0,0,0]} shouldLaunch={shouldLaunch}/>
|
||||
<HitParticle position={[0,0,0]} shouldLaunch={shouldLaunch}/>
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import * as THREE from "three";
|
||||
export const PointParticle = ({ position, png, turboColor }) => {
|
||||
const texture = useLoader(THREE.TextureLoader, png);
|
||||
const pointsRef = useRef();
|
||||
const materialRef = useRef();
|
||||
const [size, setSize] = useState(0);
|
||||
const [opacity, setOpacity] = useState(1);
|
||||
|
||||
@@ -18,7 +19,9 @@ export const PointParticle = ({ position, png, turboColor }) => {
|
||||
}, [position]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
if (materialRef.current) {
|
||||
materialRef.current.color.multiplyScalar(10);
|
||||
}
|
||||
setSize(0);
|
||||
setOpacity(1);
|
||||
}, [turboColor]);
|
||||
@@ -36,6 +39,7 @@ export const PointParticle = ({ position, png, turboColor }) => {
|
||||
return (
|
||||
<points ref={pointsRef} geometry={points}>
|
||||
<pointsMaterial
|
||||
ref={materialRef}
|
||||
size={size}
|
||||
alphaMap={texture}
|
||||
transparent={true}
|
||||
|
||||
@@ -23,6 +23,7 @@ import { FlameParticles } from "./Particles/FlameParticles";
|
||||
import { useStore } from "./store";
|
||||
import { Cylinder } from "@react-three/drei";
|
||||
import FakeGlowMaterial from "./ShaderMaterials/FakeGlow/FakeGlowMaterial";
|
||||
import { HitParticles } from "./Particles/HitParticles";
|
||||
|
||||
export const PlayerController = () => {
|
||||
const upPressed = useKeyboardControls((state) => state[Controls.up]);
|
||||
@@ -30,6 +31,8 @@ export const PlayerController = () => {
|
||||
const leftPressed = useKeyboardControls((state) => state[Controls.left]);
|
||||
const rightPressed = useKeyboardControls((state) => state[Controls.right]);
|
||||
const jumpPressed = useKeyboardControls((state) => state[Controls.jump]);
|
||||
const shootPressed = useKeyboardControls((state) => state[Controls.shoot]);
|
||||
|
||||
const [isOnGround, setIsOnGround] = useState(false);
|
||||
const body = useRef();
|
||||
const kart = useRef();
|
||||
@@ -73,6 +76,14 @@ export const PlayerController = () => {
|
||||
const landingSound = useRef();
|
||||
const turboSound = useRef();
|
||||
const [scale, setScale] = useState(0);
|
||||
const raycaster = new THREE.Raycaster();
|
||||
const downDirection = new THREE.Vector3(0, -1, 0);
|
||||
const [shouldLaunch, setShouldLaunch] = useState(false);
|
||||
|
||||
|
||||
const { actions, shouldSlowDown, item, bananas} = useStore();
|
||||
const slowDownDuration = useRef(1500);
|
||||
|
||||
|
||||
useFrame(({ pointer, clock }, delta) => {
|
||||
const time = clock.getElapsedTime();
|
||||
@@ -86,7 +97,6 @@ export const PlayerController = () => {
|
||||
driftBlueSound.current.setVolume(0.5);
|
||||
driftOrangeSound.current.setVolume(0.6);
|
||||
driftPurpleSound.current.setVolume(0.7);
|
||||
|
||||
// HANDLING AND STEERING
|
||||
const kartRotation =
|
||||
kart.current.rotation.y - driftDirection.current * driftForce.current;
|
||||
@@ -121,6 +131,8 @@ export const PlayerController = () => {
|
||||
targetXPosition = -camMaxOffset * -pointer.x;
|
||||
}
|
||||
// ACCELERATING
|
||||
const shouldSlow = actions.getShouldSlowDown();
|
||||
|
||||
|
||||
if (upPressed && currentSpeed < maxSpeed) {
|
||||
// Accelerate the kart within the maximum speed limit
|
||||
@@ -147,6 +159,22 @@ export const PlayerController = () => {
|
||||
);
|
||||
}
|
||||
}
|
||||
if (shouldSlow) {
|
||||
setCurrentSpeed(Math.max(currentSpeed - decceleration * 2 * delta * 144, 0));
|
||||
setCurrentSteeringSpeed(0);
|
||||
slowDownDuration.current -= 1500 * delta;
|
||||
setShouldLaunch(true);
|
||||
if (slowDownDuration.current <= 1) {
|
||||
actions.setShouldSlowDown(false);
|
||||
slowDownDuration.current = 1500;
|
||||
setShouldLaunch(false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// REVERSING
|
||||
if (downPressed && currentSpeed < -maxSpeed) {
|
||||
setCurrentSpeed(
|
||||
@@ -359,6 +387,55 @@ export const PlayerController = () => {
|
||||
|
||||
// SOUND WORK
|
||||
|
||||
// MISC
|
||||
|
||||
|
||||
// ITEMS
|
||||
if(shootPressed && item === "banana") {
|
||||
const distanceBehind = 2; // Adjust this value as needed
|
||||
const scaledBackwardDirection = forwardDirection.multiplyScalar(distanceBehind);
|
||||
|
||||
// Get the current position of the kart
|
||||
const kartPosition = new THREE.Vector3(...vec3(body.current.translation()));
|
||||
|
||||
// Calculate the position for the new banana
|
||||
const bananaPosition = kartPosition.sub(scaledBackwardDirection);
|
||||
const newBanana = {
|
||||
id: Math.random() + "-" + new Date(),
|
||||
position: bananaPosition,
|
||||
player: true,
|
||||
};
|
||||
actions.addBanana(newBanana);
|
||||
actions.useItem();
|
||||
|
||||
}
|
||||
|
||||
if(shootPressed && item === "shell") {
|
||||
const distanceBehind = -1; // Adjust this value as needed
|
||||
const scaledBackwardDirection = forwardDirection.multiplyScalar(distanceBehind);
|
||||
|
||||
// Get the current position of the kart
|
||||
const kartPosition = new THREE.Vector3(
|
||||
body.current.translation().x,
|
||||
body.current.translation().y,
|
||||
body.current.translation().z
|
||||
);
|
||||
|
||||
// Calculate the position for the new banana
|
||||
const shellPosition = kartPosition.sub(scaledBackwardDirection);
|
||||
const newShell = {
|
||||
id: Math.random() + "-" + new Date(),
|
||||
position: shellPosition,
|
||||
player: true,
|
||||
rotation: kartRotation
|
||||
};
|
||||
actions.addShell(newShell);
|
||||
actions.useItem();
|
||||
|
||||
}
|
||||
|
||||
if(item) console.log(item)
|
||||
|
||||
// console.lowg(body.current.translation())
|
||||
});
|
||||
|
||||
@@ -367,20 +444,19 @@ export const PlayerController = () => {
|
||||
<RigidBody
|
||||
ref={body}
|
||||
colliders={false}
|
||||
position={[8, 20, -119]}
|
||||
position={[8, 60, -119]}
|
||||
centerOfMass={[0, -1, 0]}
|
||||
mass={3}
|
||||
ccd
|
||||
name="player"
|
||||
>
|
||||
<BallCollider
|
||||
args={[0.5]}
|
||||
mass={3}
|
||||
onCollisionEnter={(event) => {
|
||||
onCollisionEnter={({other}) => {
|
||||
isOnFloor.current = true;
|
||||
}}
|
||||
// onCollisionExit={(event) => {
|
||||
// isOnFloor.current = false
|
||||
// }}
|
||||
|
||||
/>
|
||||
</RigidBody>
|
||||
|
||||
@@ -391,12 +467,11 @@ export const PlayerController = () => {
|
||||
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.05, 16, 16]} />
|
||||
@@ -417,12 +492,11 @@ export const PlayerController = () => {
|
||||
glowSharpness={1}
|
||||
/>
|
||||
</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.05, 16, 16]} />
|
||||
<meshStandardMaterial
|
||||
@@ -448,24 +522,25 @@ export const PlayerController = () => {
|
||||
<DriftParticlesRight turboColor={turboColor} scale={scale} />
|
||||
<PointParticle
|
||||
position={[-0.6, 0.05, 0.5]}
|
||||
png="./circle.png"
|
||||
png="./particles/circle.png"
|
||||
turboColor={turboColor}
|
||||
/>
|
||||
<PointParticle
|
||||
position={[0.6, 0.05, 0.5]}
|
||||
png="./circle.png"
|
||||
png="./particles/circle.png"
|
||||
turboColor={turboColor}
|
||||
/>
|
||||
<PointParticle
|
||||
position={[-0.6, 0.05, 0.5]}
|
||||
png="./star.png"
|
||||
png="./particles/star.png"
|
||||
turboColor={turboColor}
|
||||
/>
|
||||
<PointParticle
|
||||
position={[0.6, 0.05, 0.5]}
|
||||
png="./star.png"
|
||||
png="./particles/star.png"
|
||||
turboColor={turboColor}
|
||||
/>
|
||||
<HitParticles shouldLaunch={shouldLaunch}/>
|
||||
</group>
|
||||
|
||||
{/* <ContactShadows frames={1} /> */}
|
||||
|
||||
@@ -57,7 +57,6 @@ function setItemAt(instances, bodyPosition, bodyRotation, index) {
|
||||
.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);
|
||||
|
||||
@@ -3,11 +3,13 @@ Auto-generated by: https://github.com/pmndrs/gltfjsx
|
||||
Command: npx gltfjsx@6.2.16 .\mariokarttest.glb --shadows
|
||||
*/
|
||||
|
||||
import React, { useRef } from 'react'
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import { Cylinder, OrbitControls, Sphere, useGLTF } from '@react-three/drei'
|
||||
import { useFrame } from '@react-three/fiber'
|
||||
import FakeGlowMaterial from '../../ShaderMaterials/FakeGlow/FakeGlowMaterial'
|
||||
import FakeFlame from '../../ShaderMaterials/FakeFlame/FakeFlame'
|
||||
import { useStore } from '../../store'
|
||||
import gsap from 'gsap'
|
||||
|
||||
export function Mario({ currentSpeed, steeringAngleWheels, isBoosting, ...props }) {
|
||||
const { nodes, materials } = useGLTF('./models/characters/mariokarttest.glb')
|
||||
@@ -17,6 +19,9 @@ export function Mario({ currentSpeed, steeringAngleWheels, isBoosting, ...props
|
||||
const rearWheels = useRef()
|
||||
const frontWheels = useRef()
|
||||
const [scale, setScale] = React.useState(1)
|
||||
const { actions } = useStore()
|
||||
const [shouldSlow, setShouldSlow] = React.useState(false)
|
||||
const mario = useRef();
|
||||
// isBoosting = true;
|
||||
|
||||
useFrame((_,delta) => {
|
||||
@@ -30,12 +35,21 @@ export function Mario({ currentSpeed, steeringAngleWheels, isBoosting, ...props
|
||||
} else {
|
||||
setScale(Math.max(scale - 0.03 * 144 * delta, 0))
|
||||
}
|
||||
setShouldSlow(actions.getShouldSlowDown());
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldSlow) {
|
||||
gsap.to(mario.current.rotation, {duration: 1.5, y: Math.PI * 3})
|
||||
mario.current.rotation.set(0, 0, 0);
|
||||
}
|
||||
}, [shouldSlow])
|
||||
return (
|
||||
<group
|
||||
{...props}
|
||||
rotation={[0, Math.PI, 0]}
|
||||
dispose={null}
|
||||
ref={mario}
|
||||
>
|
||||
<mesh
|
||||
castShadow
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
Auto-generated by: https://github.com/pmndrs/gltfjsx
|
||||
Command: npx gltfjsx@6.2.16 .\banana_peel_mario_kart.glb --transform --shadows
|
||||
Files: .\banana_peel_mario_kart.glb [186.36KB] > C:\Users\mouli\dev\r3f-vite-starter\public\models\items\banana_peel_mario_kart-transformed.glb [20.2KB] (89%)
|
||||
Author: Anthony Yanez (https://sketchfab.com/paulyanez)
|
||||
License: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
|
||||
Source: https://sketchfab.com/3d-models/banana-peel-mario-kart-c7fd163741614859ba02f302ce0bce32
|
||||
Title: Banana Peel (Mario Kart)
|
||||
*/
|
||||
|
||||
import React, { useRef } from 'react'
|
||||
import { useGLTF } from '@react-three/drei'
|
||||
import { BallCollider, RigidBody } from '@react-three/rapier'
|
||||
import { useFrame } from '@react-three/fiber';
|
||||
import { useStore } from '../../store';
|
||||
|
||||
export function Banana({onCollide, ...props}) {
|
||||
const { nodes, materials } = useGLTF('./models/items/banana_peel_mario_kart-transformed.glb');
|
||||
const rigidBody = useRef();
|
||||
const ref = useRef();
|
||||
const [scale, setScale] = React.useState(0.002);
|
||||
|
||||
const {actions} = useStore();
|
||||
return (
|
||||
<>
|
||||
<RigidBody
|
||||
ref={rigidBody}
|
||||
type='fixed'
|
||||
position={props.position}
|
||||
sensor
|
||||
onIntersectionEnter={(event) => {
|
||||
|
||||
if(scale === 0.002) {
|
||||
actions.setShouldSlowDown(true);
|
||||
console.log(ref.current, rigidBody.current);
|
||||
ref.current.visible = false;
|
||||
setScale(0);
|
||||
rigidBody.setEnable(false);
|
||||
}
|
||||
|
||||
}}
|
||||
colliders={false}
|
||||
name='banana'
|
||||
>
|
||||
<BallCollider args={[0.5]} />
|
||||
|
||||
</RigidBody>
|
||||
|
||||
<group {...props} ref={ref} scale={scale} dispose={null}>
|
||||
<mesh castShadow receiveShadow geometry={nodes['Banana_Peel_02_-_Default_0'].geometry} material={materials['02_-_Default']} position={[39.973, -25.006, -0.017]} rotation={[-Math.PI / 2, 0, 0]} />
|
||||
<mesh castShadow receiveShadow geometry={nodes['Banana_Peel_07_-_Default_0'].geometry} material={materials['07_-_Default']} position={[39.973, -25.006, -0.017]} rotation={[-Math.PI / 2, 0, 0]} />
|
||||
<mesh castShadow receiveShadow geometry={nodes['Banana_Peel_03_-_Default_0'].geometry} material={materials['03_-_Default']} position={[39.973, -25.006, -0.017]} rotation={[-Math.PI / 2, 0, 0]} />
|
||||
</group>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
useGLTF.preload('./models/items/banana_peel_mario_kart-transformed.glb')
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Auto-generated by: https://github.com/pmndrs/gltfjsx
|
||||
Command: npx gltfjsx@6.2.16 .\mario_shell_red.glb
|
||||
Author: Thomas Fugier (https://sketchfab.com/thomas.fugier)
|
||||
License: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
|
||||
Source: https://sketchfab.com/3d-models/mario-shell-red-76a81ff57398423d80800259c3d48262
|
||||
Title: Mario Shell Red
|
||||
*/
|
||||
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import { useGLTF } from '@react-three/drei'
|
||||
import { BallCollider, RigidBody, vec3 } from '@react-three/rapier'
|
||||
import { useFrame } from '@react-three/fiber';
|
||||
|
||||
export function Shell(props) {
|
||||
const { nodes, materials } = useGLTF('./models/items/mario_shell_red.glb')
|
||||
const rigidBody = useRef();
|
||||
const ref = useRef();
|
||||
|
||||
const shell_speed = 100;
|
||||
|
||||
useEffect(() => {
|
||||
const velocity = {
|
||||
x : -Math.sin(props.rotation) * shell_speed,
|
||||
y : 0,
|
||||
z : -Math.cos(props.rotation) * shell_speed,
|
||||
};
|
||||
|
||||
rigidBody.current.setLinvel(velocity, true);
|
||||
},[]);
|
||||
|
||||
useFrame((state, delta) => {
|
||||
const rigidBodyPosition = rigidBody.current.translation();
|
||||
ref.current.position.set(rigidBodyPosition.x, rigidBodyPosition.y, rigidBodyPosition.z);
|
||||
ref.current.rotation.z += 0.2 * delta * 144;
|
||||
});
|
||||
|
||||
|
||||
return (
|
||||
<group dispose={null}>
|
||||
|
||||
<RigidBody ref={rigidBody} type="dynamic" position={props.position} name="shell" colliders={false}>
|
||||
<BallCollider args={[0.5]} />
|
||||
|
||||
</RigidBody>
|
||||
<mesh ref={ref} geometry={nodes.defaultMaterial.geometry} material={materials.Shell} rotation={[-Math.PI / 2, 0, 0]} scale={0.6} />
|
||||
</group>
|
||||
)
|
||||
}
|
||||
|
||||
useGLTF.preload('./models/items/mario_shell_red.glb')
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Auto-generated by: https://github.com/pmndrs/gltfjsx
|
||||
Command: npx gltfjsx@6.2.16 .\mario_kart_item_box.glb
|
||||
Author: Bscott5 (https://sketchfab.com/Bscott5)
|
||||
License: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
|
||||
Source: https://sketchfab.com/3d-models/mario-kart-item-box-8f6a2b6b17b844c5b5dfa38375289975
|
||||
Title: Mario Kart Item Box
|
||||
*/
|
||||
|
||||
import React, { useRef } from "react";
|
||||
import { useGLTF, Float, MeshTransmissionMaterial, RoundedBox } from "@react-three/drei";
|
||||
import { RigidBody } from "@react-three/rapier";
|
||||
import { useStore } from "../../store";
|
||||
|
||||
export function ItemBox(props) {
|
||||
|
||||
const { actions } = useStore();
|
||||
return (
|
||||
<>
|
||||
<RigidBody type="fixed" name="itemBox"
|
||||
sensor
|
||||
onIntersectionEnter={() => {
|
||||
console.log("item box hit");
|
||||
actions.setItem();
|
||||
|
||||
}}
|
||||
position={props.position}
|
||||
>
|
||||
<mesh>
|
||||
<boxGeometry args={[1, 1, 1]} />
|
||||
<meshStandardMaterial color="green" />
|
||||
</mesh>
|
||||
</RigidBody>
|
||||
<group {...props} dispose={null}>
|
||||
|
||||
|
||||
<Float
|
||||
speed={2} // Animation speed, defaults to 1
|
||||
rotationIntensity={20} // XYZ rotation intensity, defaults to 1
|
||||
floatIntensity={1} // Up/down float intensity, works like a multiplier with floatingRange,defaults to 1
|
||||
floatingRange={[1, 2]} // Range of y-axis values the object will float within, defaults to [-0.1,0.1]
|
||||
>
|
||||
<mesh>
|
||||
<boxGeometry args={[1, 1, 1]} />
|
||||
<meshBasicMaterial color="green" />
|
||||
</mesh>
|
||||
</Float>
|
||||
</group>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -7,6 +7,10 @@ export const playAudio = (path, callback) => {
|
||||
}
|
||||
audio.play();
|
||||
};
|
||||
export const items = [
|
||||
"banana",
|
||||
"shell",
|
||||
]
|
||||
|
||||
export const useStore = create((set, get) => ({
|
||||
particles1: [],
|
||||
@@ -14,6 +18,11 @@ export const useStore = create((set, get) => ({
|
||||
bodyPosition: [0, 0, 0],
|
||||
bodyRotation: [0, 0, 0],
|
||||
pastPositions: [],
|
||||
shouldSlowdown: false,
|
||||
bananas: [],
|
||||
items: ["banana", "shell"],
|
||||
item: "",
|
||||
shells: [],
|
||||
addPastPosition: (position) => {
|
||||
set((state) => ({
|
||||
pastPositions: [position, ...state.pastPositions.slice(0, 499)],
|
||||
@@ -52,5 +61,45 @@ export const useStore = create((set, get) => ({
|
||||
getBodyRotation: () => {
|
||||
return get().bodyRotation;
|
||||
},
|
||||
setShouldSlowDown: (shouldSlowdown) => {
|
||||
set({ shouldSlowdown });
|
||||
},
|
||||
getShouldSlowDown: () => {
|
||||
return get().shouldSlowdown;
|
||||
},
|
||||
addBanana: (banana) => {
|
||||
set((state) => ({
|
||||
bananas: [...state.bananas, banana],
|
||||
}));
|
||||
},
|
||||
removeBanana: (banana) => {
|
||||
set((state) => ({
|
||||
bananas: state.bananas.filter((b) => b.id !== banana.id),
|
||||
}));
|
||||
},
|
||||
getBananas: () => {
|
||||
return get().bananas;
|
||||
},
|
||||
setItem:() => {
|
||||
set((state) => ({
|
||||
item: state.items[Math.floor(Math.random() * state.items.length)],
|
||||
}));
|
||||
},
|
||||
useItem:() => {
|
||||
set((state) => ({
|
||||
item: "",
|
||||
}));
|
||||
},
|
||||
addShell: (shell) => {
|
||||
set((state) => ({
|
||||
shells: [...state.shells, shell],
|
||||
}));
|
||||
},
|
||||
removeShell: (shell) => {
|
||||
set((state) => ({
|
||||
shells: state.shells.filter((s) => s.id !== shell.id),
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
}));
|
||||
@@ -0,0 +1,68 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
export const useGamepad = () => {
|
||||
const [gamepadInfo, setGamepadInfo] = useState({ connected: false, buttonA: false, buttonB :false, buttonX: false, buttonY:false, joystick: [0, 0], joystickRight : [0,0], RB: false, LB: false, RT: false, LT: false, start: false, select: false, up: false, down: false, left: false, right: 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,
|
||||
buttonB: gamepad.buttons[1].pressed,
|
||||
buttonX: gamepad.buttons[2].pressed,
|
||||
buttonY: gamepad.buttons[3].pressed,
|
||||
joystickRight: [gamepad.axes[2], gamepad.axes[3]],
|
||||
LT: gamepad.buttons[6].pressed,
|
||||
RT: gamepad.buttons[7].pressed,
|
||||
LB: gamepad.buttons[4].pressed,
|
||||
RB: gamepad.buttons[5].pressed,
|
||||
|
||||
start: gamepad.buttons[9].pressed,
|
||||
select: gamepad.buttons[8].pressed,
|
||||
up: gamepad.buttons[12].pressed,
|
||||
down: gamepad.buttons[13].pressed,
|
||||
left: gamepad.buttons[14].pressed,
|
||||
right: gamepad.buttons[15].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, buttonB :false, buttonX: false, buttonY:false, joystick: [0, 0], joystickRight : [0,0], RB: false, LB: false, RT: false, LT: false, start: false, select: false, up: false, down: false, left: false, right: false});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const gamepadConnected = () => {
|
||||
console.log('Gamepad connected!');
|
||||
updateGamepadState();
|
||||
};
|
||||
|
||||
const gamepadDisconnected = () => {
|
||||
console.log('Gamepad disconnected!');
|
||||
setGamepadInfo({ connected : false, buttonA: false, buttonB :false, buttonX: false, buttonY:false, joystick: [0, 0], joystickRight : [0,0], RB: false, LB: false, RT: false, LT: false, start: false, select: false, up: false, down: false, left: false, right: false});
|
||||
};
|
||||
|
||||
window.addEventListener('gamepadconnected', gamepadConnected);
|
||||
window.addEventListener('gamepaddisconnected', gamepadDisconnected);
|
||||
|
||||
const interval = setInterval(updateGamepadState, 100);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('gamepadconnected', gamepadConnected);
|
||||
window.removeEventListener('gamepaddisconnected', gamepadDisconnected);
|
||||
clearInterval(interval);
|
||||
};
|
||||
}, [gamepadInfo]);
|
||||
|
||||
return gamepadInfo;
|
||||
};
|
||||
Reference in new issue
Block a user