feat(game): Added multiplayer mode
parent
b825b0fc20
commit
42680aa707
|
@ -23,34 +23,65 @@ 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 {
|
||||
RPC,
|
||||
getState,
|
||||
insertCoin,
|
||||
isHost,
|
||||
myPlayer,
|
||||
onPlayerJoin,
|
||||
useMultiplayerState,
|
||||
} from "playroomkit";
|
||||
import { PlayerDummies } from "./PlayerDummies";
|
||||
import { useEffect } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useFrame } from "@react-three/fiber";
|
||||
|
||||
export const Experience = () => {
|
||||
const onCollide = (event) => {
|
||||
console.log(event);
|
||||
};
|
||||
const { bananas, shells, players, id, actions} = useStore();
|
||||
const [networkBananas, setNetworkBananas] = useMultiplayerState("bananas", []);
|
||||
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]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{players.map((player) => (
|
||||
<PlayerController key={player.id} player={player} userPlayer={player.id === myPlayer()?.id} />
|
||||
))}
|
||||
|
||||
{players.map((player) => (
|
||||
<PlayerDummies key={player.id} player={player} userPlayer={player.id === myPlayer()?.id} />
|
||||
<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]} />
|
||||
|
@ -58,23 +89,25 @@ 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}
|
||||
|
||||
/>
|
||||
))}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ import { CoinParticles } from "./Particles/coins/CoinParticles";
|
|||
import { ItemParticles } from "./Particles/items/ItemParticles";
|
||||
import { isHost } from "playroomkit";
|
||||
|
||||
export const PlayerController = ( { player, userPlayer }) => {
|
||||
export const PlayerController = ( { player, userPlayer, setNetworkBananas, setNetworkShells, networkBananas, networkShells }) => {
|
||||
|
||||
const upPressed = useKeyboardControls((state) => state[Controls.up]);
|
||||
const downPressed = useKeyboardControls((state) => state[Controls.down]);
|
||||
|
@ -330,8 +330,7 @@ export const PlayerController = ( { player, userPlayer }) => {
|
|||
if (driftLeft.current || driftRight.current) {
|
||||
const oscillation = Math.sin(time * 1000) * 0.1;
|
||||
const vibration = oscillation + 0.9;
|
||||
|
||||
if (turboColor === 0xffffff) {
|
||||
if (turboColor === 0xffffff) {
|
||||
setScale(vibration * 0.8);
|
||||
} else {
|
||||
setScale(vibration);
|
||||
|
@ -419,36 +418,34 @@ export const PlayerController = ( { player, userPlayer }) => {
|
|||
// ITEMS
|
||||
|
||||
if(shootPressed && item === "banana") {
|
||||
const distanceBehind = 2; // Adjust this value as needed
|
||||
const distanceBehind = 2;
|
||||
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();
|
||||
setNetworkBananas([...networkBananas, newBanana]);
|
||||
|
||||
actions.useItem();
|
||||
}
|
||||
|
||||
if(shootPressed && item === "shell") {
|
||||
const distanceBehind = -1; // Adjust this value as needed
|
||||
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(),
|
||||
|
@ -456,7 +453,7 @@ export const PlayerController = ( { player, userPlayer }) => {
|
|||
player: true,
|
||||
rotation: kartRotation
|
||||
};
|
||||
actions.addShell(newShell);
|
||||
setNetworkShells([...networkShells, newShell]);
|
||||
actions.useItem();
|
||||
|
||||
}
|
||||
|
@ -513,6 +510,7 @@ export const PlayerController = ( { player, userPlayer }) => {
|
|||
currentSpeed={currentSpeed}
|
||||
steeringAngleWheels={steeringAngleWheels}
|
||||
isBoosting={isBoosting}
|
||||
shouldLaunch={shouldLaunch}
|
||||
/>
|
||||
<CoinParticles coins={coins}/>
|
||||
<ItemParticles item={item}/>
|
||||
|
|
|
@ -106,6 +106,7 @@ export const PlayerDummies = ( { player, userPlayer }) => {
|
|||
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]);
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -113,6 +114,16 @@ export const PlayerDummies = ( { player, userPlayer }) => {
|
|||
return player.id != id? (
|
||||
<>
|
||||
<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}>
|
||||
|
@ -120,6 +131,7 @@ export const PlayerDummies = ( { player, userPlayer }) => {
|
|||
currentSpeed={currentSpeed}
|
||||
steeringAngleWheels={steeringAngleWheels}
|
||||
isBoosting={isBoosting}
|
||||
shouldLaunch={shouldLaunch}
|
||||
/>
|
||||
<CoinParticles coins={coins}/>
|
||||
<ItemParticles item={item}/>
|
||||
|
|
|
@ -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) => {
|
||||
const rigidBodyPosition = rigidBody.current.translation();
|
||||
ref.current.position.set(rigidBodyPosition.x, rigidBodyPosition.y, rigidBodyPosition.z);
|
||||
ref.current.rotation.z += 0.2 * delta * 144;
|
||||
if(rigidBody.current && ref.current){
|
||||
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} />
|
||||
<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}
|
||||
/>
|
||||
</group>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
useGLTF.preload('./models/items/mario_shell_red.glb')
|
||||
useGLTF.preload("./models/items/mario_shell_red.glb");
|
||||
|
|
|
@ -20,7 +20,7 @@ export const useStore = create((set, get) => ({
|
|||
pastPositions: [],
|
||||
shouldSlowdown: false,
|
||||
bananas: [],
|
||||
items: ["banana"],
|
||||
items: ["mushroom"],
|
||||
item: "",
|
||||
shells: [],
|
||||
skids: [],
|
||||
|
|
Loading…
Reference in New Issue