diff --git a/package-lock.json b/package-lock.json
index 0a91948..1d49092 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/package.json b/package.json
index 0aae4ba..cca01c6 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/src/App.jsx b/src/App.jsx
index 5906eb4..c4aeb19 100644
--- a/src/App.jsx
+++ b/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,26 @@ function App() {
[]
)
+ const { actions } = useStore();
+ const start = async () => {
+ await insertCoin();
+
+ onPlayerJoin((state) => {
+ actions.addPlayer(state);
+ console.log('player joined', state);
+ actions.setId(state.id);
+
+ state.onQuit(() => {
+ actions.removePlayer(state);
+ console.log('player quit', state);
+ });
+ });
+ }
+
+ useEffect(() => {
+ start();
+ }, [])
+
return (
<>
diff --git a/src/HUD.jsx b/src/HUD.jsx
index ef2885d..38d9752 100644
--- a/src/HUD.jsx
+++ b/src/HUD.jsx
@@ -40,7 +40,6 @@ export const HUD = () => {
default:
setImage("");
}
- console.log(item);
}, [item]);
return (
diff --git a/src/components/Experience.jsx b/src/components/Experience.jsx
index bd50059..2b16f7f 100644
--- a/src/components/Experience.jsx
+++ b/src/components/Experience.jsx
@@ -23,16 +23,32 @@ 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, insertCoin, myPlayer, onPlayerJoin, useMultiplayerState } from "playroomkit";
+import { PlayerDummies } from "./PlayerDummies";
+import { useEffect } from "react";
+import { useFrame } from "@react-three/fiber";
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", []);
+
return (
<>
-
+ {players.map((player) => (
+
+ ))}
+
+ {players.map((player) => (
+
+ ))}
+
+
{/* */}
@@ -44,7 +60,7 @@ export const Experience = () => {
- {bananas.map((banana) => (
+ {/* {bananas.map((banana) => (
{
id={banana.id}
// rotation={banana.rotation}
/>
- ))}
+ ))} */}
{shells.map((shell) => (
{
-export const PlayerController = () => {
const upPressed = useKeyboardControls((state) => state[Controls.up]);
const downPressed = useKeyboardControls((state) => state[Controls.down]);
const leftPressed = useKeyboardControls((state) => state[Controls.left]);
@@ -85,11 +87,11 @@ export const PlayerController = () => {
const effectiveBoost = useRef(0);
- 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);
@@ -121,6 +123,8 @@ export const PlayerController = () => {
targetXPosition = 0;
1;
}
+
+
// mouse steering
@@ -464,9 +468,19 @@ export const PlayerController = () => {
}
+
+ 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 ?(
{
mass={3}
ccd
name="player"
+ type={player.id === id ? "dynamic" : "kinematic"}
>
{
/>
- );
+ ) : null;
};
diff --git a/src/components/PlayerDummies.jsx b/src/components/PlayerDummies.jsx
new file mode 100644
index 0000000..de572de
--- /dev/null
+++ b/src/components/PlayerDummies.jsx
@@ -0,0 +1,252 @@
+import { Controls } from "../App";
+import { BallCollider, RigidBody, useRapier, vec3 } from "@react-three/rapier";
+import {
+ useKeyboardControls,
+ PerspectiveCamera,
+ ContactShadows,
+ Sphere,
+ OrbitControls,
+ Trail,
+ PositionalAudio,
+} from "@react-three/drei";
+import { useFrame, useThree } from "@react-three/fiber";
+import { useRef, useState, useEffect, useCallback } from "react";
+import * as THREE from "three";
+
+import { 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);
+ }
+
+ });
+
+ return player.id != id? (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* */}
+
+
+
+
+
+
+
+
+
+ {/* */}
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ ) : null;
+};
diff --git a/src/components/store.jsx b/src/components/store.jsx
index a1e2bf1..187286c 100644
--- a/src/components/store.jsx
+++ b/src/components/store.jsx
@@ -20,11 +20,13 @@ export const useStore = create((set, get) => ({
pastPositions: [],
shouldSlowdown: false,
bananas: [],
- items: ["banana", "shell", "mushroom"],
+ items: ["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});
+ }
},
}));