diff --git a/public/models/misc/gift-transformed.glb b/public/models/misc/gift-transformed.glb new file mode 100644 index 0000000..237aa4c Binary files /dev/null and b/public/models/misc/gift-transformed.glb differ diff --git a/public/models/misc/gift.glb b/public/models/misc/gift.glb new file mode 100644 index 0000000..11456f0 Binary files /dev/null and b/public/models/misc/gift.glb differ diff --git a/public/particles/circle_01.png b/public/particles/circle_01.png new file mode 100644 index 0000000..adabdd9 Binary files /dev/null and b/public/particles/circle_01.png differ diff --git a/public/particles/circle_coin.png b/public/particles/circle_coin.png new file mode 100644 index 0000000..adabdd9 Binary files /dev/null and b/public/particles/circle_coin.png differ diff --git a/public/particles/star_coin.png b/public/particles/star_coin.png new file mode 100644 index 0000000..5836541 Binary files /dev/null and b/public/particles/star_coin.png differ diff --git a/src/App.jsx b/src/App.jsx index 6dab505..5906eb4 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -30,24 +30,26 @@ function App() { ) return ( + <> + + - + ) } diff --git a/src/HUD.jsx b/src/HUD.jsx index 19bae30..bf4ca5d 100644 --- a/src/HUD.jsx +++ b/src/HUD.jsx @@ -30,7 +30,7 @@ export const HUD = () => {
steering wheel { {/* */} - + diff --git a/src/components/Particles/coins/CircleCoinParticle.jsx b/src/components/Particles/coins/CircleCoinParticle.jsx new file mode 100644 index 0000000..a036261 --- /dev/null +++ b/src/components/Particles/coins/CircleCoinParticle.jsx @@ -0,0 +1,56 @@ +import React, { useEffect,useRef, useState } from "react"; +import { useLoader, useFrame } from "@react-three/fiber"; +import * as THREE from "three"; + +export const CircleCoinParticle = ({ position, coins }) => { + const texture = useLoader(THREE.TextureLoader, "./particles/circle_coin.png"); + const pointsRef = useRef(); + const materialRef = useRef(); + const [size, setSize] = useState(1); + const [opacity, setOpacity] = useState(1); + + const points = React.useMemo(() => { + const geom = new THREE.BufferGeometry(); + geom.setAttribute( + "position", + new THREE.Float32BufferAttribute(position, 3) + ); + return geom; + }, [position]); + + + useEffect(() => { + if (materialRef.current) { + materialRef.current.color.multiplyScalar(4); + } + }, []); + + useEffect(() => { + setSize(0); + setOpacity(1); + }, [coins]); + + useFrame((_, delta) => { + if (size < 5) { + setSize((size) => Math.min(size + 0.2 * delta * 144, 5)); + } else if (opacity > 0) { + setOpacity((opacity) => Math.max(opacity - 0.1 * delta * 144, 0)); + setSize((size) => Math.max(size - 0.1 * delta * 144, 0)); + } + }); + + return ( + + + + ); +}; diff --git a/src/components/Particles/coins/CoinParticles.jsx b/src/components/Particles/coins/CoinParticles.jsx new file mode 100644 index 0000000..c4ba52d --- /dev/null +++ b/src/components/Particles/coins/CoinParticles.jsx @@ -0,0 +1,15 @@ +import { CircleCoinParticle } from "./CircleCoinParticle" +import { StarCoinParticle } from "./StarCoinParticle" + +export const CoinParticles = ({ coins }) => { + return ( + <> + + + + + + + + ) +} \ No newline at end of file diff --git a/src/components/Particles/coins/StarCoinParticle.jsx b/src/components/Particles/coins/StarCoinParticle.jsx new file mode 100644 index 0000000..9333d10 --- /dev/null +++ b/src/components/Particles/coins/StarCoinParticle.jsx @@ -0,0 +1,68 @@ +import React, { useEffect, useRef } from "react"; +import { useLoader, useFrame } from "@react-three/fiber"; +import * as THREE from "three"; + +export const StarCoinParticle = ({ position, coins, timeModifier }) => { + const texture = useLoader(THREE.TextureLoader, "./particles/star_coin.png"); + const pointsRef = useRef(); + const materialRef = useRef(); + const sizeRef = useRef(1); + const opacityRef = useRef(1); + const originalYpos = useRef(0); + + const points = React.useMemo(() => { + const geom = new THREE.BufferGeometry(); + geom.setAttribute( + "position", + new THREE.Float32BufferAttribute(position, 3) + ); + return geom; + }, [position]); + + useEffect(() => { + if (materialRef.current) { + materialRef.current.color.multiplyScalar(6); + } + }, []); + + useEffect(() => { + sizeRef.current = 0; + opacityRef.current = 1; + pointsRef.current.position.x = Math.random() * 1 - 0.5; + pointsRef.current.position.y = Math.random() * 0.5 - 0.25; + originalYpos.current = pointsRef.current.position.y; + }, [coins]); + + useFrame((state, delta) => { + const time = state.clock.getElapsedTime(); + pointsRef.current.position.y += 0.008 * delta * 144; + if (sizeRef.current < 1) { + sizeRef.current = Math.min(sizeRef.current + 0.01 * delta * 144, 1); + } + + if (pointsRef.current.position.y > originalYpos.current + 0.01) { + opacityRef.current = Math.max(opacityRef.current - 0.01 * delta * 144, 0); + } else { + opacityRef.current = Math.abs(Math.sin(time * timeModifier * 1500)); + } + + // Update material properties directly + if (materialRef.current) { + materialRef.current.size = sizeRef.current; + materialRef.current.opacity = opacityRef.current; + } +}); + + return ( + + + + ); +}; diff --git a/src/components/Particles/DriftParticlesLeft.jsx b/src/components/Particles/drifts/DriftParticlesLeft.jsx similarity index 100% rename from src/components/Particles/DriftParticlesLeft.jsx rename to src/components/Particles/drifts/DriftParticlesLeft.jsx diff --git a/src/components/Particles/DriftParticlesRight.jsx b/src/components/Particles/drifts/DriftParticlesRight.jsx similarity index 100% rename from src/components/Particles/DriftParticlesRight.jsx rename to src/components/Particles/drifts/DriftParticlesRight.jsx diff --git a/src/components/Particles/Particles1.jsx b/src/components/Particles/drifts/Particles1.jsx similarity index 100% rename from src/components/Particles/Particles1.jsx rename to src/components/Particles/drifts/Particles1.jsx diff --git a/src/components/Particles/Particles2.jsx b/src/components/Particles/drifts/Particles2.jsx similarity index 100% rename from src/components/Particles/Particles2.jsx rename to src/components/Particles/drifts/Particles2.jsx diff --git a/src/components/Particles/Particles3.jsx b/src/components/Particles/drifts/Particles3.jsx similarity index 100% rename from src/components/Particles/Particles3.jsx rename to src/components/Particles/drifts/Particles3.jsx diff --git a/src/components/Particles/Particles4.jsx b/src/components/Particles/drifts/Particles4.jsx similarity index 100% rename from src/components/Particles/Particles4.jsx rename to src/components/Particles/drifts/Particles4.jsx diff --git a/src/components/Particles/PointParticle.jsx b/src/components/Particles/drifts/PointParticle.jsx similarity index 100% rename from src/components/Particles/PointParticle.jsx rename to src/components/Particles/drifts/PointParticle.jsx diff --git a/src/components/Particles/FlameParticle.jsx b/src/components/Particles/flames/FlameParticle.jsx similarity index 100% rename from src/components/Particles/FlameParticle.jsx rename to src/components/Particles/flames/FlameParticle.jsx diff --git a/src/components/Particles/FlameParticles.jsx b/src/components/Particles/flames/FlameParticles.jsx similarity index 100% rename from src/components/Particles/FlameParticles.jsx rename to src/components/Particles/flames/FlameParticles.jsx diff --git a/src/components/Particles/HitParticle.jsx b/src/components/Particles/hits/HitParticle.jsx similarity index 100% rename from src/components/Particles/HitParticle.jsx rename to src/components/Particles/hits/HitParticle.jsx diff --git a/src/components/Particles/HitParticleTwo.jsx b/src/components/Particles/hits/HitParticleTwo.jsx similarity index 100% rename from src/components/Particles/HitParticleTwo.jsx rename to src/components/Particles/hits/HitParticleTwo.jsx diff --git a/src/components/Particles/HitParticles.jsx b/src/components/Particles/hits/HitParticles.jsx similarity index 100% rename from src/components/Particles/HitParticles.jsx rename to src/components/Particles/hits/HitParticles.jsx diff --git a/src/components/Particles/items/CircleItemParticle.jsx b/src/components/Particles/items/CircleItemParticle.jsx new file mode 100644 index 0000000..eac1629 --- /dev/null +++ b/src/components/Particles/items/CircleItemParticle.jsx @@ -0,0 +1,61 @@ +import React, { useEffect,useRef, useState } from "react"; +import { useLoader, useFrame } from "@react-three/fiber"; +import * as THREE from "three"; + +export const CircleItemParticle = ({ position, item, color }) => { + const texture = useLoader(THREE.TextureLoader, "./particles/circle_coin.png"); + const pointsRef = useRef(); + const materialRef = useRef(); + const [size, setSize] = useState(1); + const [opacity, setOpacity] = useState(1); + + const [currentColor, setCurrentColor] = useState(color); + + const points = React.useMemo(() => { + const geom = new THREE.BufferGeometry(); + geom.setAttribute( + "position", + new THREE.Float32BufferAttribute(position, 3) + ); + return geom; + }, [position]); + + + useEffect(() => { + if (materialRef.current) { + materialRef.current.color.multiplyScalar(4); + } + }, []); + + useEffect(() => { + if(item){ + setSize(0); + setOpacity(1); + } + }, [item]); + + useFrame((_, delta) => { + if (size < 5) { + setSize((size) => Math.min(size + 0.2 * delta * 144, 5)); + } else if (opacity > 0) { + setOpacity((opacity) => Math.max(opacity - 0.1 * delta * 144, 0)); + setSize((size) => Math.max(size - 0.1 * delta * 144, 0)); + } + + }); + + return ( + + + + ); +}; diff --git a/src/components/Particles/items/ItemParticles.jsx b/src/components/Particles/items/ItemParticles.jsx new file mode 100644 index 0000000..2c4b866 --- /dev/null +++ b/src/components/Particles/items/ItemParticles.jsx @@ -0,0 +1,20 @@ +import { CircleItemParticle } from "./CircleItemParticle" +import { StarItemParticle } from "./StarItemParticle" +import { SmallCircleParticle } from "./SmallCircleParticle" + +export const ItemParticles = ({item}) => { + return ( + <> + + + + + + + + + + + + ) +} \ No newline at end of file diff --git a/src/components/Particles/items/SmallCircleParticle.jsx b/src/components/Particles/items/SmallCircleParticle.jsx new file mode 100644 index 0000000..f7cf737 --- /dev/null +++ b/src/components/Particles/items/SmallCircleParticle.jsx @@ -0,0 +1,70 @@ +import React, { useEffect, useRef } from "react"; +import { useLoader, useFrame } from "@react-three/fiber"; +import * as THREE from "three"; + +export const SmallCircleParticle = ({ position, item, timeModifier, color }) => { + const texture = useLoader(THREE.TextureLoader, "./particles/circle_01.png"); + const pointsRef = useRef(); + const materialRef = useRef(); + const sizeRef = useRef(1); + const opacityRef = useRef(1); + const originalYpos = useRef(0); + + const points = React.useMemo(() => { + const geom = new THREE.BufferGeometry(); + geom.setAttribute( + "position", + new THREE.Float32BufferAttribute(position, 3) + ); + return geom; + }, [position]); + + useEffect(() => { + if (materialRef.current) { + materialRef.current.color.multiplyScalar(6); + } + }, []); + + useEffect(() => { + if(item){ + sizeRef.current = 0; + opacityRef.current = 1; + pointsRef.current.position.x = Math.random() * 1 - 0.5; + pointsRef.current.position.y = Math.random() * 0.5 - 0.25; + originalYpos.current = pointsRef.current.position.y; + } + }, [item]); + + useFrame((state, delta) => { + const time = state.clock.getElapsedTime(); + pointsRef.current.position.y += 0.008 * delta * 144; + if (sizeRef.current < 1) { + sizeRef.current = Math.min(sizeRef.current + 0.01 * delta * 144, 1); + } + + if (pointsRef.current.position.y > originalYpos.current + 0.01) { + opacityRef.current = Math.max(opacityRef.current - 0.01 * delta * 144, 0); + } else { + opacityRef.current = Math.abs(Math.sin(time * timeModifier * 1500)); + } + + // Update material properties directly + if (materialRef.current) { + materialRef.current.size = sizeRef.current; + materialRef.current.opacity = opacityRef.current; + } +}); + + return ( + + + + ); +}; diff --git a/src/components/Particles/items/StarItemParticle.jsx b/src/components/Particles/items/StarItemParticle.jsx new file mode 100644 index 0000000..554f317 --- /dev/null +++ b/src/components/Particles/items/StarItemParticle.jsx @@ -0,0 +1,70 @@ +import React, { useEffect, useRef } from "react"; +import { useLoader, useFrame } from "@react-three/fiber"; +import * as THREE from "three"; + +export const StarItemParticle = ({ position, item, timeModifier, color }) => { + const texture = useLoader(THREE.TextureLoader, "./particles/star_coin.png"); + const pointsRef = useRef(); + const materialRef = useRef(); + const sizeRef = useRef(1); + const opacityRef = useRef(1); + const originalYpos = useRef(0); + + const points = React.useMemo(() => { + const geom = new THREE.BufferGeometry(); + geom.setAttribute( + "position", + new THREE.Float32BufferAttribute(position, 3) + ); + return geom; + }, [position]); + + useEffect(() => { + if (materialRef.current) { + materialRef.current.color.multiplyScalar(6); + } + }, []); + + useEffect(() => { + if(item){ + sizeRef.current = 0; + opacityRef.current = 1; + pointsRef.current.position.x = Math.random() * 1 - 0.5; + pointsRef.current.position.y = Math.random() * 0.5 - 0.25; + originalYpos.current = pointsRef.current.position.y; + } + }, [item]); + + useFrame((state, delta) => { + const time = state.clock.getElapsedTime(); + pointsRef.current.position.y += 0.008 * delta * 144; + if (sizeRef.current < 1) { + sizeRef.current = Math.min(sizeRef.current + 0.01 * delta * 144, 1); + } + + if (pointsRef.current.position.y > originalYpos.current + 0.01) { + opacityRef.current = Math.max(opacityRef.current - 0.01 * delta * 144, 0); + } else { + opacityRef.current = Math.abs(Math.sin(time * timeModifier * 1500)); + } + + // Update material properties directly + if (materialRef.current) { + materialRef.current.size = sizeRef.current; + materialRef.current.opacity = opacityRef.current; + } +}); + + return ( + + + + ); +}; diff --git a/src/components/PlayerController.jsx b/src/components/PlayerController.jsx index 1ba0b0e..c34b567 100644 --- a/src/components/PlayerController.jsx +++ b/src/components/PlayerController.jsx @@ -14,16 +14,18 @@ import { useRef, useState, useEffect, useCallback } from "react"; import * as THREE from "three"; import { Mario } from "./models/characters/Mario_kart"; -import { DriftParticlesLeft } from "./Particles/DriftParticlesLeft"; -import { DriftParticlesRight } from "./Particles/DriftParticlesRight"; +import { DriftParticlesLeft } from "./Particles/drifts/DriftParticlesLeft"; +import { DriftParticlesRight } from "./Particles/drifts/DriftParticlesRight"; -import { PointParticle } from "./Particles/PointParticle"; +import { PointParticle } from "./Particles/drifts/PointParticle"; -import { FlameParticles } from "./Particles/FlameParticles"; +import { FlameParticles } from "./Particles/flames/FlameParticles"; import { useStore } from "./store"; import { Cylinder } from "@react-three/drei"; import FakeGlowMaterial from "./ShaderMaterials/FakeGlow/FakeGlowMaterial"; -import { HitParticles } from "./Particles/HitParticles"; +import { HitParticles } from "./Particles/hits/HitParticles"; +import { CoinParticles } from "./Particles/coins/CoinParticles"; +import { ItemParticles } from "./Particles/items/ItemParticles"; export const PlayerController = () => { const upPressed = useKeyboardControls((state) => state[Controls.up]); @@ -83,7 +85,7 @@ export const PlayerController = () => { const effectiveBoost = useRef(0); - const { actions, shouldSlowDown, item, bananas} = useStore(); + const { actions, shouldSlowDown, item, bananas, coins} = useStore(); const slowDownDuration = useRef(1500); @@ -461,7 +463,7 @@ export const PlayerController = () => { actions.useItem(); } - + console.log("coins", coins); }); return ( @@ -497,12 +499,8 @@ export const PlayerController = () => { steeringAngleWheels={steeringAngleWheels} isBoosting={isBoosting} /> - - + + { glowSharpness={1} /> - C:\Users\mouli\dev\r3f-vite-starter\public\models\misc\gift-transformed.glb [86.34KB] (88%) +Author: gorzi (https://sketchfab.com/gorzi90) +License: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/) +Source: https://sketchfab.com/3d-models/gift-f3d8abcd3b9442f39a9a2017d59b56a1 +Title: Gift +*/ + +import React, { useRef } from 'react' +import { useGLTF, Float } from '@react-three/drei' +import { CuboidCollider, RigidBody } from "@react-three/rapier"; +import { useStore } from "../../store"; +import { useFrame } from '@react-three/fiber'; + +export function ItemBox(props) { + const { nodes, materials } = useGLTF('./models/misc/gift-transformed.glb'); + const { actions } = useStore(); + const ref = useRef(); + const [scale, setScale] = React.useState(0.6); + const frames = useRef(0); + const body = useRef(); + useFrame((state, delta) => { + const time = state.clock.getElapsedTime(); + ref.current.position.y = Math.sin(time) * 0.1 + 2.5; + ref.current.rotation.x = Math.sin(time) * 0.1; + ref.current.rotation.y += delta; + ref.current.rotation.z = Math.sin(time) * 0.5; + if(scale < 0.6 && frames.current > 0){ + frames.current -= 1 * delta * 144; + + } + if(frames.current <= 0){ + setScale(Math.min(scale + 0.5 * delta, 0.6)); + if(body.current){ + body.current.setEnabled(true); + } + } + } + ); + return ( + <> + { + if(other.rigidBodyObject.name === "player"){ + + console.log("item box hit"); + actions.setItem(); + setScale(0); + frames.current = 400; + body.current.setEnabled(false); + } + }} + position={props.position} + colliders={false} + > + + + + + + + + ) + +} + +useGLTF.preload('./models/misc/gift-transformed.glb') diff --git a/src/components/models/misc/Super_mario_bros_coin.jsx b/src/components/models/misc/Super_mario_bros_coin.jsx index 4153177..d71874b 100644 --- a/src/components/models/misc/Super_mario_bros_coin.jsx +++ b/src/components/models/misc/Super_mario_bros_coin.jsx @@ -8,30 +8,64 @@ Source: https://sketchfab.com/3d-models/super-mario-bros-coin-aa97e093847a439f9f Title: Super Mario Bros Coin */ -import React, { useEffect, useRef } from 'react' -import { useGLTF, useAnimations } from '@react-three/drei' -import { useFrame } from '@react-three/fiber' +import React, { useEffect, useRef } from "react"; +import { useGLTF, useAnimations } from "@react-three/drei"; +import { useFrame } from "@react-three/fiber"; +import { RigidBody } from "@react-three/rapier"; +import { useStore } from "../../store"; export function Coin(props) { - const group = useRef() - const { nodes, materials, animations } = useGLTF('./models/misc/super_mario_bros_coin-transformed.glb') - const { actions } = useAnimations(animations, group) - + const group = useRef(); + const { nodes, materials } = useGLTF( + "./models/misc/super_mario_bros_coin-transformed.glb" + ); + const { actions } = useStore(); + const [scale, setScale] = React.useState(0.424); + const frames = useRef(0); useFrame((state, delta) => { - group.current.rotation.y += 4 * delta - }) + + group.current.rotation.y += 4 * delta; + if(scale < 0.424 && frames.current > 0){ + frames.current -= 1 * delta * 144; + + } + if(frames.current <= 0){ + setScale(Math.min(scale + 0.5 * delta, 0.424)); + if(body.current){ + body.current.setEnable(true); + } + } + }); + + const body = useRef(); return ( - - - - - - - - - - ) + <> + { + if(other.rigidBodyObject.name === "player"){ + actions.addCoins(); + setScale(0); + frames.current = 600; + body.current.setEnable(false); + } + }} + position={props.position} + > + + + + ); } -useGLTF.preload('./models/misc/super_mario_bros_coin-transformed.glb') +useGLTF.preload("./models/misc/super_mario_bros_coin-transformed.glb"); diff --git a/src/components/store.jsx b/src/components/store.jsx index 5142044..a1e2bf1 100644 --- a/src/components/store.jsx +++ b/src/components/store.jsx @@ -24,6 +24,7 @@ export const useStore = create((set, get) => ({ item: "", shells: [], skids: [], + coins : 0, addPastPosition: (position) => { set((state) => ({ pastPositions: [position, ...state.pastPositions.slice(0, 499)], @@ -111,6 +112,16 @@ export const useStore = create((set, get) => ({ skids: [...state.skids, skid], })); }, + addCoins : () => { + set((state) => ({ + coins: state.coins + 1, + })); + }, + looseCoins : () => { + set((state) => ({ + coins: state.coins - 1, + })); + }, }, })); diff --git a/src/index.css b/src/index.css index a397622..18e8d52 100644 --- a/src/index.css +++ b/src/index.css @@ -39,6 +39,7 @@ pointer-events: none; } .logo{ + display: none; position:absolute; top:150px; left:500px; diff --git a/src/main.jsx b/src/main.jsx index dc4b631..e35d3a2 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -7,6 +7,6 @@ import { HUD } from './HUD' ReactDOM.createRoot(document.getElementById('root')).render( - {/* */} + , )