added item system

pull/3/head
Alex 2024-01-31 15:29:31 +01:00
parent 11be02d977
commit 77a14c7733
26 changed files with 676 additions and 35 deletions

1
package-lock.json generated
View File

@ -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": {

View File

@ -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.

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 93 KiB

View File

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

BIN
public/particles/test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@ -39,6 +39,7 @@ function App() {
<Physics
gravity={[0, -90, 0]}
timeStep={'vary'}
// debug
>
<KeyboardControls map={map}>
<Experience />

View File

@ -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>
</>
)
}
);
};

View File

@ -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 });

View File

@ -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>
);
};

View File

@ -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}/>
</>
)
}

View File

@ -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}

View File

@ -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} /> */}

View File

@ -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);

View File

@ -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

View File

@ -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')

View File

@ -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')

View File

@ -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>
</>
);
}

View File

@ -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),
}));
}
},
}));

View File

@ -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;
};