commit
310e471fab
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) [2022] [Ron Waller]
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,77 @@
|
|||
# Mario Kart 3.js - JavaScript/WebGL Mario Kart
|
||||
[Link](https://mario-kart-3-js.vercel.app/)
|
||||
|
||||
DISCLAIMER : This is not a completed project, I would say around 50% of the work has been done up to now. It takes a lot of time so please enjoy.
|
||||
|
||||
## How to install
|
||||
|
||||
Clone the repository or download it
|
||||
|
||||
Open your terminal and inside the project folder, run :
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
Start the dev server
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## How to use (Gameplay)
|
||||
|
||||
- Use the W key to accelerate, the mouse to steer for now (will be updated for mobile/gamepad/keyboard).
|
||||
|
||||
- Steer with the mouse.
|
||||
|
||||
- Press and hold the space bar to initiate a drift. Steer and counter steer to maintain the drift. release it to get a mini - turbo.
|
||||
|
||||
- Press E key to use the current item.
|
||||
|
||||
- Press R to reset your position, usable anytime.
|
||||
|
||||
## How to use (Code)
|
||||
|
||||
- Anything needs update.
|
||||
|
||||
- You can also edit the README to add elements to the To-do List.
|
||||
|
||||
- Feel free to bring your ideas to the project even if you can't code them.
|
||||
|
||||
## TO - DO
|
||||
|
||||
- Design Landing page
|
||||
|
||||
- Add items
|
||||
|
||||
- Add texture to the flame shaders
|
||||
|
||||
- Add curve/length modifiers to drift particles 3/4
|
||||
|
||||
- Add Skid marks
|
||||
|
||||
- Add smokes
|
||||
|
||||
- Add wind screen effect when boosting
|
||||
|
||||
- Improve sound design quality
|
||||
|
||||
- Design UI for HUD
|
||||
|
||||
- Make Time Trial mode
|
||||
|
||||
- Design tracks and checkpoints
|
||||
|
||||
- Improve code quality
|
||||
|
||||
- Items
|
||||
- Tennis ball
|
||||
- Bomb
|
||||
- Real red shell
|
||||
- Treats
|
||||
- ?
|
||||
|
||||
## License
|
||||
|
||||
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
Auto-generated by: https://github.com/pmndrs/gltfjsx
|
||||
Command: npx gltfjsx@6.2.16 c:\Users\mouli\Downloads\mario_kart.glb -o c:\Users\mouli\Desktop\mario_kart.tsx --types
|
||||
Author: TheShibeLord (https://sketchfab.com/TheShibeLord)
|
||||
License: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
|
||||
Source: https://sketchfab.com/3d-models/mario-kart-66cc131575344ab69238ec5872f24927
|
||||
Title: Mario Kart
|
||||
*/
|
||||
|
||||
import * as THREE from 'three'
|
||||
import React, { useRef } from 'react'
|
||||
import { useGLTF } from '@react-three/drei'
|
||||
import { GLTF } from 'three-stdlib'
|
||||
|
||||
type GLTFResult = GLTF & {
|
||||
nodes: {
|
||||
mt_mario: THREE.Mesh
|
||||
mt_kart_Mario_S: THREE.Mesh
|
||||
mt_Kart_Mario_Tire_S: THREE.Mesh
|
||||
}
|
||||
materials: {
|
||||
mt_mario: THREE.MeshStandardMaterial
|
||||
mt_kart_Mario_S: THREE.MeshStandardMaterial
|
||||
mt_Kart_Mario_Tire_S: THREE.MeshStandardMaterial
|
||||
}
|
||||
animations: GLTFAction[]
|
||||
}
|
||||
|
||||
type ContextType = Record<string, React.ForwardRefExoticComponent<JSX.IntrinsicElements['mesh']>>
|
||||
|
||||
export function Model(props: JSX.IntrinsicElements['group']) {
|
||||
const { nodes, materials } = useGLTF('/mario_kart.glb') as GLTFResult
|
||||
return (
|
||||
<group {...props} dispose={null}>
|
||||
<group rotation={[-Math.PI / 2, 0, 0]}>
|
||||
<group rotation={[Math.PI / 2, 0, 0]}>
|
||||
<mesh geometry={nodes.mt_mario.geometry} material={materials.mt_mario} />
|
||||
<mesh geometry={nodes.mt_kart_Mario_S.geometry} material={materials.mt_kart_Mario_S} />
|
||||
<mesh geometry={nodes.mt_Kart_Mario_Tire_S.geometry} material={materials.mt_Kart_Mario_Tire_S} />
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
)
|
||||
}
|
||||
|
||||
useGLTF.preload('/mario_kart.glb')
|
|
@ -14,6 +14,7 @@
|
|||
"@react-three/rapier": "^1.2.1",
|
||||
"gsap": "^3.12.5",
|
||||
"leva": "^0.9.35",
|
||||
"playroomkit": "^0.0.61",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-gamepad": "^1.0.3",
|
||||
|
@ -2423,6 +2424,15 @@
|
|||
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/playroomkit": {
|
||||
"version": "0.0.61",
|
||||
"resolved": "https://registry.npmjs.org/playroomkit/-/playroomkit-0.0.61.tgz",
|
||||
"integrity": "sha512-BUjGkZZcV5OQ29sTmjjI3Ad0SZLRvuBYWAdu4MqhnCjiaHTDJp4KvacVx6rJEJe9jdamtCimkZ/5XXuGm9h2AQ==",
|
||||
"peerDependencies": {
|
||||
"react": ">=17.0.2 <= 18",
|
||||
"react-dom": ">=17.0.2 <= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.33",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz",
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
"@react-three/rapier": "^1.2.1",
|
||||
"gsap": "^3.12.5",
|
||||
"leva": "^0.9.35",
|
||||
"playroomkit": "^0.0.61",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-gamepad": "^1.0.3",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
25
src/App.jsx
25
src/App.jsx
|
@ -1,8 +1,10 @@
|
|||
import { Canvas } from '@react-three/fiber'
|
||||
import { Experience } from './components/Experience'
|
||||
import { Suspense, useMemo } from 'react'
|
||||
import { Suspense, useEffect, useMemo } from 'react'
|
||||
import { Physics } from '@react-three/rapier'
|
||||
import { KeyboardControls, Loader, OrbitControls, Preload, Stats } from '@react-three/drei'
|
||||
import { insertCoin, onPlayerJoin } from 'playroomkit'
|
||||
import { useStore } from "./components/store";
|
||||
|
||||
export const Controls = {
|
||||
up: 'up',
|
||||
|
@ -29,6 +31,27 @@ function App() {
|
|||
[]
|
||||
)
|
||||
|
||||
const { actions } = useStore();
|
||||
const start = async () => {
|
||||
await insertCoin();
|
||||
|
||||
onPlayerJoin((state) => {
|
||||
actions.addPlayer(state);
|
||||
console.log('player joined', state);
|
||||
actions.setId(state.id);
|
||||
console.log(state)
|
||||
|
||||
state.onQuit(() => {
|
||||
actions.removePlayer(state);
|
||||
console.log('player quit', state);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
start();
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<Loader />
|
||||
|
|
|
@ -40,7 +40,6 @@ export const HUD = () => {
|
|||
default:
|
||||
setImage("");
|
||||
}
|
||||
console.log(item);
|
||||
}, [item]);
|
||||
|
||||
return (
|
||||
|
|
|
@ -17,24 +17,75 @@ import {
|
|||
SMAA,
|
||||
ChromaticAberration,
|
||||
Vignette,
|
||||
LUT,
|
||||
} from "@react-three/postprocessing";
|
||||
import { Banana } from "./models/items/Banana_peel_mario_kart";
|
||||
import { ItemBox } from "./models/misc/Gift";
|
||||
import { useStore } from "./store";
|
||||
import { Shell } from "./models/items/Mario_shell_red";
|
||||
import { Coin } from "./models/misc/Super_mario_bros_coin";
|
||||
import {
|
||||
RPC,
|
||||
getState,
|
||||
insertCoin,
|
||||
isHost,
|
||||
myPlayer,
|
||||
onPlayerJoin,
|
||||
useMultiplayerState,
|
||||
} from "playroomkit";
|
||||
import { PlayerDummies } from "./PlayerDummies";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useFrame, useLoader } from "@react-three/fiber";
|
||||
import { LUTPass, LUTCubeLoader } from 'three-stdlib'
|
||||
|
||||
export const Experience = () => {
|
||||
const onCollide = (event) => {
|
||||
console.log(event);
|
||||
};
|
||||
const { bananas, shells} = useStore();
|
||||
const { bananas, shells, players, id, actions } = useStore();
|
||||
const [networkBananas, setNetworkBananas] = useMultiplayerState(
|
||||
"bananas",
|
||||
[]
|
||||
);
|
||||
|
||||
const [networkShells, setNetworkShells] = useMultiplayerState("shells", []);
|
||||
|
||||
const testing = getState("bananas");
|
||||
|
||||
// useEffect(() => {
|
||||
// setNetworkBananas(bananas);
|
||||
// }, [bananas]);
|
||||
|
||||
// useEffect(() => {
|
||||
// setNetworkShells(shells);
|
||||
// }, [shells]);
|
||||
|
||||
const {texture}= useLoader(LUTCubeLoader, "./cubicle-99.CUBE");
|
||||
|
||||
return (
|
||||
<>
|
||||
<PlayerController />
|
||||
{players.map((player) => (
|
||||
<PlayerController
|
||||
key={player.id}
|
||||
player={player}
|
||||
userPlayer={player.id === myPlayer()?.id}
|
||||
setNetworkBananas={setNetworkBananas}
|
||||
setNetworkShells={setNetworkShells}
|
||||
networkBananas={networkBananas}
|
||||
networkShells={networkShells}
|
||||
/>
|
||||
))}
|
||||
|
||||
{players.map((player) => (
|
||||
<PlayerDummies
|
||||
key={player.id}
|
||||
player={player}
|
||||
userPlayer={player.id === myPlayer()?.id}
|
||||
/>
|
||||
))}
|
||||
|
||||
<Paris position={[0, 0, 0]} />
|
||||
<Banana onCollide={onCollide} position={[-10, 1.8, -119]} />
|
||||
{/* <Banana onCollide={onCollide} position={[-10, 1.8, -119]} /> */}
|
||||
{/* <Shell position={[-20, 2, -119]} /> */}
|
||||
<ItemBox position={[-20, 2.5, -119]} />
|
||||
<Coin position={[-30, 2, -119]} />
|
||||
|
@ -42,27 +93,29 @@ export const Experience = () => {
|
|||
<Ground position={[0, 0, 0]} />
|
||||
<Environment resolution={256} preset="lobby" />
|
||||
|
||||
|
||||
|
||||
{bananas.map((banana) => (
|
||||
{networkBananas.map((banana) => (
|
||||
<Banana
|
||||
key={banana.id}
|
||||
position={banana.position}
|
||||
banana={banana}
|
||||
setNetworkBananas={setNetworkBananas}
|
||||
networkBananas={networkBananas}
|
||||
id={banana.id}
|
||||
// rotation={banana.rotation}
|
||||
/>
|
||||
))}
|
||||
|
||||
{shells.map((shell) => (
|
||||
{networkShells.map((shell) => (
|
||||
<Shell
|
||||
key={shell.id}
|
||||
id={shell.id}
|
||||
position={shell.position}
|
||||
rotation={shell.rotation}
|
||||
setNetworkShells={setNetworkShells}
|
||||
networkShells={networkShells}
|
||||
|
||||
/>
|
||||
))}
|
||||
|
||||
<directionalLight
|
||||
{/* <directionalLight
|
||||
position={[10, 50, -30]}
|
||||
intensity={1}
|
||||
shadow-bias={-0.0001}
|
||||
|
@ -72,7 +125,7 @@ export const Experience = () => {
|
|||
shadow-camera-top={300}
|
||||
shadow-camera-bottom={-300}
|
||||
castShadow
|
||||
/>
|
||||
/> */}
|
||||
|
||||
<EffectComposer
|
||||
multisampling={0}
|
||||
|
@ -88,11 +141,10 @@ export const Experience = () => {
|
|||
luminanceSmoothing={0.01}
|
||||
intensity={0.5}
|
||||
/>
|
||||
|
||||
<TiltShift2 />
|
||||
<ChromaticAberration offset={[0.0006, 0.0006]} />
|
||||
<HueSaturation saturation={0.1} />
|
||||
<Vignette eskil={false} offset={0.1} darkness={0.4} />
|
||||
{/* <ChromaticAberration offset={[0.0006, 0.0006]} /> */}
|
||||
<HueSaturation saturation={0.05} />
|
||||
{/* <Vignette eskil={false} offset={0.1} darkness={0.4} /> */}
|
||||
</EffectComposer>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -3,13 +3,9 @@ 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 { useFrame, useThree, extend } from "@react-three/fiber";
|
||||
import { useRef, useState, useEffect, useCallback } from "react";
|
||||
import * as THREE from "three";
|
||||
|
||||
|
@ -26,8 +22,17 @@ import FakeGlowMaterial from "./ShaderMaterials/FakeGlow/FakeGlowMaterial";
|
|||
import { HitParticles } from "./Particles/hits/HitParticles";
|
||||
import { CoinParticles } from "./Particles/coins/CoinParticles";
|
||||
import { ItemParticles } from "./Particles/items/ItemParticles";
|
||||
import { geometry } from "maath";
|
||||
extend(geometry);
|
||||
|
||||
export const PlayerController = () => {
|
||||
export const PlayerController = ({
|
||||
player,
|
||||
userPlayer,
|
||||
setNetworkBananas,
|
||||
setNetworkShells,
|
||||
networkBananas,
|
||||
networkShells,
|
||||
}) => {
|
||||
const upPressed = useKeyboardControls((state) => state[Controls.up]);
|
||||
const downPressed = useKeyboardControls((state) => state[Controls.down]);
|
||||
const leftPressed = useKeyboardControls((state) => state[Controls.left]);
|
||||
|
@ -83,13 +88,13 @@ export const PlayerController = () => {
|
|||
const downDirection = new THREE.Vector3(0, -1, 0);
|
||||
const [shouldLaunch, setShouldLaunch] = useState(false);
|
||||
const effectiveBoost = useRef(0);
|
||||
const text = useRef();
|
||||
|
||||
|
||||
const { actions, shouldSlowDown, item, bananas, coins} = useStore();
|
||||
const { actions, shouldSlowDown, item, bananas, coins, id } = useStore();
|
||||
const slowDownDuration = useRef(1500);
|
||||
|
||||
|
||||
useFrame(({ pointer, clock }, delta) => {
|
||||
if (player.id !== id) return;
|
||||
const time = clock.getElapsedTime();
|
||||
if (!body.current && !mario.current) return;
|
||||
engineSound.current.setVolume(currentSpeed / 300 + 0.2);
|
||||
|
@ -128,16 +133,15 @@ export const PlayerController = () => {
|
|||
steeringAngle = currentSteeringSpeed * -pointer.x;
|
||||
targetXPosition = -camMaxOffset * -pointer.x;
|
||||
} else if (driftLeft.current && !driftRight.current) {
|
||||
steeringAngle = currentSteeringSpeed * -(pointer.x - 0.5);
|
||||
steeringAngle = currentSteeringSpeed * -(pointer.x - 1);
|
||||
targetXPosition = -camMaxOffset * -pointer.x;
|
||||
} else if (driftRight.current && !driftLeft.current) {
|
||||
steeringAngle = currentSteeringSpeed * -(pointer.x + 0.5);
|
||||
steeringAngle = currentSteeringSpeed * -(pointer.x + 1);
|
||||
targetXPosition = -camMaxOffset * -pointer.x;
|
||||
}
|
||||
// ACCELERATING
|
||||
const shouldSlow = actions.getShouldSlowDown();
|
||||
|
||||
|
||||
if (upPressed && currentSpeed < maxSpeed) {
|
||||
// Accelerate the kart within the maximum speed limit
|
||||
setCurrentSpeed(
|
||||
|
@ -164,7 +168,9 @@ export const PlayerController = () => {
|
|||
}
|
||||
}
|
||||
if (shouldSlow) {
|
||||
setCurrentSpeed(Math.max(currentSpeed - decceleration * 2 * delta * 144, 0));
|
||||
setCurrentSpeed(
|
||||
Math.max(currentSpeed - decceleration * 2 * delta * 144, 0)
|
||||
);
|
||||
setCurrentSteeringSpeed(0);
|
||||
slowDownDuration.current -= 1500 * delta;
|
||||
setShouldLaunch(true);
|
||||
|
@ -173,12 +179,8 @@ export const PlayerController = () => {
|
|||
slowDownDuration.current = 1500;
|
||||
setShouldLaunch(false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// REVERSING
|
||||
if (downPressed && currentSpeed < -maxSpeed) {
|
||||
setCurrentSpeed(
|
||||
|
@ -235,7 +237,7 @@ export const PlayerController = () => {
|
|||
if (isOnFloor.current && jumpForce.current > 0) {
|
||||
landingSound.current.play();
|
||||
}
|
||||
if (!isOnGround && jumpForce.current > 0 ) {
|
||||
if (!isOnGround && jumpForce.current > 0) {
|
||||
jumpForce.current -= 1 * delta * 144;
|
||||
}
|
||||
if (!jumpPressed) {
|
||||
|
@ -282,7 +284,7 @@ export const PlayerController = () => {
|
|||
driftForce.current = 0.4;
|
||||
mario.current.rotation.y = THREE.MathUtils.lerp(
|
||||
mario.current.rotation.y,
|
||||
steeringAngle * 50 + 0.5,
|
||||
steeringAngle * 25 + 0.4,
|
||||
0.05 * delta * 144
|
||||
);
|
||||
accumulatedDriftPower.current += 0.1 * (steeringAngle + 1) * delta * 144;
|
||||
|
@ -292,7 +294,7 @@ export const PlayerController = () => {
|
|||
driftForce.current = 0.4;
|
||||
mario.current.rotation.y = THREE.MathUtils.lerp(
|
||||
mario.current.rotation.y,
|
||||
-(-steeringAngle * 50 + 0.5),
|
||||
-(-steeringAngle * 25 + 0.4),
|
||||
0.05 * delta * 144
|
||||
);
|
||||
accumulatedDriftPower.current += 0.1 * (-steeringAngle + 1) * delta * 144;
|
||||
|
@ -326,7 +328,6 @@ export const PlayerController = () => {
|
|||
if (driftLeft.current || driftRight.current) {
|
||||
const oscillation = Math.sin(time * 1000) * 0.1;
|
||||
const vibration = oscillation + 0.9;
|
||||
|
||||
if (turboColor === 0xffffff) {
|
||||
setScale(vibration * 0.8);
|
||||
} else {
|
||||
|
@ -353,7 +354,7 @@ export const PlayerController = () => {
|
|||
setCurrentSpeed(boostSpeed);
|
||||
effectiveBoost.current -= 1 * delta * 144;
|
||||
targetZPosition = 10;
|
||||
if(!turboSound.current.isPlaying) turboSound.current.play();
|
||||
if (!turboSound.current.isPlaying) turboSound.current.play();
|
||||
driftTwoSound.current.play();
|
||||
driftBlueSound.current.stop();
|
||||
driftOrangeSound.current.stop();
|
||||
|
@ -396,10 +397,10 @@ export const PlayerController = () => {
|
|||
|
||||
// MISC
|
||||
|
||||
if(resetPressed) {
|
||||
body.current.setTranslation({x: 8, y: 2, z: -119});
|
||||
body.current.setLinvel({x: 0, y: 0, z: 0});
|
||||
body.current.setAngvel({x: 0, y: 0, z: 0});
|
||||
if (resetPressed) {
|
||||
body.current.setTranslation({ x: 8, y: 2, z: -119 });
|
||||
body.current.setLinvel({ x: 0, y: 0, z: 0 });
|
||||
body.current.setAngvel({ x: 0, y: 0, z: 0 });
|
||||
setCurrentSpeed(0);
|
||||
setCurrentSteeringSpeed(0);
|
||||
setIsBoosting(false);
|
||||
|
@ -410,63 +411,66 @@ export const PlayerController = () => {
|
|||
kart.current.rotation.y = Math.PI / 2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ITEMS
|
||||
|
||||
if(shootPressed && item === "banana") {
|
||||
const distanceBehind = 2; // Adjust this value as needed
|
||||
const scaledBackwardDirection = forwardDirection.multiplyScalar(distanceBehind);
|
||||
if (shootPressed && item === "banana") {
|
||||
const distanceBehind = 2;
|
||||
const scaledBackwardDirection =
|
||||
forwardDirection.multiplyScalar(distanceBehind);
|
||||
|
||||
// Get the current position of the kart
|
||||
const kartPosition = new THREE.Vector3(...vec3(body.current.translation()));
|
||||
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();
|
||||
setNetworkBananas([...networkBananas, newBanana]);
|
||||
|
||||
actions.useItem();
|
||||
}
|
||||
|
||||
if(shootPressed && item === "shell") {
|
||||
const distanceBehind = -1; // Adjust this value as needed
|
||||
const scaledBackwardDirection = forwardDirection.multiplyScalar(distanceBehind);
|
||||
if (shootPressed && item === "shell") {
|
||||
const distanceBehind = -2;
|
||||
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
|
||||
rotation: kartRotation,
|
||||
};
|
||||
actions.addShell(newShell);
|
||||
setNetworkShells([...networkShells, newShell]);
|
||||
actions.useItem();
|
||||
|
||||
}
|
||||
|
||||
if(shootPressed && item === "mushroom") {
|
||||
if (shootPressed && item === "mushroom") {
|
||||
setIsBoosting(true);
|
||||
effectiveBoost.current = 300;
|
||||
actions.useItem();
|
||||
}
|
||||
|
||||
|
||||
player.setState("position", body.current.translation());
|
||||
player.setState("rotation", kartRotation + mario.current.rotation.y);
|
||||
player.setState("isBoosting", isBoosting);
|
||||
player.setState("shouldLaunch", shouldLaunch);
|
||||
player.setState("turboColor", turboColor);
|
||||
player.setState("scale", scale);
|
||||
player.setState("bananas", bananas);
|
||||
});
|
||||
|
||||
return (
|
||||
return player.id === id ? (
|
||||
<group>
|
||||
<RigidBody
|
||||
ref={body}
|
||||
|
@ -476,19 +480,19 @@ export const PlayerController = () => {
|
|||
mass={3}
|
||||
ccd
|
||||
name="player"
|
||||
type={player.id === id ? "dynamic" : "kinematic"}
|
||||
>
|
||||
<BallCollider
|
||||
args={[0.5]}
|
||||
mass={3}
|
||||
onCollisionEnter={({other}) => {
|
||||
onCollisionEnter={({ other }) => {
|
||||
isOnFloor.current = true;
|
||||
setIsOnGround(true);
|
||||
}}
|
||||
onCollisionExit={({other}) => {
|
||||
onCollisionExit={({ other }) => {
|
||||
isOnFloor.current = false;
|
||||
setIsOnGround(false);
|
||||
}}
|
||||
|
||||
/>
|
||||
</RigidBody>
|
||||
|
||||
|
@ -498,9 +502,10 @@ export const PlayerController = () => {
|
|||
currentSpeed={currentSpeed}
|
||||
steeringAngleWheels={steeringAngleWheels}
|
||||
isBoosting={isBoosting}
|
||||
shouldLaunch={shouldLaunch}
|
||||
/>
|
||||
<CoinParticles coins={coins}/>
|
||||
<ItemParticles item={item}/>
|
||||
<CoinParticles coins={coins} />
|
||||
<ItemParticles item={item} />
|
||||
<mesh position={[0.6, 0.05, 0.5]} scale={scale}>
|
||||
<sphereGeometry args={[0.05, 16, 16]} />
|
||||
<meshStandardMaterial
|
||||
|
@ -539,7 +544,6 @@ export const PlayerController = () => {
|
|||
glowSharpness={1}
|
||||
/>
|
||||
</mesh>
|
||||
|
||||
{/* <FlameParticles isBoosting={isBoosting} /> */}
|
||||
<DriftParticlesLeft turboColor={turboColor} scale={scale} />
|
||||
<DriftParticlesRight turboColor={turboColor} scale={scale} />
|
||||
|
@ -563,7 +567,7 @@ export const PlayerController = () => {
|
|||
png="./particles/star.png"
|
||||
turboColor={turboColor}
|
||||
/>
|
||||
<HitParticles shouldLaunch={shouldLaunch}/>
|
||||
<HitParticles shouldLaunch={shouldLaunch} />
|
||||
</group>
|
||||
|
||||
{/* <ContactShadows frames={1} /> */}
|
||||
|
@ -631,5 +635,5 @@ export const PlayerController = () => {
|
|||
/>
|
||||
</group>
|
||||
</group>
|
||||
);
|
||||
) : null;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,269 @@
|
|||
import { Controls } from "../App";
|
||||
import { BallCollider, RigidBody, useRapier, vec3 } from "@react-three/rapier";
|
||||
import {
|
||||
useKeyboardControls,
|
||||
PerspectiveCamera,
|
||||
ContactShadows,
|
||||
Sphere,
|
||||
OrbitControls,
|
||||
Trail,
|
||||
PositionalAudio,
|
||||
Text,
|
||||
Billboard,
|
||||
} from "@react-three/drei";
|
||||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import { useRef, useState, useEffect, useCallback } from "react";
|
||||
import * as THREE from "three";
|
||||
|
||||
import { Mario } from "./models/characters/Mario_kart";
|
||||
import { DriftParticlesLeft } from "./Particles/drifts/DriftParticlesLeft";
|
||||
import { DriftParticlesRight } from "./Particles/drifts/DriftParticlesRight";
|
||||
|
||||
import { PointParticle } from "./Particles/drifts/PointParticle";
|
||||
|
||||
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/hits/HitParticles";
|
||||
import { CoinParticles } from "./Particles/coins/CoinParticles";
|
||||
import { ItemParticles } from "./Particles/items/ItemParticles";
|
||||
import { isHost } from "playroomkit";
|
||||
import { Banana } from "./models/items/Banana_peel_mario_kart";
|
||||
|
||||
export const PlayerDummies = ( { player, userPlayer }) => {
|
||||
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 shootPressed = useKeyboardControls((state) => state[Controls.shoot]);
|
||||
const resetPressed = useKeyboardControls((state) => state[Controls.reset]);
|
||||
|
||||
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 driftSound = useRef();
|
||||
const driftTwoSound = useRef();
|
||||
const driftOrangeSound = useRef();
|
||||
const driftPurpleSound = useRef();
|
||||
const driftBlueSound = useRef();
|
||||
const jumpSound = useRef();
|
||||
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 effectiveBoost = useRef(0);
|
||||
const [networkBananas, setNetworkBananas] = useState([]);
|
||||
const [networkShells, setNetworkShells] = useState([]);
|
||||
|
||||
|
||||
const { actions, shouldSlowDown, item, coins, id} = useStore();
|
||||
const slowDownDuration = useRef(1500);
|
||||
|
||||
useFrame((state, delta) => {
|
||||
const bodyPosition = player.getState("position");
|
||||
const bodyRotation = player.getState("rotation");
|
||||
setIsBoosting(player.getState("isBoosting"));
|
||||
setShouldLaunch(player.getState("shouldLaunch"));
|
||||
setTurboColor(player.getState("turboColor"));
|
||||
setScale(player.getState("scale"));
|
||||
|
||||
|
||||
|
||||
|
||||
if(bodyPosition && bodyRotation && kart.current && mario.current){
|
||||
kart.current.position.set(bodyPosition.x, bodyPosition.y -.5, bodyPosition.z);
|
||||
kart.current.rotation.set(0, bodyRotation, 0);
|
||||
body.current.setTranslation([bodyPosition.x, bodyPosition.y, bodyPosition.z]);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return player.id != id? (
|
||||
<>
|
||||
<Billboard>
|
||||
<Text font={"./fonts/HK.ttf"} ref={text} fontSize={0.4} outlineWidth={0.03} position={[0, 2, 0]}>{player.state.profile.name}</Text>
|
||||
</Billboard>
|
||||
<group>
|
||||
<RigidBody
|
||||
type="kinematic"
|
||||
ref={body}
|
||||
position={[0, 0, 0]}
|
||||
rotation={[0, 0, 0]}
|
||||
colliders={false}
|
||||
name="player"
|
||||
>
|
||||
<BallCollider args={[0.5]} />
|
||||
</RigidBody>
|
||||
|
||||
<group ref={kart} rotation={[0, Math.PI / 2, 0]}>
|
||||
<group ref={mario}>
|
||||
<Mario
|
||||
currentSpeed={currentSpeed}
|
||||
steeringAngleWheels={steeringAngleWheels}
|
||||
isBoosting={isBoosting}
|
||||
shouldLaunch={shouldLaunch}
|
||||
/>
|
||||
<CoinParticles coins={coins}/>
|
||||
<ItemParticles item={item}/>
|
||||
<mesh position={[0.6, 0.05, 0.5]} scale={scale}>
|
||||
<sphereGeometry args={[0.05, 16, 16]} />
|
||||
<meshStandardMaterial
|
||||
emissive={turboColor}
|
||||
toneMapped={false}
|
||||
emissiveIntensity={100}
|
||||
transparent
|
||||
opacity={0.4}
|
||||
/>
|
||||
</mesh>
|
||||
<mesh position={[0.6, 0.05, 0.5]} scale={scale * 10}>
|
||||
<sphereGeometry args={[0.05, 16, 16]} />
|
||||
<FakeGlowMaterial
|
||||
falloff={3}
|
||||
glowInternalRadius={1}
|
||||
glowColor={turboColor}
|
||||
glowSharpness={1}
|
||||
/>
|
||||
</mesh>
|
||||
<mesh position={[-0.6, 0.05, 0.5]} scale={scale}>
|
||||
<sphereGeometry args={[0.05, 16, 16]} />
|
||||
<meshStandardMaterial
|
||||
emissive={turboColor}
|
||||
toneMapped={false}
|
||||
emissiveIntensity={100}
|
||||
transparent
|
||||
opacity={0.4}
|
||||
/>
|
||||
</mesh>
|
||||
<mesh position={[-0.6, 0.05, 0.5]} scale={scale * 10}>
|
||||
<sphereGeometry args={[0.05, 16, 16]} />
|
||||
<FakeGlowMaterial
|
||||
falloff={3}
|
||||
glowInternalRadius={1}
|
||||
glowColor={turboColor}
|
||||
glowSharpness={1}
|
||||
/>
|
||||
</mesh>
|
||||
|
||||
{/* <FlameParticles isBoosting={isBoosting} /> */}
|
||||
<DriftParticlesLeft turboColor={turboColor} scale={scale} />
|
||||
<DriftParticlesRight turboColor={turboColor} scale={scale} />
|
||||
<PointParticle
|
||||
position={[-0.6, 0.05, 0.5]}
|
||||
png="./particles/circle.png"
|
||||
turboColor={turboColor}
|
||||
/>
|
||||
<PointParticle
|
||||
position={[0.6, 0.05, 0.5]}
|
||||
png="./particles/circle.png"
|
||||
turboColor={turboColor}
|
||||
/>
|
||||
<PointParticle
|
||||
position={[-0.6, 0.05, 0.5]}
|
||||
png="./particles/star.png"
|
||||
turboColor={turboColor}
|
||||
/>
|
||||
<PointParticle
|
||||
position={[0.6, 0.05, 0.5]}
|
||||
png="./particles/star.png"
|
||||
turboColor={turboColor}
|
||||
/>
|
||||
<HitParticles shouldLaunch={shouldLaunch}/>
|
||||
</group>
|
||||
|
||||
{/* <ContactShadows frames={1} /> */}
|
||||
<PositionalAudio
|
||||
ref={engineSound}
|
||||
url="./sounds/engine.wav"
|
||||
autoplay
|
||||
loop
|
||||
distance={1000}
|
||||
/>
|
||||
<PositionalAudio
|
||||
ref={driftSound}
|
||||
url="./sounds/drifting.mp3"
|
||||
loop
|
||||
distance={1000}
|
||||
/>
|
||||
<PositionalAudio
|
||||
ref={driftTwoSound}
|
||||
url="./sounds/driftingTwo.mp3"
|
||||
loop
|
||||
distance={1000}
|
||||
/>
|
||||
<PositionalAudio
|
||||
ref={driftOrangeSound}
|
||||
url="./sounds/driftOrange.wav"
|
||||
loop={false}
|
||||
distance={1000}
|
||||
/>
|
||||
<PositionalAudio
|
||||
ref={driftBlueSound}
|
||||
url="./sounds/driftBlue.wav"
|
||||
loop={false}
|
||||
distance={1000}
|
||||
/>
|
||||
|
||||
<PositionalAudio
|
||||
ref={driftPurpleSound}
|
||||
url="./sounds/driftPurple.wav"
|
||||
loop={false}
|
||||
distance={1000}
|
||||
/>
|
||||
<PositionalAudio
|
||||
ref={jumpSound}
|
||||
url="./sounds/jump.mp3"
|
||||
loop={false}
|
||||
distance={1000}
|
||||
/>
|
||||
<PositionalAudio
|
||||
ref={landingSound}
|
||||
url="./sounds/landing.wav"
|
||||
loop={false}
|
||||
distance={1000}
|
||||
/>
|
||||
<PositionalAudio
|
||||
ref={turboSound}
|
||||
url="./sounds/turbo.wav"
|
||||
loop={false}
|
||||
distance={1000}
|
||||
/>
|
||||
</group>
|
||||
</group>
|
||||
</>
|
||||
) : null;
|
||||
};
|
|
@ -11,7 +11,7 @@ import FakeFlame from '../../ShaderMaterials/FakeFlame/FakeFlame'
|
|||
import { useStore } from '../../store'
|
||||
import gsap from 'gsap'
|
||||
|
||||
export function Mario({ currentSpeed, steeringAngleWheels, isBoosting, ...props }) {
|
||||
export function Mario({ currentSpeed, steeringAngleWheels, isBoosting, shouldLaunch, ...props }) {
|
||||
const { nodes, materials } = useGLTF('./models/characters/mariokarttest.glb')
|
||||
|
||||
const frontLeftWheel = useRef()
|
||||
|
@ -39,11 +39,11 @@ export function Mario({ currentSpeed, steeringAngleWheels, isBoosting, ...props
|
|||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldSlow) {
|
||||
if (shouldLaunch) {
|
||||
gsap.to(mario.current.rotation, {duration: 1.5, y: Math.PI * 3})
|
||||
mario.current.rotation.set(0, 0, 0);
|
||||
}
|
||||
}, [shouldSlow])
|
||||
}, [shouldLaunch])
|
||||
return (
|
||||
<group
|
||||
{...props}
|
||||
|
|
|
@ -8,13 +8,13 @@ Source: https://sketchfab.com/3d-models/banana-peel-mario-kart-c7fd163741614859b
|
|||
Title: Banana Peel (Mario Kart)
|
||||
*/
|
||||
|
||||
import React, { useRef } from 'react'
|
||||
import React, { useEffect, 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, id, ...props}) {
|
||||
export function Banana({onCollide, id, position, setNetworkBananas, networkBananas}) {
|
||||
const { nodes, materials } = useGLTF('./models/items/banana_peel_mario_kart-transformed.glb');
|
||||
const rigidBody = useRef();
|
||||
const ref = useRef();
|
||||
|
@ -28,13 +28,13 @@ export function Banana({onCollide, id, ...props}) {
|
|||
<RigidBody
|
||||
ref={rigidBody}
|
||||
type='fixed'
|
||||
position={props.position}
|
||||
position={[position.x, position.y, position.z]}
|
||||
sensor
|
||||
onIntersectionEnter={({other}) => {
|
||||
if(other.rigidBodyObject.name === "player"){
|
||||
actions.setShouldSlowDown(true);
|
||||
setNetworkBananas(networkBananas.filter((banana) => banana.id !== id));
|
||||
}
|
||||
actions.removeBananaById(id);
|
||||
}}
|
||||
colliders={false}
|
||||
name='banana'
|
||||
|
@ -43,7 +43,7 @@ export function Banana({onCollide, id, ...props}) {
|
|||
|
||||
</RigidBody>
|
||||
|
||||
<group {...props} ref={ref} scale={scale} dispose={null}>
|
||||
<group position={[position.x, position.y, position.z]} 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]} />
|
||||
|
|
|
@ -7,45 +7,70 @@ Source: https://sketchfab.com/3d-models/mario-shell-red-76a81ff57398423d80800259
|
|||
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';
|
||||
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";
|
||||
import { useStore } from "../../store";
|
||||
|
||||
export function Shell(props) {
|
||||
const { nodes, materials } = useGLTF('./models/items/mario_shell_red.glb')
|
||||
export function Shell({ id, position, rotation, setNetworkShells, networkShells, ...props}) {
|
||||
const { nodes, materials } = useGLTF("./models/items/mario_shell_red.glb");
|
||||
const rigidBody = useRef();
|
||||
const ref = useRef();
|
||||
|
||||
const shell_speed = 100;
|
||||
const {actions} = useStore();
|
||||
|
||||
useEffect(() => {
|
||||
const velocity = {
|
||||
x : -Math.sin(props.rotation) * shell_speed,
|
||||
y : 0,
|
||||
z : -Math.cos(props.rotation) * shell_speed,
|
||||
x: -Math.sin(rotation) * shell_speed,
|
||||
y: 0,
|
||||
z: -Math.cos(rotation) * shell_speed,
|
||||
};
|
||||
|
||||
rigidBody.current.setLinvel(velocity, true);
|
||||
},[]);
|
||||
}, []);
|
||||
|
||||
useFrame((state, delta) => {
|
||||
if(rigidBody.current && ref.current){
|
||||
const rigidBodyPosition = rigidBody.current.translation();
|
||||
ref.current.position.set(rigidBodyPosition.x, rigidBodyPosition.y, rigidBodyPosition.z);
|
||||
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}>
|
||||
<RigidBody
|
||||
ref={rigidBody}
|
||||
type="dynamic"
|
||||
position={[position.x, position.y, position.z]}
|
||||
name="shell"
|
||||
colliders={false}
|
||||
onCollisionEnter={(other) => {
|
||||
if (other.rigidBodyObject.name === "player") {
|
||||
actions.setShouldSlowDown(true);
|
||||
setNetworkShells(
|
||||
networkShells.filter((shell) => shell.id !== id)
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<BallCollider args={[0.5]} />
|
||||
|
||||
</RigidBody>
|
||||
<mesh ref={ref} geometry={nodes.defaultMaterial.geometry} material={materials.Shell} rotation={[-Math.PI / 2, 0, 0]} scale={0.6} />
|
||||
<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')
|
||||
useGLTF.preload("./models/items/mario_shell_red.glb");
|
||||
|
|
|
@ -20,11 +20,13 @@ export const useStore = create((set, get) => ({
|
|||
pastPositions: [],
|
||||
shouldSlowdown: false,
|
||||
bananas: [],
|
||||
items: ["banana", "shell", "mushroom"],
|
||||
items: ["mushroom", "shell", "banana"],
|
||||
item: "",
|
||||
shells: [],
|
||||
skids: [],
|
||||
coins : 0,
|
||||
players : [],
|
||||
id : "",
|
||||
addPastPosition: (position) => {
|
||||
set((state) => ({
|
||||
pastPositions: [position, ...state.pastPositions.slice(0, 499)],
|
||||
|
@ -87,6 +89,9 @@ export const useStore = create((set, get) => ({
|
|||
bananas: state.bananas.filter((b) => b.id !== id),
|
||||
}));
|
||||
},
|
||||
setBananas: (bananas) => {
|
||||
set({ bananas });
|
||||
},
|
||||
setItem:() => {
|
||||
set((state) => ({
|
||||
item: state.items[Math.floor(Math.random() * state.items.length)],
|
||||
|
@ -122,6 +127,19 @@ export const useStore = create((set, get) => ({
|
|||
coins: state.coins - 1,
|
||||
}));
|
||||
},
|
||||
addPlayer : (player) => {
|
||||
set((state) => ({
|
||||
players: [...state.players, player],
|
||||
}));
|
||||
},
|
||||
removePlayer : (player) => {
|
||||
set((state) => ({
|
||||
players: state.players.filter((p) => p.id !== player.id),
|
||||
}));
|
||||
},
|
||||
setId : (id) => {
|
||||
set({id});
|
||||
}
|
||||
},
|
||||
|
||||
}));
|
||||
|
|
|
@ -110,3 +110,14 @@ body::-webkit-scrollbar {
|
|||
transform: scale(1.2);
|
||||
}
|
||||
}
|
||||
|
||||
.annotation{
|
||||
display:flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
background:none;
|
||||
backdrop-filter: blur(10px);
|
||||
pointer-events: none;
|
||||
|
||||
}
|
Loading…
Reference in New Issue