Compare commits
1 Commits
main
...
useGamepad
Author | SHA1 | Date |
---|---|---|
Alex | a8cf0d1ca4 |
|
@ -1,27 +0,0 @@
|
|||
{
|
||||
"name": "Mario Kart Dev Container",
|
||||
"image": "mcr.microsoft.com/devcontainers/javascript-node",
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"eamodio.gitlens",
|
||||
"esbenp.prettier-vscode",
|
||||
"VisualStudioExptTeam.vscodeintellicode",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"dsznajder.es7-react-js-snippets",
|
||||
"antfu.vite",
|
||||
"meganrogge.template-string-converter",
|
||||
"ambar.bundle-size",
|
||||
"aaron-bond.better-comments"
|
||||
]
|
||||
}
|
||||
},
|
||||
"forwardPorts": [4000],
|
||||
"portsAttributes": {
|
||||
"4000": {
|
||||
"label": "Application",
|
||||
"onAutoForward": "notify"
|
||||
}
|
||||
},
|
||||
"postCreateCommand": "npm install"
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"$schema": "https://triplex.dev/config.schema.json",
|
||||
"components": ["../src/components/**/*.(j|t)sx"],
|
||||
"files": ["../src/components/**/*.(j|t)sx"],
|
||||
"provider": "./provider.tsx",
|
||||
"assetsDir": "models"
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
import React from "react";
|
||||
import { Physics } from "@react-three/rapier";
|
||||
|
||||
export default function Provider({
|
||||
children,
|
||||
physicsDisabled = true,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
physicsDisabled?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<Physics gravity={[0, -90, 0]} timeStep="vary" paused={physicsDisabled}>
|
||||
{children}
|
||||
</Physics>
|
||||
);
|
||||
}
|
21
LICENSE
|
@ -1,21 +0,0 @@
|
|||
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.
|
94
README.md
|
@ -1,94 +0,0 @@
|
|||
# Mario Kart 3.js - JavaScript/WebGL Mario Kart
|
||||
|
||||
[Link](https://mario-kart-3-js.vercel.app/)
|
||||
|
||||
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/Lunakepio/Mario-Kart-3.js)
|
||||
|
||||
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
|
||||
|
||||
Fork the repository
|
||||
|
||||
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 <kbd>W</kbd> 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 <kbd>E</kbd> key to use the current item.
|
||||
|
||||
- Press <kbd>R</kbd> 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.
|
||||
|
||||
## How to use (Editor)
|
||||
|
||||
- [Download Triplex](https://triplex.dev/download)
|
||||
|
||||
- Open this project in Triplex from the projects root directory
|
||||
|
||||
- Iterate on individual components, set props, have some fun
|
||||
|
||||
- [Learn more about Triplex](https://triplex.dev/docs/get-started/user-interface)
|
||||
|
||||
## 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
|
||||
|
||||
- [x] 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
|
||||
|
||||
- [ ] Add Minimap
|
||||
|
||||
- [ ] 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)
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
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')
|
|
@ -13,14 +13,11 @@
|
|||
"@react-three/postprocessing": "^2.15.11",
|
||||
"@react-three/rapier": "^1.2.1",
|
||||
"gsap": "^3.12.5",
|
||||
"joymap": "^2.2.4",
|
||||
"leva": "^0.9.35",
|
||||
"playroomkit": "^0.0.66",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-gamepad": "^1.0.3",
|
||||
"react-joystick-component": "^6.2.1",
|
||||
"three": "^0.160.1",
|
||||
"three-mesh-bvh": "^0.7.0",
|
||||
"zustand": "^4.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -1397,9 +1394,9 @@
|
|||
"peer": true
|
||||
},
|
||||
"node_modules/@types/three": {
|
||||
"version": "0.161.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.161.2.tgz",
|
||||
"integrity": "sha512-DazpZ+cIfBzbW/p0zm6G8CS03HBMd748A3R1ZOXHpqaXZLv2I5zNgQUrRG//UfJ6zYFp2cUoCQaOLaz8ubH07w==",
|
||||
"version": "0.160.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.160.0.tgz",
|
||||
"integrity": "sha512-jWlbUBovicUKaOYxzgkLlhkiEQJkhCVvg4W2IYD2trqD2om3VK4DGLpHH5zQHNr7RweZK/5re/4IVhbhvxbV9w==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/stats.js": "*",
|
||||
|
@ -1865,6 +1862,11 @@
|
|||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||
},
|
||||
"node_modules/fast-memoize": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz",
|
||||
"integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw=="
|
||||
},
|
||||
"node_modules/fflate": {
|
||||
"version": "0.6.10",
|
||||
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz",
|
||||
|
@ -2143,6 +2145,16 @@
|
|||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/joymap": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/joymap/-/joymap-2.2.4.tgz",
|
||||
"integrity": "sha512-5N0VMbym49AwrfUz0vD6tE++I50SFjBYtwcJsdgE086GgAraGB2YQFsgVj+cG2fd8eUFmK+8U36Ecud3/UYTRg==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.9.2",
|
||||
"fast-memoize": "^2.5.2",
|
||||
"lodash": "^4.17.15"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
|
@ -2425,15 +2437,6 @@
|
|||
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/playroomkit": {
|
||||
"version": "0.0.66",
|
||||
"resolved": "https://registry.npmjs.org/playroomkit/-/playroomkit-0.0.66.tgz",
|
||||
"integrity": "sha512-lBYSLR/0AebQhWteMgkXiMXyMPxMqGz2uptA3QrBig4NCn5r3ViIXWIFmsdbLSG9spKrFPVTaYRClUq3fSCxDw==",
|
||||
"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",
|
||||
|
@ -2595,28 +2598,11 @@
|
|||
"react": ">= 16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-gamepad": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/react-gamepad/-/react-gamepad-1.0.3.tgz",
|
||||
"integrity": "sha512-gMwITmfoHtCaMFpDaEshcjeibHAgynXD28NnS2pa+dG+stwNoN66YDVizN7GfyIrYiW5Ft1ubRxs6/2xW9sRhQ==",
|
||||
"peerDependencies": {
|
||||
"react": ">=15.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/react-joystick-component": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/react-joystick-component/-/react-joystick-component-6.2.1.tgz",
|
||||
"integrity": "sha512-0G5Y5aX4hNuXB3xJCwz6Q+nYQOtC6kprNGKmZxmfoPvhepNYUiid0DbLEGZxmr/UKip3S/LUbcQUobtRCuB8IQ==",
|
||||
"peerDependencies": {
|
||||
"react": ">=17.0.2",
|
||||
"react-dom": ">=17.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/react-merge-refs": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-merge-refs/-/react-merge-refs-1.1.0.tgz",
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host",
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
|
@ -14,14 +14,11 @@
|
|||
"@react-three/postprocessing": "^2.15.11",
|
||||
"@react-three/rapier": "^1.2.1",
|
||||
"gsap": "^3.12.5",
|
||||
"joymap": "^2.2.4",
|
||||
"leva": "^0.9.35",
|
||||
"playroomkit": "^0.0.66",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-gamepad": "^1.0.3",
|
||||
"react-joystick-component": "^6.2.1",
|
||||
"three": "^0.160.1",
|
||||
"three-mesh-bvh": "^0.7.0",
|
||||
"zustand": "^4.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
3605
public/SPLINE.json
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
35943
public/cubicle-99.CUBE
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 93 KiB |
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 82 KiB |
Before Width: | Height: | Size: 932 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 500 KiB |
Before Width: | Height: | Size: 408 KiB |
Before Width: | Height: | Size: 393 KiB |
Before Width: | Height: | Size: 510 KiB |
Before Width: | Height: | Size: 450 KiB |
Before Width: | Height: | Size: 641 KiB |
Before Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 95 KiB |
Before Width: | Height: | Size: 95 KiB |
Before Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 95 KiB |
Before Width: | Height: | Size: 82 KiB |
Before Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 76 KiB |
Before Width: | Height: | Size: 88 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
50
src/App.jsx
|
@ -1,12 +1,8 @@
|
|||
import { Canvas } from '@react-three/fiber'
|
||||
import { Experience } from './components/Experience'
|
||||
import { Suspense, useEffect, useMemo } from 'react'
|
||||
import { Suspense, useMemo } from 'react'
|
||||
import { Physics } from '@react-three/rapier'
|
||||
import { Environment, KeyboardControls, Loader, OrbitControls, Preload, Stats } from '@react-three/drei'
|
||||
import { insertCoin, onPlayerJoin } from 'playroomkit'
|
||||
import { useStore } from "./components/store";
|
||||
import * as THREE from "three";
|
||||
import { ParisBis } from './components/models/tracks/Paris-bis'
|
||||
import { KeyboardControls, Loader, OrbitControls, Preload, Stats } from '@react-three/drei'
|
||||
|
||||
export const Controls = {
|
||||
up: 'up',
|
||||
|
@ -16,10 +12,8 @@ export const Controls = {
|
|||
boost: 'boost',
|
||||
shoot: 'shoot',
|
||||
slow: 'slow',
|
||||
reset: 'reset',
|
||||
escape: 'escape'
|
||||
reset: 'reset'
|
||||
}
|
||||
|
||||
function App() {
|
||||
const map = useMemo(
|
||||
() => [
|
||||
|
@ -30,46 +24,18 @@ function App() {
|
|||
{ name: Controls.jump, keys: ['Space'] },
|
||||
{ name: Controls.slow, keys: ['Shift'] },
|
||||
{ name: Controls.shoot, keys: ['KeyE', 'Click'] },
|
||||
{ name: Controls.reset, keys: ['KeyR'] },
|
||||
{ name: Controls.escape, keys: ['Escape']}
|
||||
{ name: Controls.reset, keys: ['KeyR'] }
|
||||
],
|
||||
[]
|
||||
)
|
||||
|
||||
const { actions } = useStore();
|
||||
const start = async () => {
|
||||
await insertCoin({ skipLobby: true});
|
||||
|
||||
onPlayerJoin((state) => {
|
||||
actions.addPlayer(state);
|
||||
|
||||
actions.setId(state.id);
|
||||
|
||||
state.onQuit(() => {
|
||||
actions.removePlayer(state);
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
start();
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<Loader />
|
||||
<Canvas
|
||||
// shadows
|
||||
shadows
|
||||
dpr={1}
|
||||
gl={{ antialias: false, stencil: false, depth:false, powerPreference: 'high-performance' }}
|
||||
mode="concurrent"
|
||||
onCreated={({ gl, camera }) => {
|
||||
gl.toneMapping = THREE.AgXToneMapping
|
||||
gl.setClearColor(0x000000, 0)
|
||||
}}>
|
||||
gl={{ antialias: false, stencil: false, powerPreference: 'high-performance' }}
|
||||
>
|
||||
<Suspense fallback={null}>
|
||||
<Preload all />
|
||||
<Physics
|
||||
gravity={[0, -90, 0]}
|
||||
timeStep={'vary'}
|
||||
|
@ -77,10 +43,10 @@ function App() {
|
|||
<KeyboardControls map={map}>
|
||||
<Experience />
|
||||
</KeyboardControls>
|
||||
<Stats />
|
||||
</Physics>
|
||||
</Suspense>
|
||||
</Canvas>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
134
src/HUD.jsx
|
@ -1,11 +1,7 @@
|
|||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { useStore } from "./components/store";
|
||||
import { Joystick } from "react-joystick-component";
|
||||
import React, { useEffect, useRef } from "react";
|
||||
|
||||
export const HUD = () => {
|
||||
const wheel = useRef();
|
||||
const [image, setImage] = useState("");
|
||||
const { item, gameStarted, actions, controls } = useStore();
|
||||
|
||||
useEffect(() => {
|
||||
const handleMouseMove = (e) => {
|
||||
|
@ -27,118 +23,24 @@ export const HUD = () => {
|
|||
};
|
||||
}, []);
|
||||
|
||||
const handleMove = (e) => {
|
||||
actions.setJoystickX(e.x);
|
||||
};
|
||||
|
||||
const handleStop = () => {
|
||||
actions.setJoystickX(0);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
switch (item) {
|
||||
case "banana":
|
||||
setImage("./images/banana.webp");
|
||||
break;
|
||||
case "mushroom":
|
||||
setImage("./images/mushroom.png");
|
||||
break;
|
||||
case "shell":
|
||||
setImage("./images/shell.webp");
|
||||
break;
|
||||
default:
|
||||
setImage("");
|
||||
}
|
||||
}, [item]);
|
||||
|
||||
return (
|
||||
<div className="overlay">
|
||||
{gameStarted && (
|
||||
<>
|
||||
<div className="item">
|
||||
<div className="borderOut">
|
||||
<div className="borderIn">
|
||||
<div className="background">
|
||||
{image && <img src={image} alt="item" width={90} />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{controls === "touch" && (
|
||||
<>
|
||||
<div className="controls joystick">
|
||||
<Joystick
|
||||
size={100}
|
||||
sticky={false}
|
||||
baseColor="rgba(255, 255, 255, 0.5)"
|
||||
stickColor="rgba(255, 255, 255, 0.5)"
|
||||
move={handleMove}
|
||||
stop={handleStop}
|
||||
></Joystick>
|
||||
</div>
|
||||
<div
|
||||
className="controls drift"
|
||||
onMouseDown={(e) => {
|
||||
actions.setDriftButton(true);
|
||||
}}
|
||||
onMouseUp={(e) => {
|
||||
actions.setDriftButton(false);
|
||||
}}
|
||||
onTouchStart={(e) => {
|
||||
e.preventDefault();
|
||||
actions.setDriftButton(true);
|
||||
}}
|
||||
onTouchEnd={(e) => {
|
||||
e.preventDefault();
|
||||
actions.setDriftButton(false);
|
||||
}}
|
||||
>
|
||||
drift
|
||||
</div>
|
||||
<div
|
||||
className="controls itemButton"
|
||||
onMouseDown={(e) => {
|
||||
actions.setItemButton(true);
|
||||
}}
|
||||
onMouseUp={(e) => {
|
||||
actions.setItemButton(false);
|
||||
}}
|
||||
onTouchStart={(e) => {
|
||||
e.preventDefault();
|
||||
actions.setItemButton(true);
|
||||
}}
|
||||
onTouchEnd={(e) => {
|
||||
e.preventDefault();
|
||||
actions.setItemButton(false);
|
||||
}}
|
||||
|
||||
>
|
||||
item
|
||||
</div>
|
||||
<div
|
||||
className="controls menuButton"
|
||||
onMouseDown={(e) => {
|
||||
actions.setMenuButton(true);
|
||||
}}
|
||||
onMouseUp={(e) => {
|
||||
actions.setMenuButton(false);
|
||||
}}
|
||||
onTouchStart={(e) => {
|
||||
e.preventDefault();
|
||||
actions.setMenuButton(true);
|
||||
}}
|
||||
onTouchEnd={(e) => {
|
||||
e.preventDefault();
|
||||
actions.setMenuButton(false);
|
||||
}}
|
||||
|
||||
>
|
||||
menu
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<div className="overlay"> dadasd
|
||||
<div className="logo">
|
||||
<img src="./logo.png" alt="logo" />
|
||||
</div>
|
||||
<div className="wheel">
|
||||
<img
|
||||
ref={wheel}
|
||||
src="./steering_wheel.png"
|
||||
alt="steering wheel"
|
||||
className="steering-wheel"
|
||||
style={{
|
||||
position: "absolute",
|
||||
pointerEvents: "none",
|
||||
transformOrigin: "center",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
128
src/Landing.jsx
|
@ -1,128 +0,0 @@
|
|||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { useStore } from "./components/store";
|
||||
import gsap from "gsap";
|
||||
|
||||
export const Landing = () => {
|
||||
const { gameStarted, actions } = useStore();
|
||||
|
||||
const logo = useRef();
|
||||
const startButton = useRef();
|
||||
const homeRef = useRef();
|
||||
const [setupStatus, setSetupStatus] = useState(0);
|
||||
const [controlStyle, setControlStyle] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
const tl = gsap.timeline();
|
||||
|
||||
if (setupStatus === 0) {
|
||||
if (logo.current && startButton.current) {
|
||||
tl.from(logo.current, {
|
||||
scale: 122,
|
||||
opacity: 0,
|
||||
duration: 0,
|
||||
ease: "power4.out",
|
||||
})
|
||||
.to(logo.current, {
|
||||
scale: 1,
|
||||
opacity: 1,
|
||||
duration: 1.5,
|
||||
ease: "power4.out",
|
||||
})
|
||||
.to(startButton.current, {
|
||||
opacity: 1,
|
||||
duration: 3,
|
||||
delay: 1,
|
||||
ease: "power4.out",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeyDown = (event) => {
|
||||
if (event.key === 'Enter') {
|
||||
setSetupStatus(1);
|
||||
}
|
||||
};
|
||||
|
||||
document.body.addEventListener('keydown', handleKeyDown);
|
||||
return () => {
|
||||
document.body.removeEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
}, [setupStatus]);
|
||||
|
||||
if (gameStarted) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{setupStatus === 0 && (
|
||||
<div className="home" ref={homeRef}>
|
||||
<div className="logo">
|
||||
<img ref={logo} src="./logo.png" alt="logo" />
|
||||
</div>
|
||||
<div className="start" ref={startButton}>
|
||||
<button className="start-button"
|
||||
onClick={() => setSetupStatus(1)}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
setSetupStatus(1);
|
||||
}}} autoFocus>
|
||||
PRESS ENTER TO START
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{setupStatus === 1 && (
|
||||
<div className="home">
|
||||
<div className="glassy">
|
||||
<h1>CHOOSE YOUR CONTROL STYLE</h1>
|
||||
|
||||
<div className="articles">
|
||||
<div className={controlStyle === "keyboard" ? "article selected" : "article"} onClick={() =>
|
||||
setControlStyle("keyboard")}>
|
||||
<img src="./images/keyboard.png" alt="keyboard" />
|
||||
<div className="article_label">
|
||||
<p>Keyboard</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className={controlStyle === "gamepad" ? "article selected" : "article"} onClick={() =>
|
||||
setControlStyle("gamepad")}>
|
||||
<img src="./images/gamepad.png" alt="gamepad" />
|
||||
<div className="article_label">
|
||||
<p>Gamepad</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className={controlStyle === "mouseKeyboard" ? "article selected" : "article"} onClick={() =>
|
||||
setControlStyle("mouseKeyboard")}>
|
||||
<img src="./images/mousekeyboard.png" alt="mouse & keyboard" />
|
||||
<div className="article_label">
|
||||
<p>Mouse & Keyboard</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className={controlStyle === "touch" ? "article selected" : "article"} onClick={() =>
|
||||
setControlStyle("touch")}>
|
||||
<img src="./images/mobile.png" alt="mobile" />
|
||||
<div className="article_label">
|
||||
<p>Mobile</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className={controlStyle != "" ? "submit" : "submit disabled"}>
|
||||
<button
|
||||
className={controlStyle != "" ? "submit-button" : "submit-button disabled"}
|
||||
onClick={() => {
|
||||
actions.setControls(controlStyle);
|
||||
actions.setGameStarted(true);
|
||||
}}
|
||||
>
|
||||
CONFIRM
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
);
|
||||
};
|
|
@ -1,87 +0,0 @@
|
|||
import { Euler, Object3D, Vector3, Matrix4, DoubleSide, Quaternion, TextureLoader, BackSide } from 'three'
|
||||
import { useRef, useLayoutEffect } from 'react'
|
||||
import { useFrame, useLoader } from '@react-three/fiber'
|
||||
import { vec3 } from '@react-three/rapier'
|
||||
|
||||
|
||||
import { useStore } from './store'
|
||||
|
||||
|
||||
const e = new Euler()
|
||||
const m = new Matrix4()
|
||||
const o = new Object3D()
|
||||
const v = new Vector3()
|
||||
const q = new Quaternion()
|
||||
|
||||
|
||||
|
||||
export function Dust({ count = 500, opacity = 0.1, size = 0.6 }) {
|
||||
const smoke01 = useLoader(TextureLoader, './particles/smokes/smoke_01.png');
|
||||
const smoke02 = useLoader(TextureLoader, './particles/smokes/smoke_02.png');
|
||||
const smoke03 = useLoader(TextureLoader, './particles/smokes/smoke_03.png');
|
||||
const smoke04 = useLoader(TextureLoader, './particles/smokes/smoke_04.png');
|
||||
const smoke05 = useLoader(TextureLoader, './particles/smokes/smoke_05.png');
|
||||
const smoke06 = useLoader(TextureLoader, './particles/smokes/smoke_06.png');
|
||||
const smoke07 = useLoader(TextureLoader, './particles/smokes/smoke_07.png');
|
||||
const smoke08 = useLoader(TextureLoader, './particles/smokes/smoke_08.png');
|
||||
|
||||
const texture = [smoke01, smoke02, smoke03, smoke04, smoke05, smoke06, smoke07, smoke08]
|
||||
const ref = useRef(null);
|
||||
const { leftWheel, rightWheel } = useStore();
|
||||
let index = 0
|
||||
let time = 0
|
||||
let i = 0
|
||||
useFrame((state,delta ) => {
|
||||
if(!leftWheel && !rightWheel) return;
|
||||
const rotation = leftWheel.kartRotation;
|
||||
if (state.clock.getElapsedTime() - time > 0.02 && leftWheel && rightWheel && ref.current && leftWheel.isSpinning) {
|
||||
time = state.clock.getElapsedTime()
|
||||
setItemAt(ref.current, rotation, leftWheel, index++);
|
||||
setItemAt(ref.current, rotation, rightWheel, index++);
|
||||
|
||||
if (index === count) index = 0
|
||||
} else {
|
||||
// Shrink old one
|
||||
for (i = 0; i < count; i++) {
|
||||
const direction = new Vector3(Math.sin(time * 6 + i * 10) , 2, 0);
|
||||
ref.current.getMatrixAt(i, m)
|
||||
m.decompose(o.position, q, v)
|
||||
o.scale.setScalar(Math.max(0, v.x - 0.005))
|
||||
o.position.addScaledVector(direction, 0.01)
|
||||
o.updateMatrix()
|
||||
ref.current.setMatrixAt(i, o.matrix)
|
||||
ref.current.instanceMatrix.needsUpdate = true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if(ref.current){
|
||||
ref.current.geometry.rotateY(-Math.PI / 2)
|
||||
return () => {
|
||||
ref.current.geometry.rotateY(Math.PI / 2)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<instancedMesh frustumCulled={false} ref={ref} args={[undefined, undefined, count]}>
|
||||
<planeGeometry args={[size, size]} />
|
||||
<meshBasicMaterial color={0xfcebc5} transparent map={smoke01} opacity={1} depthWrite={false} side={DoubleSide} />
|
||||
</instancedMesh>
|
||||
)
|
||||
}
|
||||
|
||||
function setItemAt(instances, rotation, body, index) {
|
||||
const randomOffset = (Math.random() - 0.5) * 0.3 ;
|
||||
const pos = body.getWorldPosition(v);
|
||||
o.rotation.set(0, rotation + Math.PI / 2, 0);
|
||||
pos.x += randomOffset
|
||||
// pos.y += randomOffset
|
||||
pos.z += randomOffset
|
||||
o.position.copy(pos);
|
||||
o.scale.setScalar(1)
|
||||
o.updateMatrix()
|
||||
instances.setMatrixAt(index, o.matrix)
|
||||
instances.instanceMatrix.needsUpdate = true
|
||||
}
|
|
@ -1,182 +1,21 @@
|
|||
import {
|
||||
Environment,
|
||||
OrbitControls,
|
||||
PerspectiveCamera,
|
||||
Lightformer,
|
||||
Bvh,
|
||||
} from "@react-three/drei";
|
||||
import { Ground } from "./Ground";
|
||||
import { PlayerController } from "./PlayerController";
|
||||
import { PlayerControllerGamepad } from "./PlayerControllerGamepad";
|
||||
import { PlayerControllerKeyboard } from "./PlayerControllerKeyboard";
|
||||
import { PlayerControllerTouch } from "./PlayerControllerTouch";
|
||||
import { Paris } from "./models/tracks/Tour_paris_promenade";
|
||||
import {
|
||||
EffectComposer,
|
||||
N8AO,
|
||||
Bloom,
|
||||
TiltShift2,
|
||||
HueSaturation,
|
||||
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, useRef } from "react";
|
||||
import { useFrame, useLoader } from "@react-three/fiber";
|
||||
import { LUTPass, LUTCubeLoader } from "three-stdlib";
|
||||
import { useCurvedPathPoints } from "./useCurvedPath";
|
||||
import { ParisBis } from "./models/tracks/Paris-bis";
|
||||
import { Skid } from "./Skid";
|
||||
import { Dust } from "./Dust";
|
||||
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'
|
||||
|
||||
export const Experience = () => {
|
||||
const onCollide = (event) => {};
|
||||
const { gameStarted, bananas, shells, players, id, actions, controls } =
|
||||
useStore();
|
||||
const [networkBananas, setNetworkBananas] = useMultiplayerState(
|
||||
"bananas",
|
||||
[]
|
||||
);
|
||||
|
||||
const { points, loading, error } = useCurvedPathPoints("./CurvedPath.json");
|
||||
|
||||
const [networkShells, setNetworkShells] = useMultiplayerState("shells", []);
|
||||
const [pointest, setPointest] = useState([]);
|
||||
const [currentPoint, setCurrentPoint] = useState(0);
|
||||
useEffect(() => {
|
||||
if (points) {
|
||||
//This is adjusted to Paris scale
|
||||
const scaledPoints = points.map((point) => ({
|
||||
x: point.x * 50,
|
||||
y: point.y * 50,
|
||||
z: point.z * 50,
|
||||
}));
|
||||
setPointest(scaledPoints.reverse());
|
||||
}
|
||||
}, [points]);
|
||||
|
||||
const testing = getState("bananas");
|
||||
const cam = useRef();
|
||||
const lookAtTarget = useRef();
|
||||
// useEffect(() => {
|
||||
// setNetworkBananas(bananas);
|
||||
// }, [bananas]);
|
||||
|
||||
// useEffect(() => {
|
||||
// setNetworkShells(shells);
|
||||
// }, [shells]);
|
||||
const speedFactor = 5;
|
||||
const { texture } = useLoader(LUTCubeLoader, "./cubicle-99.CUBE");
|
||||
useFrame((state, delta) => {
|
||||
if (!gameStarted) {
|
||||
const camera = cam.current;
|
||||
|
||||
if (currentPoint < pointest.length - 1) {
|
||||
camera.position.lerp(pointest[currentPoint], delta * speedFactor);
|
||||
lookAtTarget.current.position.lerp(
|
||||
pointest[currentPoint + 1],
|
||||
delta * speedFactor
|
||||
);
|
||||
camera.lookAt(lookAtTarget.current.position);
|
||||
|
||||
if (camera.position.distanceTo(pointest[currentPoint]) < 5) {
|
||||
setCurrentPoint(currentPoint + 1);
|
||||
}
|
||||
} else {
|
||||
setCurrentPoint(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{gameStarted &&
|
||||
players.map((player) => {
|
||||
const ControllerComponent =
|
||||
controls === "keyboard"
|
||||
? PlayerControllerKeyboard
|
||||
: controls === "gamepad"
|
||||
? PlayerControllerGamepad
|
||||
: controls === "touch"
|
||||
? PlayerControllerTouch
|
||||
: PlayerController;
|
||||
|
||||
return (
|
||||
<ControllerComponent
|
||||
key={player.id}
|
||||
player={player}
|
||||
userPlayer={player.id === myPlayer()?.id}
|
||||
setNetworkBananas={setNetworkBananas}
|
||||
setNetworkShells={setNetworkShells}
|
||||
networkBananas={networkBananas}
|
||||
networkShells={networkShells}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{gameStarted &&
|
||||
players.map((player) => (
|
||||
<PlayerDummies
|
||||
key={player.id}
|
||||
player={player}
|
||||
userPlayer={player.id === myPlayer()?.id}
|
||||
/>
|
||||
))}
|
||||
{!gameStarted && (
|
||||
<>
|
||||
<mesh ref={lookAtTarget}></mesh>
|
||||
<PerspectiveCamera
|
||||
ref={cam}
|
||||
makeDefault
|
||||
position={[0, 2, 0]}
|
||||
far={5000}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{/* <Paris position={[0, 0, 0]} /> */}
|
||||
|
||||
<ParisBis position={[0, 0, 0]} />
|
||||
<ItemBox position={[-20, 2.5, -119]} />
|
||||
<Coin position={[-30, 2, -119]} />
|
||||
<Skid />
|
||||
<Dust />
|
||||
|
||||
<PlayerController />
|
||||
{/* <Skid /> */}
|
||||
<Ground position={[0, 0, 0]} />
|
||||
<Environment resolution={256} preset="lobby" />
|
||||
{networkBananas.map((banana) => (
|
||||
<Banana
|
||||
key={banana.id}
|
||||
position={banana.position}
|
||||
setNetworkBananas={setNetworkBananas}
|
||||
networkBananas={networkBananas}
|
||||
id={banana.id}
|
||||
/>
|
||||
))}
|
||||
{networkShells.map((shell) => (
|
||||
<Shell
|
||||
key={shell.id}
|
||||
id={shell.id}
|
||||
position={shell.position}
|
||||
rotation={shell.rotation}
|
||||
setNetworkShells={setNetworkShells}
|
||||
networkShells={networkShells}
|
||||
/>
|
||||
))}
|
||||
<Environment
|
||||
resolution={256}
|
||||
preset='lobby'
|
||||
|
||||
/>
|
||||
|
||||
<directionalLight
|
||||
position={[10, 50, -30]}
|
||||
|
@ -186,29 +25,32 @@ export const Experience = () => {
|
|||
shadow-camera-left={-300}
|
||||
shadow-camera-right={300}
|
||||
shadow-camera-top={300}
|
||||
shadow-camera-bottom={-300}
|
||||
shadow-camera-bottom={-3000}
|
||||
castShadow
|
||||
/>
|
||||
|
||||
<Paris position={[0, 0, 0]} />
|
||||
<EffectComposer
|
||||
multisampling={0}
|
||||
disableNormalPass
|
||||
disableSSAO
|
||||
disableDepthPass
|
||||
|
||||
>
|
||||
<SMAA />
|
||||
{/* <N8AO distanceFalloff={1} aoRadius={1} intensity={3} /> */}
|
||||
<N8AO distanceFalloff={1} aoRadius={1} intensity={3} />
|
||||
<Bloom
|
||||
luminanceThreshold={0}
|
||||
mipmapBlur
|
||||
luminanceSmoothing={0.01}
|
||||
intensity={0.5}
|
||||
/>
|
||||
<TiltShift2 />
|
||||
{/* <ChromaticAberration offset={[0.0006, 0.0006]} /> */}
|
||||
<HueSaturation saturation={0.05} />
|
||||
{/* <Vignette eskil={false} offset={0.1} darkness={0.4} /> */}
|
||||
|
||||
<TiltShift2/>
|
||||
<ChromaticAberration offset={[0.0006, 0.0006]} />
|
||||
<HueSaturation saturation={0.1} />
|
||||
<Vignette eskil={false} offset={0.1} darkness={0.4} />
|
||||
</EffectComposer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
|
|
@ -10,23 +10,15 @@ export const DriftParticlesLeft = ({turboColor,scale, ...props}) => {
|
|||
return (
|
||||
<group {...props}>
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
{/* <Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} />
|
||||
<Particles1 turboColor={turboColor} scale={scale} /> */}
|
||||
|
||||
{/* <Particles3 turboColor={turboColor} scale={scale} /> */}
|
||||
|
||||
</group>
|
|
@ -0,0 +1,16 @@
|
|||
import { Particles2 } from "./Particles2";
|
||||
import { Particles4 } from "./Particles4";
|
||||
|
||||
export const DriftParticlesRight = ({turboColor,scale, ...props}) => {
|
||||
|
||||
// if(scale < 0.8) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
return (
|
||||
<group {...props}>
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
|
||||
</group>
|
||||
)
|
||||
}
|
|
@ -58,7 +58,7 @@ export const FlameParticle = ({ position, png, isBoosting, delay = 0 }) => {
|
|||
alphaMap={texture}
|
||||
transparent={true}
|
||||
depthWrite={false}
|
||||
color={0xff9900}
|
||||
color={0x000000}
|
||||
opacity={1}
|
||||
toneMapped={false}
|
||||
/>
|
|
@ -0,0 +1,57 @@
|
|||
import { useRef, useMemo } from "react";
|
||||
import { useFrame } from "@react-three/fiber";
|
||||
import * as THREE from 'three';
|
||||
|
||||
export const Particles1 = ({ turboColor, scale, numParticles = 50, ...props }) => {
|
||||
const instancedMeshRef = useRef();
|
||||
const particlesData = useMemo(() => {
|
||||
return new Array(numParticles).fill().map(() => ({
|
||||
position: new THREE.Vector3(-0.6, 0.05, 0.5),
|
||||
velocity: new THREE.Vector3(-Math.random() * 0.05, Math.random() * 0.05, Math.random() * 0.02),
|
||||
gravity: -0.003
|
||||
}));
|
||||
}, [numParticles]);
|
||||
|
||||
useFrame((state, delta) => {
|
||||
if (!instancedMeshRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Manage visibility directly in the animation loop
|
||||
instancedMeshRef.current.visible = scale >= 0.8;
|
||||
|
||||
if (scale < 0.8) {
|
||||
return;
|
||||
}
|
||||
|
||||
const deltaScaled = delta * 144; // Scale for 144 FPS
|
||||
particlesData.forEach((particle, i) => {
|
||||
particle.velocity.y += particle.gravity * deltaScaled;
|
||||
|
||||
particle.position.x += particle.velocity.x * deltaScaled;
|
||||
particle.position.y += particle.velocity.y * deltaScaled;
|
||||
particle.position.z += particle.velocity.z * deltaScaled;
|
||||
|
||||
if (particle.position.y < 0.05) {
|
||||
particle.position.set(-0.6, 0.05, 0.5);
|
||||
particle.velocity.set(-Math.random() * 0.05, Math.random() * 0.05, Math.random() * 0.02);
|
||||
}
|
||||
const matrix = new THREE.Matrix4();
|
||||
matrix.setPosition(particle.position);
|
||||
instancedMeshRef.current.setMatrixAt(i, matrix);
|
||||
});
|
||||
|
||||
instancedMeshRef.current.instanceMatrix.needsUpdate = true;
|
||||
});
|
||||
|
||||
return (
|
||||
<instancedMesh ref={instancedMeshRef} args={[null, null, numParticles]} visible={scale >= 0.8}>
|
||||
<sphereGeometry args={[0.01, 16, 16]} />
|
||||
<meshStandardMaterial
|
||||
emissive={turboColor}
|
||||
toneMapped={false}
|
||||
emissiveIntensity={5}
|
||||
/>
|
||||
</instancedMesh>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,57 @@
|
|||
import { useRef, useMemo } from "react";
|
||||
import { useFrame } from "@react-three/fiber";
|
||||
import * as THREE from 'three';
|
||||
|
||||
export const Particles2 = ({ turboColor, scale, numParticles = 50, ...props }) => {
|
||||
const instancedMeshRef = useRef();
|
||||
const particlesData = useMemo(() => {
|
||||
return new Array(numParticles).fill().map(() => ({
|
||||
position: new THREE.Vector3(0.6, 0.05, 0.5),
|
||||
velocity: new THREE.Vector3(Math.random() * 0.05, Math.random() * 0.05, Math.random() * 0.02),
|
||||
gravity: -0.003
|
||||
}));
|
||||
}, [numParticles]);
|
||||
|
||||
useFrame((state, delta) => {
|
||||
if (!instancedMeshRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Manage visibility directly in the animation loop
|
||||
instancedMeshRef.current.visible = scale >= 0.8;
|
||||
|
||||
if (scale < 0.8) {
|
||||
return;
|
||||
}
|
||||
|
||||
const deltaScaled = delta * 144; // Scale for 144 FPS
|
||||
particlesData.forEach((particle, i) => {
|
||||
particle.velocity.y += particle.gravity * deltaScaled;
|
||||
|
||||
particle.position.x += particle.velocity.x * deltaScaled;
|
||||
particle.position.y += particle.velocity.y * deltaScaled;
|
||||
particle.position.z += particle.velocity.z * deltaScaled;
|
||||
|
||||
if (particle.position.y < 0.05) {
|
||||
particle.position.set(0.6, 0.05, 0.5);
|
||||
particle.velocity.set(Math.random() * 0.05, Math.random() * 0.05, Math.random() * 0.02);
|
||||
}
|
||||
const matrix = new THREE.Matrix4();
|
||||
matrix.setPosition(particle.position);
|
||||
instancedMeshRef.current.setMatrixAt(i, matrix);
|
||||
});
|
||||
|
||||
instancedMeshRef.current.instanceMatrix.needsUpdate = true;
|
||||
});
|
||||
|
||||
return (
|
||||
<instancedMesh ref={instancedMeshRef} args={[null, null, numParticles]} visible={scale >= 0.8}>
|
||||
<sphereGeometry args={[0.01, 16, 16]} />
|
||||
<meshStandardMaterial
|
||||
emissive={turboColor}
|
||||
toneMapped={false}
|
||||
emissiveIntensity={5}
|
||||
/>
|
||||
</instancedMesh>
|
||||
);
|
||||
};
|
|
@ -5,7 +5,6 @@ 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);
|
||||
|
||||
|
@ -19,9 +18,7 @@ export const PointParticle = ({ position, png, turboColor }) => {
|
|||
}, [position]);
|
||||
|
||||
useEffect(() => {
|
||||
if (materialRef.current) {
|
||||
materialRef.current.color.multiplyScalar(10);
|
||||
}
|
||||
|
||||
setSize(0);
|
||||
setOpacity(1);
|
||||
}, [turboColor]);
|
||||
|
@ -39,7 +36,6 @@ export const PointParticle = ({ position, png, turboColor }) => {
|
|||
return (
|
||||
<points ref={pointsRef} geometry={points}>
|
||||
<pointsMaterial
|
||||
ref={materialRef}
|
||||
size={size}
|
||||
alphaMap={texture}
|
||||
transparent={true}
|
|
@ -1,56 +0,0 @@
|
|||
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 (
|
||||
<points ref={pointsRef} geometry={points}>
|
||||
<pointsMaterial
|
||||
ref={materialRef}
|
||||
size={size}
|
||||
alphaMap={texture}
|
||||
transparent={true}
|
||||
depthWrite={false}
|
||||
opacity={opacity}
|
||||
toneMapped={false}
|
||||
color={0xbf8717}
|
||||
/>
|
||||
</points>
|
||||
);
|
||||
};
|
|
@ -1,15 +0,0 @@
|
|||
import { CircleCoinParticle } from "./CircleCoinParticle"
|
||||
import { StarCoinParticle } from "./StarCoinParticle"
|
||||
|
||||
export const CoinParticles = ({ coins }) => {
|
||||
return (
|
||||
<>
|
||||
<CircleCoinParticle position={[0,0.8, 0.2]} coins={coins}/>
|
||||
<StarCoinParticle position={[0,0.8, 0.2]} coins={coins} timeModifier={50}/>
|
||||
<StarCoinParticle position={[0,0.8, 0.2]} coins={coins} timeModifier={60}/>
|
||||
<StarCoinParticle position={[0,0.8, 0.2]} coins={coins} timeModifier={40}/>
|
||||
<StarCoinParticle position={[0,0.8, 0.2]} coins={coins} timeModifier={90}/>
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
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 (
|
||||
<points ref={pointsRef} geometry={points}>
|
||||
<pointsMaterial
|
||||
ref={materialRef}
|
||||
alphaMap={texture}
|
||||
transparent={true}
|
||||
depthWrite={false}
|
||||
toneMapped={false}
|
||||
color={0xbf8717}
|
||||
/>
|
||||
</points>
|
||||
);
|
||||
};
|
|
@ -1,33 +0,0 @@
|
|||
import { Particles2 } from "./Particles2";
|
||||
import { Particles4 } from "./Particles4";
|
||||
|
||||
export const DriftParticlesRight = ({turboColor,scale, ...props}) => {
|
||||
|
||||
// if(scale < 0.8) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
return (
|
||||
<group {...props}>
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
<Particles2 turboColor={turboColor} scale={scale} />
|
||||
</group>
|
||||
)
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
import { useRef } from "react";
|
||||
import { useFrame } from "@react-three/fiber";
|
||||
import * as THREE from 'three';
|
||||
|
||||
export const Particles1 = ({ turboColor, scale, ...props }) => {
|
||||
const ref = useRef();
|
||||
const velocity = useRef({
|
||||
x: -Math.random() * 0.05,
|
||||
y: Math.random() * 0.05,
|
||||
z: Math.random() * 0.02,
|
||||
});
|
||||
const gravity = -0.003;
|
||||
|
||||
useFrame((state, delta) => {
|
||||
let position = ref.current.position;
|
||||
let velocityVector = new THREE.Vector3(velocity.current.x, velocity.current.y, velocity.current.z);
|
||||
|
||||
// Adjust gravity and velocity based on delta
|
||||
velocity.current.y += gravity * delta * 144; // Multiply by 144 to scale for 144 FPS
|
||||
|
||||
// Scale velocity changes by delta
|
||||
position.x += velocity.current.x * delta * 144;
|
||||
position.y += velocity.current.y * delta * 144;
|
||||
position.z += velocity.current.z * delta * 144;
|
||||
|
||||
if (!velocityVector.equals(new THREE.Vector3(0, 0, 0))) {
|
||||
const alignmentQuaternion = new THREE.Quaternion();
|
||||
alignmentQuaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), velocityVector.normalize());
|
||||
ref.current.quaternion.slerp(alignmentQuaternion, 0.1);
|
||||
}
|
||||
|
||||
if (position.y < 0.05) {
|
||||
position.set(-0.6, 0.05, 0.5);
|
||||
velocity.current = {
|
||||
x: -Math.random() * 0.05,
|
||||
y: Math.random() * 0.05,
|
||||
z: Math.random() * 0.02,
|
||||
};
|
||||
}
|
||||
|
||||
ref.current.position.set(position.x, position.y, position.z);
|
||||
});
|
||||
|
||||
|
||||
return (
|
||||
<mesh ref={ref} position={[-0.6, 0.05, 0.5]} scale={[scale, scale * 5, scale]}>
|
||||
<sphereGeometry args={[0.01, 16, 16]} />
|
||||
<meshStandardMaterial
|
||||
emissive={turboColor}
|
||||
toneMapped={false}
|
||||
emissiveIntensity={5}
|
||||
/>
|
||||
</mesh>
|
||||
);
|
||||
};
|
|
@ -1,54 +0,0 @@
|
|||
import { useRef } from "react";
|
||||
import { useFrame } from "@react-three/fiber";
|
||||
import * as THREE from 'three';
|
||||
|
||||
export const Particles2 = ({ turboColor, scale, ...props }) => {
|
||||
const ref = useRef();
|
||||
const velocity = useRef({
|
||||
x: Math.random() * 0.05,
|
||||
y: Math.random() * 0.05,
|
||||
z: Math.random() * 0.02,
|
||||
});
|
||||
const gravity = -0.003;
|
||||
|
||||
useFrame((state, delta) => {
|
||||
let position = ref.current.position;
|
||||
let velocityVector = new THREE.Vector3(velocity.current.x, velocity.current.y, velocity.current.z);
|
||||
|
||||
|
||||
velocity.current.y += gravity * delta * 144;
|
||||
|
||||
position.x += velocity.current.x * delta * 144;
|
||||
position.y += velocity.current.y * delta * 144;
|
||||
position.z += velocity.current.z * delta * 144;
|
||||
|
||||
if (!velocityVector.equals(new THREE.Vector3(0, 0, 0))) {
|
||||
const alignmentQuaternion = new THREE.Quaternion();
|
||||
alignmentQuaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), velocityVector.normalize());
|
||||
ref.current.quaternion.slerp(alignmentQuaternion, 0.1);
|
||||
}
|
||||
|
||||
if (position.y < 0.05) {
|
||||
position.set(0.6, 0.05, 0.5);
|
||||
velocity.current = {
|
||||
x: Math.random() * 0.05,
|
||||
y: Math.random() * 0.05,
|
||||
z: Math.random() * 0.02,
|
||||
};
|
||||
}
|
||||
|
||||
ref.current.position.set(position.x, position.y, position.z);
|
||||
});
|
||||
|
||||
|
||||
return (
|
||||
<mesh ref={ref} position={[0.6, 0.05, 0.5]} scale={[scale, scale * 5, scale]}>
|
||||
<sphereGeometry args={[0.01, 16, 16]} />
|
||||
<meshStandardMaterial
|
||||
emissive={turboColor}
|
||||
toneMapped={false}
|
||||
emissiveIntensity={5}
|
||||
/>
|
||||
</mesh>
|
||||
);
|
||||
};
|
|
@ -1,139 +0,0 @@
|
|||
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 });
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
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>
|
||||
);
|
||||
};
|
|
@ -1,19 +0,0 @@
|
|||
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}/>
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
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 (
|
||||
<points ref={pointsRef} geometry={points}>
|
||||
<pointsMaterial
|
||||
ref={materialRef}
|
||||
size={size}
|
||||
alphaMap={texture}
|
||||
transparent={true}
|
||||
depthWrite={false}
|
||||
opacity={opacity}
|
||||
toneMapped={false}
|
||||
color={currentColor}
|
||||
/>
|
||||
</points>
|
||||
);
|
||||
};
|
|
@ -1,20 +0,0 @@
|
|||
import { CircleItemParticle } from "./CircleItemParticle"
|
||||
import { StarItemParticle } from "./StarItemParticle"
|
||||
import { SmallCircleParticle } from "./SmallCircleParticle"
|
||||
|
||||
export const ItemParticles = ({item}) => {
|
||||
return (
|
||||
<>
|
||||
<CircleItemParticle position={[0,0.8, 0.2]} item={item} color={0x75ff9a}/>
|
||||
<StarItemParticle position={[0,0.8, 0.2]} item={item} timeModifier={50} color={0x75ff9a}/>
|
||||
<StarItemParticle position={[0,0.8, 0.2]} item={item} timeModifier={60} color={0xe872fc}/>
|
||||
<StarItemParticle position={[0,0.8, 0.2]} item={item} timeModifier={40} color={0x72e5fc}/>
|
||||
<StarItemParticle position={[0,0.8, 0.2]} item={item} timeModifier={90} color={0xf0db7f}/>
|
||||
<SmallCircleParticle position={[0,0.8, 0.2]} item={item} timeModifier={50} color={0x75ff9a}/>
|
||||
<SmallCircleParticle position={[0,0.8, 0.2]} item={item} timeModifier={60} color={0xe872fc}/>
|
||||
<SmallCircleParticle position={[0,0.8, 0.2]} item={item} timeModifier={40} color={0x72e5fc}/>
|
||||
<SmallCircleParticle position={[0,0.8, 0.2]} item={item} timeModifier={90} color={0xf0db7f}/>
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
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 (
|
||||
<points ref={pointsRef} geometry={points}>
|
||||
<pointsMaterial
|
||||
ref={materialRef}
|
||||
alphaMap={texture}
|
||||
transparent={true}
|
||||
depthWrite={false}
|
||||
toneMapped={false}
|
||||
color={color}
|
||||
/>
|
||||
</points>
|
||||
);
|
||||
};
|
|
@ -1,70 +0,0 @@
|
|||
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 (
|
||||
<points ref={pointsRef} geometry={points}>
|
||||
<pointsMaterial
|
||||
ref={materialRef}
|
||||
alphaMap={texture}
|
||||
transparent={true}
|
||||
depthWrite={false}
|
||||
toneMapped={false}
|
||||
color={color}
|
||||
/>
|
||||
</points>
|
||||
);
|
||||
};
|
|
@ -1,82 +0,0 @@
|
|||
import React, { useRef, useMemo } from "react";
|
||||
import { useLoader, useFrame } from "@react-three/fiber";
|
||||
import * as THREE from "three";
|
||||
|
||||
export const SmokeParticle = ({ position, png, leftDrift, rightDrift, delay = 0 }) => {
|
||||
const texture = useLoader(THREE.TextureLoader, png);
|
||||
const pointsRef = useRef();
|
||||
const initialized = useRef(false);
|
||||
|
||||
// Initialize after delay
|
||||
useMemo(() => {
|
||||
const timer = setTimeout(() => {
|
||||
initialized.current = true;
|
||||
}, delay);
|
||||
return () => clearTimeout(timer);
|
||||
}, [delay]);
|
||||
|
||||
const points = useMemo(() => {
|
||||
const geom = new THREE.BufferGeometry();
|
||||
geom.setAttribute(
|
||||
"position",
|
||||
new THREE.Float32BufferAttribute(position, 3)
|
||||
);
|
||||
return geom;
|
||||
}, [position]);
|
||||
|
||||
useFrame(({clock}, delta) => {
|
||||
if (!initialized.current) return;
|
||||
|
||||
const pointsCurrent = pointsRef.current;
|
||||
|
||||
if(leftDrift || rightDrift){
|
||||
pointsCurrent.position.z += 0.1 * delta * 144;
|
||||
|
||||
//Set inclination
|
||||
if(leftDrift){
|
||||
pointsCurrent.position.x -= 0.09 * delta * 144;
|
||||
}
|
||||
|
||||
if(rightDrift){
|
||||
pointsCurrent.position.x += 0.09 * delta * 144;
|
||||
}
|
||||
|
||||
if(pointsCurrent.position.x < -1.8 || pointsCurrent.position.x > 1.8) {
|
||||
pointsCurrent.position.z = 0;
|
||||
pointsCurrent.position.x = 0;
|
||||
pointsCurrent.material.opacity = 1.5;
|
||||
pointsCurrent.material.size = 4;
|
||||
}
|
||||
|
||||
if(pointsCurrent.material.opacity > 0) {
|
||||
pointsCurrent.material.opacity -= 0.01 * delta * 144;
|
||||
}
|
||||
|
||||
if(pointsCurrent.material.size > 0) {
|
||||
//Shrinking effect
|
||||
pointsCurrent.material.size -= 0.1* delta * 144;
|
||||
}
|
||||
|
||||
} else {
|
||||
pointsCurrent.position.z = 0;
|
||||
pointsCurrent.position.x = 0;
|
||||
pointsCurrent.material.opacity = 0;
|
||||
pointsCurrent.material.size = 0;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return (
|
||||
<points ref={pointsRef} geometry={points}>
|
||||
<pointsMaterial
|
||||
size={1}
|
||||
alphaMap={texture}
|
||||
transparent={true}
|
||||
depthWrite={false}
|
||||
color={0xBFBFBF}
|
||||
opacity={1}
|
||||
toneMapped={false}
|
||||
/>
|
||||
</points>
|
||||
);
|
||||
};
|
|
@ -1,24 +0,0 @@
|
|||
import { SmokeParticle } from "./SmokeParticle";
|
||||
|
||||
export const SmokeParticles = ({ driftRight, driftLeft }) => {
|
||||
|
||||
|
||||
return (
|
||||
<group>
|
||||
<SmokeParticle
|
||||
position={[-0.6, 0.05, 0.5]}
|
||||
png="./particles/fire_02.png"
|
||||
leftDrift={driftLeft}
|
||||
rightDrift={driftRight}
|
||||
delay={200}
|
||||
/>
|
||||
<SmokeParticle
|
||||
position={[0.6, 0.05, 0.5]}
|
||||
png="./particles/fire_01.png"
|
||||
leftDrift={driftLeft}
|
||||
rightDrift={driftRight}
|
||||
delay={200}
|
||||
/>
|
||||
</group>
|
||||
);
|
||||
};
|
|
@ -3,45 +3,33 @@ import { BallCollider, RigidBody, useRapier, vec3 } from "@react-three/rapier";
|
|||
import {
|
||||
useKeyboardControls,
|
||||
PerspectiveCamera,
|
||||
ContactShadows,
|
||||
Sphere,
|
||||
OrbitControls,
|
||||
Trail,
|
||||
PositionalAudio,
|
||||
} from "@react-three/drei";
|
||||
import { useFrame, useThree, extend } from "@react-three/fiber";
|
||||
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 { DriftParticlesLeft } from "./Particles/DriftParticlesLeft";
|
||||
import { DriftParticlesRight } from "./Particles/DriftParticlesRight";
|
||||
|
||||
import { PointParticle } from "./Particles/drifts/PointParticle";
|
||||
import { PointParticle } from "./Particles/PointParticle";
|
||||
|
||||
import { SmokeParticles } from "./Particles/smoke/SmokeParticles";
|
||||
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/hits/HitParticles";
|
||||
import { CoinParticles } from "./Particles/coins/CoinParticles";
|
||||
import { ItemParticles } from "./Particles/items/ItemParticles";
|
||||
import { geometry } from "maath";
|
||||
extend(geometry);
|
||||
import { useGamepad } from "./useGamepad";
|
||||
|
||||
export const PlayerController = ({
|
||||
player,
|
||||
userPlayer,
|
||||
setNetworkBananas,
|
||||
setNetworkShells,
|
||||
networkBananas,
|
||||
networkShells,
|
||||
}) => {
|
||||
export const PlayerController = () => {
|
||||
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 escPressed = useKeyboardControls((state) => state[Controls.escape]);
|
||||
|
||||
const [isOnGround, setIsOnGround] = useState(false);
|
||||
const body = useRef();
|
||||
const kart = useRef();
|
||||
|
@ -76,46 +64,16 @@ export const PlayerController = ({
|
|||
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 { buttonA, joystick, RB } = useGamepad();
|
||||
|
||||
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 text = useRef();
|
||||
|
||||
const { actions, shouldSlowDown, item, bananas, coins, id, controls } =
|
||||
useStore();
|
||||
const slowDownDuration = useRef(1500);
|
||||
|
||||
const rightWheel = useRef();
|
||||
const leftWheel = useRef();
|
||||
useEffect(() => {
|
||||
if (leftWheel.current && rightWheel.current && body.current) {
|
||||
actions.setLeftWheel(leftWheel.current);
|
||||
actions.setRightWheel(rightWheel.current);
|
||||
}
|
||||
}, [body.current]);
|
||||
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);
|
||||
engineSound.current.setPlaybackRate(currentSpeed / 10 + 0.1);
|
||||
jumpSound.current.setPlaybackRate(1.5);
|
||||
jumpSound.current.setVolume(0.5);
|
||||
driftSound.current.setVolume(0.2);
|
||||
|
||||
driftBlueSound.current.setVolume(0.5);
|
||||
driftOrangeSound.current.setVolume(0.6);
|
||||
driftPurpleSound.current.setVolume(0.7);
|
||||
// console.log(buttonA, joystick);
|
||||
|
||||
// HANDLING AND STEERING
|
||||
const kartRotation =
|
||||
kart.current.rotation.y - driftDirection.current * driftForce.current;
|
||||
|
@ -125,24 +83,12 @@ export const PlayerController = ({
|
|||
-Math.cos(kartRotation)
|
||||
);
|
||||
|
||||
if (escPressed) {
|
||||
actions.setGameStarted(false);
|
||||
}
|
||||
if(kartRotation){
|
||||
leftWheel.current.kartRotation = kartRotation;
|
||||
}
|
||||
if (leftPressed && currentSpeed > 0) {
|
||||
steeringAngle = currentSteeringSpeed;
|
||||
targetXPosition = -camMaxOffset;
|
||||
} else if (rightPressed && currentSpeed > 0) {
|
||||
steeringAngle = -currentSteeringSpeed;
|
||||
targetXPosition = camMaxOffset;
|
||||
} else if (rightPressed && currentSpeed < 0) {
|
||||
steeringAngle = currentSteeringSpeed;
|
||||
targetXPosition = -camMaxOffset;
|
||||
} else if (leftPressed && currentSpeed < 0) {
|
||||
steeringAngle = -currentSteeringSpeed;
|
||||
targetXPosition = camMaxOffset;
|
||||
} else {
|
||||
steeringAngle = 0;
|
||||
targetXPosition = 0;
|
||||
|
@ -150,19 +96,32 @@ export const PlayerController = ({
|
|||
}
|
||||
|
||||
// mouse steering
|
||||
const steer = joystick[0] * 0.8;
|
||||
|
||||
if (!driftLeft.current && !driftRight.current) {
|
||||
steeringAngle = currentSteeringSpeed * -pointer.x;
|
||||
targetXPosition = -camMaxOffset * -pointer.x;
|
||||
} else if (driftLeft.current && !driftRight.current) {
|
||||
steeringAngle = currentSteeringSpeed * -(pointer.x - 1);
|
||||
steeringAngle = currentSteeringSpeed * -(pointer.x - 0.5);
|
||||
targetXPosition = -camMaxOffset * -pointer.x;
|
||||
} else if (driftRight.current && !driftLeft.current) {
|
||||
steeringAngle = currentSteeringSpeed * -(pointer.x + 1);
|
||||
steeringAngle = currentSteeringSpeed * -(pointer.x + 0.5);
|
||||
targetXPosition = -camMaxOffset * -pointer.x;
|
||||
}
|
||||
|
||||
if (steer) {
|
||||
if (!driftLeft.current && !driftRight.current) {
|
||||
steeringAngle = currentSteeringSpeed * -joystick[0];
|
||||
targetXPosition = -camMaxOffset * -joystick[0];
|
||||
} else if (driftLeft.current && !driftRight.current) {
|
||||
steeringAngle = currentSteeringSpeed * -(joystick[0] - 1);
|
||||
targetXPosition = -camMaxOffset * -joystick[0];
|
||||
} else if (driftRight.current && !driftLeft.current) {
|
||||
steeringAngle = currentSteeringSpeed * -(joystick[0] + 1);
|
||||
targetXPosition = -camMaxOffset * -joystick[0];
|
||||
}
|
||||
}
|
||||
// ACCELERATING
|
||||
const shouldSlow = actions.getShouldSlowDown();
|
||||
|
||||
if (upPressed && currentSpeed < maxSpeed) {
|
||||
// Accelerate the kart within the maximum speed limit
|
||||
|
@ -172,7 +131,7 @@ export const PlayerController = ({
|
|||
} else if (
|
||||
upPressed &&
|
||||
currentSpeed > maxSpeed &&
|
||||
effectiveBoost.current > 0
|
||||
boostDuration.current > 0
|
||||
) {
|
||||
setCurrentSpeed(
|
||||
Math.max(currentSpeed - decceleration * delta * 144, maxSpeed)
|
||||
|
@ -189,25 +148,23 @@ export const PlayerController = ({
|
|||
);
|
||||
}
|
||||
}
|
||||
if (shouldSlow) {
|
||||
rightWheel.current.isSpinning = true;
|
||||
|
||||
if (buttonA && currentSpeed < maxSpeed) {
|
||||
// Accelerate the kart within the maximum speed limit
|
||||
setCurrentSpeed(
|
||||
Math.max(currentSpeed - decceleration * 2 * delta * 144, 0)
|
||||
Math.min(currentSpeed + acceleration * delta * 144, maxSpeed)
|
||||
);
|
||||
} else if (
|
||||
buttonA &&
|
||||
currentSpeed > maxSpeed &&
|
||||
boostDuration.current > 0
|
||||
) {
|
||||
setCurrentSpeed(
|
||||
Math.max(currentSpeed - decceleration * delta * 144, maxSpeed)
|
||||
);
|
||||
setCurrentSteeringSpeed(0);
|
||||
slowDownDuration.current -= 1500 * delta;
|
||||
setShouldLaunch(true);
|
||||
if (slowDownDuration.current <= 1) {
|
||||
rightWheel.current.isSpinning = false;
|
||||
actions.setShouldSlowDown(false);
|
||||
slowDownDuration.current = 1500;
|
||||
setShouldLaunch(false);
|
||||
}
|
||||
}
|
||||
|
||||
// REVERSING
|
||||
if (downPressed) {
|
||||
if (buttonA) {
|
||||
if (currentSteeringSpeed < MaxSteeringSpeed) {
|
||||
setCurrentSteeringSpeed(
|
||||
Math.min(
|
||||
|
@ -218,13 +175,14 @@ export const PlayerController = ({
|
|||
}
|
||||
}
|
||||
|
||||
if (downPressed && currentSpeed <= 0) {
|
||||
// REVERSING
|
||||
if (downPressed && currentSpeed < -maxSpeed) {
|
||||
setCurrentSpeed(
|
||||
Math.max(currentSpeed - acceleration * delta * 144, -maxSpeed)
|
||||
);
|
||||
}
|
||||
// DECELERATING
|
||||
else if (!upPressed) {
|
||||
else if (!buttonA && !downPressed) {
|
||||
if (currentSteeringSpeed > 0) {
|
||||
setCurrentSteeringSpeed(
|
||||
Math.max(currentSteeringSpeed - 0.00005 * delta * 144, 0)
|
||||
|
@ -257,50 +215,62 @@ export const PlayerController = ({
|
|||
);
|
||||
|
||||
// JUMPING
|
||||
if (jumpPressed && isOnGround && !jumpIsHeld.current) {
|
||||
if (jumpPressed && isOnFloor.current && !jumpIsHeld.current) {
|
||||
jumpForce.current += 10;
|
||||
isOnFloor.current = false;
|
||||
jumpIsHeld.current = true;
|
||||
} else if (RB && isOnFloor.current && !jumpIsHeld.current) {
|
||||
jumpForce.current += 10;
|
||||
isOnFloor.current = false;
|
||||
jumpIsHeld.current = true;
|
||||
jumpSound.current.play();
|
||||
setIsOnGround(false);
|
||||
|
||||
if (jumpSound.current.isPlaying) {
|
||||
jumpSound.current.stop();
|
||||
jumpSound.current.play();
|
||||
}
|
||||
}
|
||||
|
||||
if (isOnFloor.current && jumpForce.current > 0) {
|
||||
landingSound.current.play();
|
||||
}
|
||||
if (!isOnGround && jumpForce.current > 0) {
|
||||
if (!isOnFloor.current && jumpForce.current > 0) {
|
||||
jumpForce.current -= 1 * delta * 144;
|
||||
}
|
||||
if (!jumpPressed) {
|
||||
if (!jumpPressed && !RB) {
|
||||
jumpIsHeld.current = false;
|
||||
driftDirection.current = 0;
|
||||
driftForce.current = 0;
|
||||
driftLeft.current = false;
|
||||
driftRight.current = false;
|
||||
}
|
||||
console.log(jumpIsHeld.current);
|
||||
// DRIFTING
|
||||
if (
|
||||
jumpIsHeld.current &&
|
||||
currentSteeringSpeed > 0 &&
|
||||
upPressed &&
|
||||
pointer.x < -0.1 &&
|
||||
!driftRight.current
|
||||
) {
|
||||
driftLeft.current = true;
|
||||
}
|
||||
if (
|
||||
jumpIsHeld.current &&
|
||||
currentSteeringSpeed > 0 &&
|
||||
upPressed &&
|
||||
pointer.x > 0.1 &&
|
||||
!driftLeft.current
|
||||
) {
|
||||
driftRight.current = true;
|
||||
// if (
|
||||
// jumpIsHeld.current &&
|
||||
// currentSteeringSpeed > 0 &&
|
||||
// pointer.x < -0.1 &&
|
||||
// !driftRight.current
|
||||
// ) {
|
||||
// driftLeft.current = true;
|
||||
// }
|
||||
// if (
|
||||
// jumpIsHeld.current &&
|
||||
// currentSteeringSpeed > 0 &&
|
||||
// pointer.x > 0.1 &&
|
||||
// !driftLeft.current
|
||||
// ) {
|
||||
// driftRight.current = true;
|
||||
// }
|
||||
|
||||
if (steer) {
|
||||
if (
|
||||
jumpIsHeld.current &&
|
||||
currentSteeringSpeed > 0 &&
|
||||
steer < -0.1 &&
|
||||
!driftRight.current
|
||||
) {
|
||||
driftLeft.current = true;
|
||||
}
|
||||
if (
|
||||
jumpIsHeld.current &&
|
||||
currentSteeringSpeed > 0 &&
|
||||
steer > 0.1 &&
|
||||
!driftLeft.current
|
||||
) {
|
||||
driftRight.current = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!jumpIsHeld.current && !driftLeft.current && !driftRight.current) {
|
||||
|
@ -311,10 +281,6 @@ export const PlayerController = ({
|
|||
);
|
||||
setTurboColor(0xffffff);
|
||||
accumulatedDriftPower.current = 0;
|
||||
driftSound.current.stop();
|
||||
driftTwoSound.current.stop();
|
||||
driftOrangeSound.current.stop();
|
||||
driftPurpleSound.current.stop();
|
||||
}
|
||||
|
||||
if (driftLeft.current) {
|
||||
|
@ -322,28 +288,20 @@ export const PlayerController = ({
|
|||
driftForce.current = 0.4;
|
||||
mario.current.rotation.y = THREE.MathUtils.lerp(
|
||||
mario.current.rotation.y,
|
||||
steeringAngle * 25 + 0.4,
|
||||
steeringAngle * 50 + 0.5,
|
||||
0.05 * delta * 144
|
||||
);
|
||||
if (isOnFloor.current) {
|
||||
leftWheel.current.isSpinning = true;
|
||||
accumulatedDriftPower.current +=
|
||||
0.1 * (steeringAngle + 1) * delta * 144;
|
||||
}
|
||||
accumulatedDriftPower.current += 0.1 * (steeringAngle + 1) * delta * 144;
|
||||
}
|
||||
if (driftRight.current) {
|
||||
driftDirection.current = -1;
|
||||
driftForce.current = 0.4;
|
||||
mario.current.rotation.y = THREE.MathUtils.lerp(
|
||||
mario.current.rotation.y,
|
||||
-(-steeringAngle * 25 + 0.4),
|
||||
-(-steeringAngle * 50 + 0.5),
|
||||
0.05 * delta * 144
|
||||
);
|
||||
if(isOnFloor.current){
|
||||
leftWheel.current.isSpinning = true;
|
||||
accumulatedDriftPower.current += 0.1 * (-steeringAngle + 1) * delta * 144;
|
||||
|
||||
}
|
||||
accumulatedDriftPower.current += 0.1 * (-steeringAngle + 1) * delta * 144;
|
||||
}
|
||||
if (!driftLeft.current && !driftRight.current) {
|
||||
mario.current.rotation.y = THREE.MathUtils.lerp(
|
||||
|
@ -352,68 +310,46 @@ export const PlayerController = ({
|
|||
0.05 * delta * 144
|
||||
);
|
||||
setScale(0);
|
||||
if((pointer.x > 0.8 || pointer.x < -0.8) && currentSpeed > 20 && isOnFloor.current){
|
||||
leftWheel.current.isSpinning = true;
|
||||
} else {
|
||||
leftWheel.current.isSpinning = false;
|
||||
}
|
||||
}
|
||||
if (accumulatedDriftPower.current > blueTurboThreshold) {
|
||||
setTurboColor(0x00ffff);
|
||||
boostDuration.current = 50;
|
||||
driftBlueSound.current.play();
|
||||
}
|
||||
if (accumulatedDriftPower.current > orangeTurboThreshold) {
|
||||
setTurboColor(0xffcf00);
|
||||
boostDuration.current = 100;
|
||||
driftBlueSound.current.stop();
|
||||
driftOrangeSound.current.play();
|
||||
}
|
||||
if (accumulatedDriftPower.current > purpleTurboThreshold) {
|
||||
setTurboColor(0xff00ff);
|
||||
boostDuration.current = 250;
|
||||
driftOrangeSound.current.stop();
|
||||
driftPurpleSound.current.play();
|
||||
}
|
||||
|
||||
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 {
|
||||
setScale(vibration);
|
||||
}
|
||||
if (isOnFloor.current && !driftSound.current.isPlaying) {
|
||||
driftSound.current.play();
|
||||
driftTwoSound.current.play();
|
||||
landingSound.current.play();
|
||||
}
|
||||
}
|
||||
// RELEASING DRIFT
|
||||
|
||||
if (boostDuration.current > 1 && !jumpIsHeld.current) {
|
||||
setIsBoosting(true);
|
||||
effectiveBoost.current = boostDuration.current;
|
||||
boostDuration.current = 0;
|
||||
} else if (effectiveBoost.current <= 1) {
|
||||
} else if (boostDuration.current <= 1) {
|
||||
targetZPosition = 8;
|
||||
setIsBoosting(false);
|
||||
}
|
||||
|
||||
if (isBoosting && effectiveBoost.current > 1) {
|
||||
if (isBoosting && boostDuration.current > 1) {
|
||||
setCurrentSpeed(boostSpeed);
|
||||
effectiveBoost.current -= 1 * delta * 144;
|
||||
boostDuration.current -= 1 * delta * 144;
|
||||
targetZPosition = 10;
|
||||
if (!turboSound.current.isPlaying) turboSound.current.play();
|
||||
driftTwoSound.current.play();
|
||||
driftBlueSound.current.stop();
|
||||
driftOrangeSound.current.stop();
|
||||
driftPurpleSound.current.stop();
|
||||
} else if (effectiveBoost.current <= 1) {
|
||||
} else if (boostDuration.current <= 1) {
|
||||
setIsBoosting(false);
|
||||
targetZPosition = 8;
|
||||
turboSound.current.stop();
|
||||
}
|
||||
|
||||
// CAMERA WORK
|
||||
|
@ -446,117 +382,34 @@ export const PlayerController = ({
|
|||
|
||||
// SOUND WORK
|
||||
|
||||
// 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 });
|
||||
setCurrentSpeed(0);
|
||||
setCurrentSteeringSpeed(0);
|
||||
setIsBoosting(false);
|
||||
effectiveBoost.current = 0;
|
||||
setIsOnGround(false);
|
||||
jumpForce.current = 0;
|
||||
driftDirection.current = 0;
|
||||
kart.current.rotation.y = Math.PI / 2;
|
||||
}
|
||||
|
||||
// ITEMS
|
||||
|
||||
if (shootPressed && item === "banana") {
|
||||
const distanceBehind = 2;
|
||||
const scaledBackwardDirection =
|
||||
forwardDirection.multiplyScalar(distanceBehind);
|
||||
|
||||
const kartPosition = new THREE.Vector3(
|
||||
...vec3(body.current.translation())
|
||||
);
|
||||
|
||||
const bananaPosition = kartPosition.sub(scaledBackwardDirection);
|
||||
const newBanana = {
|
||||
id: Math.random() + "-" + +new Date(),
|
||||
position: bananaPosition,
|
||||
player: true,
|
||||
};
|
||||
setNetworkBananas([...networkBananas, newBanana]);
|
||||
|
||||
actions.useItem();
|
||||
}
|
||||
|
||||
if (shootPressed && item === "shell") {
|
||||
const distanceBehind = -2;
|
||||
const scaledBackwardDirection =
|
||||
forwardDirection.multiplyScalar(distanceBehind);
|
||||
|
||||
const kartPosition = new THREE.Vector3(
|
||||
body.current.translation().x,
|
||||
body.current.translation().y,
|
||||
body.current.translation().z
|
||||
);
|
||||
|
||||
const shellPosition = kartPosition.sub(scaledBackwardDirection);
|
||||
const newShell = {
|
||||
id: Math.random() + "-" + +new Date(),
|
||||
position: shellPosition,
|
||||
player: true,
|
||||
rotation: kartRotation,
|
||||
};
|
||||
setNetworkShells([...networkShells, newShell]);
|
||||
actions.useItem();
|
||||
}
|
||||
|
||||
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);
|
||||
// console.lowg(body.current.translation())
|
||||
});
|
||||
|
||||
return player.id === id ? (
|
||||
return (
|
||||
<group>
|
||||
<RigidBody
|
||||
ref={body}
|
||||
colliders={false}
|
||||
position={[8, 60, -119]}
|
||||
position={[8, 100, -96]}
|
||||
centerOfMass={[0, -1, 0]}
|
||||
mass={3}
|
||||
ccd
|
||||
name="player"
|
||||
type={player.id === id ? "dynamic" : "kinematic"}
|
||||
>
|
||||
<BallCollider
|
||||
args={[0.5]}
|
||||
mass={3}
|
||||
onCollisionEnter={({ other }) => {
|
||||
onCollisionEnter={(event) => {
|
||||
isOnFloor.current = true;
|
||||
setIsOnGround(true);
|
||||
}}
|
||||
onCollisionExit={({ other }) => {
|
||||
isOnFloor.current = false;
|
||||
setIsOnGround(false);
|
||||
}}
|
||||
/>
|
||||
</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
|
||||
|
@ -567,15 +420,6 @@ export const PlayerController = ({
|
|||
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
|
||||
|
@ -586,112 +430,37 @@ export const PlayerController = ({
|
|||
opacity={0.4}
|
||||
/>
|
||||
</mesh>
|
||||
<mesh position={[-0.46, 0.05, 0.3]} ref={leftWheel}></mesh>
|
||||
<mesh position={[0.46, 0.05, 0.3]} ref={rightWheel}></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} /> */}
|
||||
<FlameParticles isBoosting={isBoosting} />
|
||||
<DriftParticlesLeft turboColor={turboColor} scale={scale} />
|
||||
<DriftParticlesRight turboColor={turboColor} scale={scale} />
|
||||
<SmokeParticles
|
||||
driftRight={driftRight.current}
|
||||
driftLeft={driftLeft.current}
|
||||
/>
|
||||
<PointParticle
|
||||
position={[-0.6, 0.05, 0.5]}
|
||||
png="./particles/circle.png"
|
||||
png="./circle.png"
|
||||
turboColor={turboColor}
|
||||
/>
|
||||
<PointParticle
|
||||
position={[0.6, 0.05, 0.5]}
|
||||
png="./particles/circle.png"
|
||||
png="./circle.png"
|
||||
turboColor={turboColor}
|
||||
/>
|
||||
<PointParticle
|
||||
position={[-0.6, 0.05, 0.5]}
|
||||
png="./particles/star.png"
|
||||
png="./star.png"
|
||||
turboColor={turboColor}
|
||||
/>
|
||||
<PointParticle
|
||||
position={[0.6, 0.05, 0.5]}
|
||||
png="./particles/star.png"
|
||||
png="./star.png"
|
||||
turboColor={turboColor}
|
||||
/>
|
||||
<HitParticles shouldLaunch={shouldLaunch} />
|
||||
</group>
|
||||
|
||||
{/* <ContactShadows frames={1} /> */}
|
||||
<PerspectiveCamera
|
||||
makeDefault
|
||||
position={[0, 2, 8]}
|
||||
fov={50}
|
||||
ref={cam}
|
||||
far={5000}
|
||||
/>
|
||||
<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;
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,670 +0,0 @@
|
|||
import { Controls } from "../App";
|
||||
import { BallCollider, RigidBody, useRapier, vec3 } from "@react-three/rapier";
|
||||
import {
|
||||
useKeyboardControls,
|
||||
PerspectiveCamera,
|
||||
PositionalAudio,
|
||||
} from "@react-three/drei";
|
||||
import { useFrame, useThree, extend } 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 { 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 { geometry } from "maath";
|
||||
import { useGamepad } from "./useGamepad";
|
||||
extend(geometry);
|
||||
|
||||
export const PlayerControllerGamepad = ({
|
||||
player,
|
||||
userPlayer,
|
||||
setNetworkBananas,
|
||||
setNetworkShells,
|
||||
networkBananas,
|
||||
networkShells,
|
||||
}) => {
|
||||
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 text = useRef();
|
||||
|
||||
const { actions, shouldSlowDown, item, bananas, coins, id, controls } =
|
||||
useStore();
|
||||
const slowDownDuration = useRef(1500);
|
||||
const { buttonA, buttonB, RB, LB, joystick, select, start } = useGamepad();
|
||||
|
||||
const skidRotation = useRef(0);
|
||||
|
||||
const rightWheel = useRef();
|
||||
const leftWheel = useRef();
|
||||
const isDrifting = useRef(false);
|
||||
useEffect(() => {
|
||||
if (leftWheel.current && rightWheel.current && body.current) {
|
||||
actions.setLeftWheel(leftWheel.current);
|
||||
actions.setRightWheel(rightWheel.current);
|
||||
}
|
||||
}, [body.current]);
|
||||
|
||||
useFrame(({ pointer, clock }, delta) => {
|
||||
if (player.id !== id) return;
|
||||
const time = clock.getElapsedTime();
|
||||
if (!body.current && !mario.current) return;
|
||||
isDrifting.current = driftLeft.current || driftRight.current;
|
||||
engineSound.current.setVolume(currentSpeed / 300 + 0.2);
|
||||
engineSound.current.setPlaybackRate(currentSpeed / 10 + 0.1);
|
||||
jumpSound.current.setPlaybackRate(1.5);
|
||||
jumpSound.current.setVolume(0.5);
|
||||
driftSound.current.setVolume(0.2);
|
||||
|
||||
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;
|
||||
const forwardDirection = new THREE.Vector3(
|
||||
-Math.sin(kartRotation),
|
||||
0,
|
||||
-Math.cos(kartRotation)
|
||||
);
|
||||
|
||||
if (start) {
|
||||
actions.setGameStarted(false);
|
||||
}
|
||||
leftWheel.current.kartRotation = kartRotation ;
|
||||
|
||||
if (!driftLeft.current && !driftRight.current) {
|
||||
steeringAngle = currentSteeringSpeed * -joystick[0];
|
||||
targetXPosition = -camMaxOffset * -joystick[0];
|
||||
} else if (driftLeft.current && !driftRight.current) {
|
||||
steeringAngle = currentSteeringSpeed * -(joystick[0] - 1);
|
||||
targetXPosition = -camMaxOffset * -joystick[0];
|
||||
} else if (driftRight.current && !driftLeft.current) {
|
||||
steeringAngle = currentSteeringSpeed * -(joystick[0] + 1);
|
||||
targetXPosition = -camMaxOffset * -joystick[0];
|
||||
}
|
||||
// ACCELERATING
|
||||
const shouldSlow = actions.getShouldSlowDown();
|
||||
|
||||
if (buttonA && currentSpeed < maxSpeed) {
|
||||
// Accelerate the kart within the maximum speed limit
|
||||
setCurrentSpeed(
|
||||
Math.min(currentSpeed + acceleration * delta * 144, maxSpeed)
|
||||
);
|
||||
} else if (
|
||||
buttonA &&
|
||||
currentSpeed > maxSpeed &&
|
||||
effectiveBoost.current > 0
|
||||
) {
|
||||
setCurrentSpeed(
|
||||
Math.max(currentSpeed - decceleration * delta * 144, maxSpeed)
|
||||
);
|
||||
}
|
||||
|
||||
if (buttonA) {
|
||||
if (currentSteeringSpeed < MaxSteeringSpeed) {
|
||||
setCurrentSteeringSpeed(
|
||||
Math.min(
|
||||
currentSteeringSpeed + 0.0001 * delta * 144,
|
||||
MaxSteeringSpeed
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
if (shouldSlow) {
|
||||
rightWheel.current.isSpinning = true;
|
||||
setCurrentSpeed(
|
||||
Math.max(currentSpeed - decceleration * 2 * delta * 144, 0)
|
||||
);
|
||||
setCurrentSteeringSpeed(0);
|
||||
slowDownDuration.current -= 1500 * delta;
|
||||
setShouldLaunch(true);
|
||||
if (slowDownDuration.current <= 1) {
|
||||
rightWheel.current.isSpinning = false;
|
||||
actions.setShouldSlowDown(false);
|
||||
slowDownDuration.current = 1500;
|
||||
setShouldLaunch(false);
|
||||
}
|
||||
}
|
||||
|
||||
// REVERSING
|
||||
if (buttonB) {
|
||||
if (currentSteeringSpeed < MaxSteeringSpeed) {
|
||||
setCurrentSteeringSpeed(
|
||||
Math.min(
|
||||
currentSteeringSpeed + 0.0001 * delta * 144,
|
||||
MaxSteeringSpeed
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonB && currentSpeed <= 0) {
|
||||
setCurrentSpeed(
|
||||
Math.max(currentSpeed - acceleration * delta * 144, -maxSpeed)
|
||||
);
|
||||
}
|
||||
// DECELERATING
|
||||
else if (!buttonA) {
|
||||
if (currentSteeringSpeed > 0) {
|
||||
setCurrentSteeringSpeed(
|
||||
Math.max(currentSteeringSpeed - 0.00005 * delta * 144, 0)
|
||||
);
|
||||
} else if (currentSteeringSpeed < 0) {
|
||||
setCurrentSteeringSpeed(
|
||||
Math.min(currentSteeringSpeed + 0.00005 * delta * 144, 0)
|
||||
);
|
||||
}
|
||||
setCurrentSpeed(Math.max(currentSpeed - decceleration * delta * 144, 0));
|
||||
}
|
||||
|
||||
// Update the kart's rotation based on the steering angle
|
||||
kart.current.rotation.y += steeringAngle * delta * 144;
|
||||
|
||||
// Apply damping to simulate slowdown when no keys are pressed
|
||||
body.current.applyImpulse(
|
||||
{
|
||||
x: -body.current.linvel().x * (1 - damping) * delta * 144,
|
||||
y: 0,
|
||||
z: -body.current.linvel().z * (1 - damping) * delta * 144,
|
||||
},
|
||||
true
|
||||
);
|
||||
const bodyPosition = body.current.translation();
|
||||
kart.current.position.set(
|
||||
bodyPosition.x,
|
||||
bodyPosition.y - 0.5,
|
||||
bodyPosition.z
|
||||
);
|
||||
|
||||
// JUMPING
|
||||
if (RB && isOnGround && !jumpIsHeld.current) {
|
||||
jumpForce.current += 10;
|
||||
isOnFloor.current = false;
|
||||
jumpIsHeld.current = true;
|
||||
jumpSound.current.play();
|
||||
setIsOnGround(false);
|
||||
|
||||
if (jumpSound.current.isPlaying) {
|
||||
jumpSound.current.stop();
|
||||
jumpSound.current.play();
|
||||
}
|
||||
}
|
||||
|
||||
if (isOnFloor.current && jumpForce.current > 0) {
|
||||
landingSound.current.play();
|
||||
}
|
||||
if (!isOnGround && jumpForce.current > 0) {
|
||||
jumpForce.current -= 1 * delta * 144;
|
||||
}
|
||||
if (!RB) {
|
||||
jumpIsHeld.current = false;
|
||||
driftDirection.current = 0;
|
||||
driftForce.current = 0;
|
||||
driftLeft.current = false;
|
||||
driftRight.current = false;
|
||||
}
|
||||
// DRIFTING
|
||||
if (
|
||||
jumpIsHeld.current &&
|
||||
currentSteeringSpeed > 0 &&
|
||||
joystick[0] < -0.1 &&
|
||||
!driftRight.current
|
||||
) {
|
||||
driftLeft.current = true;
|
||||
}
|
||||
if (
|
||||
jumpIsHeld.current &&
|
||||
currentSteeringSpeed > 0 &&
|
||||
joystick[0] > 0.1 &&
|
||||
!driftLeft.current
|
||||
) {
|
||||
driftRight.current = true;
|
||||
}
|
||||
|
||||
if (!jumpIsHeld.current && !driftLeft.current && !driftRight.current) {
|
||||
mario.current.rotation.y = THREE.MathUtils.lerp(
|
||||
mario.current.rotation.y,
|
||||
0,
|
||||
0.0001 * delta * 144
|
||||
);
|
||||
setTurboColor(0xffffff);
|
||||
accumulatedDriftPower.current = 0;
|
||||
driftSound.current.stop();
|
||||
driftTwoSound.current.stop();
|
||||
driftOrangeSound.current.stop();
|
||||
driftPurpleSound.current.stop();
|
||||
}
|
||||
|
||||
if (driftLeft.current) {
|
||||
driftDirection.current = 1;
|
||||
driftForce.current = 0.4;
|
||||
mario.current.rotation.y = THREE.MathUtils.lerp(
|
||||
mario.current.rotation.y,
|
||||
steeringAngle * 25 + 0.4,
|
||||
0.05 * delta * 144
|
||||
);
|
||||
if(isOnFloor.current){
|
||||
leftWheel.current.isSpinning = true;
|
||||
accumulatedDriftPower.current += 0.1 * (steeringAngle + 1) * delta * 144;
|
||||
|
||||
}
|
||||
}
|
||||
if (driftRight.current ) {
|
||||
driftDirection.current = -1;
|
||||
driftForce.current = 0.4;
|
||||
mario.current.rotation.y = THREE.MathUtils.lerp(
|
||||
mario.current.rotation.y,
|
||||
-(-steeringAngle * 25 + 0.4),
|
||||
0.05 * delta * 144
|
||||
);
|
||||
if(isOnFloor.current){
|
||||
leftWheel.current.isSpinning = true;
|
||||
accumulatedDriftPower.current += 0.1 * (-steeringAngle + 1) * delta * 144;
|
||||
|
||||
}
|
||||
}
|
||||
if (!driftLeft.current && !driftRight.current) {
|
||||
mario.current.rotation.y = THREE.MathUtils.lerp(
|
||||
mario.current.rotation.y,
|
||||
steeringAngle * 30,
|
||||
0.05 * delta * 144
|
||||
);
|
||||
setScale(0);
|
||||
|
||||
if((joystick[0] > 0.8 || joystick[0] < -0.8) && currentSpeed > 20 && isOnFloor.current){
|
||||
leftWheel.current.isSpinning = true;
|
||||
} else {
|
||||
leftWheel.current.isSpinning = false;
|
||||
}
|
||||
}
|
||||
if (accumulatedDriftPower.current > blueTurboThreshold) {
|
||||
setTurboColor(0x00ffff);
|
||||
boostDuration.current = 50;
|
||||
driftBlueSound.current.play();
|
||||
}
|
||||
if (accumulatedDriftPower.current > orangeTurboThreshold) {
|
||||
setTurboColor(0xffcf00);
|
||||
boostDuration.current = 100;
|
||||
driftBlueSound.current.stop();
|
||||
driftOrangeSound.current.play();
|
||||
}
|
||||
if (accumulatedDriftPower.current > purpleTurboThreshold) {
|
||||
setTurboColor(0xff00ff);
|
||||
boostDuration.current = 250;
|
||||
driftOrangeSound.current.stop();
|
||||
driftPurpleSound.current.play();
|
||||
}
|
||||
|
||||
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 {
|
||||
setScale(vibration);
|
||||
}
|
||||
if (isOnFloor.current && !driftSound.current.isPlaying) {
|
||||
driftSound.current.play();
|
||||
driftTwoSound.current.play();
|
||||
landingSound.current.play();
|
||||
}
|
||||
}
|
||||
// RELEASING DRIFT
|
||||
|
||||
if (boostDuration.current > 1 && !jumpIsHeld.current) {
|
||||
setIsBoosting(true);
|
||||
effectiveBoost.current = boostDuration.current;
|
||||
boostDuration.current = 0;
|
||||
} else if (effectiveBoost.current <= 1) {
|
||||
targetZPosition = 8;
|
||||
setIsBoosting(false);
|
||||
}
|
||||
|
||||
if (isBoosting && effectiveBoost.current > 1) {
|
||||
setCurrentSpeed(boostSpeed);
|
||||
effectiveBoost.current -= 1 * delta * 144;
|
||||
targetZPosition = 10;
|
||||
if (!turboSound.current.isPlaying) turboSound.current.play();
|
||||
driftTwoSound.current.play();
|
||||
driftBlueSound.current.stop();
|
||||
driftOrangeSound.current.stop();
|
||||
driftPurpleSound.current.stop();
|
||||
} else if (effectiveBoost.current <= 1) {
|
||||
setIsBoosting(false);
|
||||
targetZPosition = 8;
|
||||
turboSound.current.stop();
|
||||
}
|
||||
|
||||
// CAMERA WORK
|
||||
|
||||
cam.current.updateMatrixWorld();
|
||||
|
||||
cam.current.position.x = THREE.MathUtils.lerp(
|
||||
cam.current.position.x,
|
||||
targetXPosition,
|
||||
0.01 * delta * 144
|
||||
);
|
||||
|
||||
|
||||
cam.current.position.z = THREE.MathUtils.lerp(
|
||||
cam.current.position.z,
|
||||
targetZPosition,
|
||||
0.01 * delta * 144
|
||||
);
|
||||
|
||||
body.current.applyImpulse(
|
||||
{
|
||||
x: forwardDirection.x * currentSpeed * delta * 144,
|
||||
y: 0 + jumpForce.current * delta * 144,
|
||||
z: forwardDirection.z * currentSpeed * delta * 144,
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
// Update the kart's rotation based on the steering angle
|
||||
setSteeringAngleWheels(steeringAngle * 25);
|
||||
|
||||
// SOUND WORK
|
||||
|
||||
// MISC
|
||||
|
||||
if (select) {
|
||||
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);
|
||||
effectiveBoost.current = 0;
|
||||
setIsOnGround(false);
|
||||
jumpForce.current = 0;
|
||||
driftDirection.current = 0;
|
||||
kart.current.rotation.y = Math.PI / 2;
|
||||
}
|
||||
|
||||
// ITEMS
|
||||
|
||||
if (LB && item === "banana") {
|
||||
const distanceBehind = 2;
|
||||
const scaledBackwardDirection =
|
||||
forwardDirection.multiplyScalar(distanceBehind);
|
||||
|
||||
const kartPosition = new THREE.Vector3(
|
||||
...vec3(body.current.translation())
|
||||
);
|
||||
|
||||
const bananaPosition = kartPosition.sub(scaledBackwardDirection);
|
||||
const newBanana = {
|
||||
id: Math.random() + "-" + +new Date(),
|
||||
position: bananaPosition,
|
||||
player: true,
|
||||
};
|
||||
setNetworkBananas([...networkBananas, newBanana]);
|
||||
|
||||
actions.useItem();
|
||||
}
|
||||
|
||||
if (LB && item === "shell") {
|
||||
const distanceBehind = -2;
|
||||
const scaledBackwardDirection =
|
||||
forwardDirection.multiplyScalar(distanceBehind);
|
||||
|
||||
const kartPosition = new THREE.Vector3(
|
||||
body.current.translation().x,
|
||||
body.current.translation().y,
|
||||
body.current.translation().z
|
||||
);
|
||||
|
||||
const shellPosition = kartPosition.sub(scaledBackwardDirection);
|
||||
const newShell = {
|
||||
id: Math.random() + "-" + +new Date(),
|
||||
position: shellPosition,
|
||||
player: true,
|
||||
rotation: kartRotation,
|
||||
};
|
||||
setNetworkShells([...networkShells, newShell]);
|
||||
actions.useItem();
|
||||
}
|
||||
|
||||
if (LB && 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);
|
||||
|
||||
skidRotation.current = kartRotation + mario.current.rotation.y;
|
||||
});
|
||||
|
||||
return player.id === id ? (
|
||||
<group>
|
||||
<RigidBody
|
||||
ref={body}
|
||||
colliders={false}
|
||||
position={[8, 60, -119]}
|
||||
centerOfMass={[0, -1, 0]}
|
||||
mass={3}
|
||||
ccd
|
||||
name="player"
|
||||
type={player.id === id ? "dynamic" : "kinematic"}
|
||||
>
|
||||
<BallCollider
|
||||
args={[0.5]}
|
||||
mass={3}
|
||||
onCollisionEnter={({ other }) => {
|
||||
isOnFloor.current = true;
|
||||
setIsOnGround(true);
|
||||
}}
|
||||
onCollisionExit={({ other }) => {
|
||||
isOnFloor.current = false;
|
||||
setIsOnGround(false);
|
||||
}}
|
||||
/>
|
||||
</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} ref={rightWheel}>
|
||||
<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.46, 0.05, 0.3]} ref={leftWheel}></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.46, 0.05, 0.3]} ref={rightWheel}></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} /> */}
|
||||
<PerspectiveCamera
|
||||
makeDefault
|
||||
position={[0, 2, 8]}
|
||||
fov={50}
|
||||
ref={cam}
|
||||
far={5000}
|
||||
/>
|
||||
<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;
|
||||
};
|
|
@ -1,686 +0,0 @@
|
|||
import { Controls } from "../App";
|
||||
import { BallCollider, RigidBody, useRapier, vec3 } from "@react-three/rapier";
|
||||
import {
|
||||
useKeyboardControls,
|
||||
PerspectiveCamera,
|
||||
PositionalAudio,
|
||||
} from "@react-three/drei";
|
||||
import { useFrame, useThree, extend } 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 { SmokeParticles } from "./Particles/smoke/SmokeParticles";
|
||||
import { FlameParticle } from "./Particles/flames/FlameParticle";
|
||||
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 { geometry } from "maath";
|
||||
extend(geometry);
|
||||
|
||||
export const PlayerControllerKeyboard = ({
|
||||
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]);
|
||||
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 escPressed = useKeyboardControls((state) => state[Controls.escape]);
|
||||
|
||||
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 text = useRef();
|
||||
|
||||
const { actions, shouldSlowDown, item, bananas, coins, id, controls } =
|
||||
useStore();
|
||||
const slowDownDuration = useRef(1500);
|
||||
|
||||
const rightWheel = useRef();
|
||||
const leftWheel = useRef();
|
||||
const isDrifting = useRef(false);
|
||||
useEffect(() => {
|
||||
if (leftWheel.current && rightWheel.current && body.current) {
|
||||
actions.setLeftWheel(leftWheel.current);
|
||||
actions.setRightWheel(rightWheel.current);
|
||||
}
|
||||
}, [body.current]);
|
||||
|
||||
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);
|
||||
engineSound.current.setPlaybackRate(currentSpeed / 10 + 0.1);
|
||||
jumpSound.current.setPlaybackRate(1.5);
|
||||
jumpSound.current.setVolume(0.5);
|
||||
driftSound.current.setVolume(0.2);
|
||||
|
||||
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;
|
||||
const forwardDirection = new THREE.Vector3(
|
||||
-Math.sin(kartRotation),
|
||||
0,
|
||||
-Math.cos(kartRotation)
|
||||
);
|
||||
leftWheel.current.kartRotation = kartRotation;
|
||||
if (escPressed) {
|
||||
actions.setGameStarted(false);
|
||||
}
|
||||
|
||||
if (leftPressed && currentSpeed > 0) {
|
||||
steeringAngle = currentSteeringSpeed;
|
||||
targetXPosition = -camMaxOffset;
|
||||
} else if (rightPressed && currentSpeed > 0) {
|
||||
steeringAngle = -currentSteeringSpeed;
|
||||
targetXPosition = camMaxOffset;
|
||||
} else if (rightPressed && currentSpeed < 0) {
|
||||
steeringAngle = currentSteeringSpeed;
|
||||
targetXPosition = -camMaxOffset;
|
||||
} else if (leftPressed && currentSpeed < 0) {
|
||||
steeringAngle = -currentSteeringSpeed;
|
||||
targetXPosition = camMaxOffset;
|
||||
} else {
|
||||
steeringAngle = 0;
|
||||
targetXPosition = 0;
|
||||
1;
|
||||
}
|
||||
|
||||
// ACCELERATING
|
||||
const shouldSlow = actions.getShouldSlowDown();
|
||||
|
||||
if (upPressed && currentSpeed < maxSpeed) {
|
||||
// Accelerate the kart within the maximum speed limit
|
||||
setCurrentSpeed(
|
||||
Math.min(currentSpeed + acceleration * delta * 144, maxSpeed)
|
||||
);
|
||||
} else if (
|
||||
upPressed &&
|
||||
currentSpeed > maxSpeed &&
|
||||
effectiveBoost.current > 0
|
||||
) {
|
||||
setCurrentSpeed(
|
||||
Math.max(currentSpeed - decceleration * delta * 144, maxSpeed)
|
||||
);
|
||||
}
|
||||
|
||||
if (upPressed) {
|
||||
if (currentSteeringSpeed < MaxSteeringSpeed) {
|
||||
setCurrentSteeringSpeed(
|
||||
Math.min(
|
||||
currentSteeringSpeed + 0.0001 * delta * 144,
|
||||
MaxSteeringSpeed
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
if (shouldSlow) {
|
||||
rightWheel.current.isSpinning = true;
|
||||
setCurrentSpeed(
|
||||
Math.max(currentSpeed - decceleration * 2 * delta * 144, 0)
|
||||
);
|
||||
setCurrentSteeringSpeed(0);
|
||||
slowDownDuration.current -= 1500 * delta;
|
||||
setShouldLaunch(true);
|
||||
if (slowDownDuration.current <= 1) {
|
||||
rightWheel.current.isSpinning = false;
|
||||
actions.setShouldSlowDown(false);
|
||||
slowDownDuration.current = 1500;
|
||||
setShouldLaunch(false);
|
||||
}
|
||||
}
|
||||
|
||||
// REVERSING
|
||||
if (downPressed) {
|
||||
if (currentSteeringSpeed < MaxSteeringSpeed) {
|
||||
setCurrentSteeringSpeed(
|
||||
Math.min(
|
||||
currentSteeringSpeed + 0.0001 * delta * 144,
|
||||
MaxSteeringSpeed
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (downPressed && currentSpeed <= 0) {
|
||||
setCurrentSpeed(
|
||||
Math.max(currentSpeed - acceleration * delta * 144, -maxSpeed)
|
||||
);
|
||||
}
|
||||
// DECELERATING
|
||||
else if (!upPressed) {
|
||||
if (currentSteeringSpeed > 0) {
|
||||
setCurrentSteeringSpeed(
|
||||
Math.max(currentSteeringSpeed - 0.00005 * delta * 144, 0)
|
||||
);
|
||||
} else if (currentSteeringSpeed < 0) {
|
||||
setCurrentSteeringSpeed(
|
||||
Math.min(currentSteeringSpeed + 0.00005 * delta * 144, 0)
|
||||
);
|
||||
}
|
||||
setCurrentSpeed(Math.max(currentSpeed - decceleration * delta * 144, 0));
|
||||
}
|
||||
|
||||
// Update the kart's rotation based on the steering angle
|
||||
kart.current.rotation.y += steeringAngle * delta * 144;
|
||||
|
||||
// Apply damping to simulate slowdown when no keys are pressed
|
||||
body.current.applyImpulse(
|
||||
{
|
||||
x: -body.current.linvel().x * (1 - damping) * delta * 144,
|
||||
y: 0,
|
||||
z: -body.current.linvel().z * (1 - damping) * delta * 144,
|
||||
},
|
||||
true
|
||||
);
|
||||
const bodyPosition = body.current.translation();
|
||||
kart.current.position.set(
|
||||
bodyPosition.x,
|
||||
bodyPosition.y - 0.5,
|
||||
bodyPosition.z
|
||||
);
|
||||
|
||||
// JUMPING
|
||||
if (jumpPressed && isOnGround && !jumpIsHeld.current) {
|
||||
jumpForce.current += 10;
|
||||
isOnFloor.current = false;
|
||||
jumpIsHeld.current = true;
|
||||
jumpSound.current.play();
|
||||
setIsOnGround(false);
|
||||
|
||||
if (jumpSound.current.isPlaying) {
|
||||
jumpSound.current.stop();
|
||||
jumpSound.current.play();
|
||||
}
|
||||
}
|
||||
|
||||
if (isOnFloor.current && jumpForce.current > 0) {
|
||||
landingSound.current.play();
|
||||
}
|
||||
if (!isOnGround && jumpForce.current > 0) {
|
||||
jumpForce.current -= 1 * delta * 144;
|
||||
}
|
||||
if (!jumpPressed) {
|
||||
jumpIsHeld.current = false;
|
||||
driftDirection.current = 0;
|
||||
driftForce.current = 0;
|
||||
driftLeft.current = false;
|
||||
driftRight.current = false;
|
||||
}
|
||||
// DRIFTING
|
||||
if (
|
||||
jumpIsHeld.current &&
|
||||
currentSteeringSpeed > 0 &&
|
||||
upPressed &&
|
||||
leftPressed &&
|
||||
!driftRight.current
|
||||
) {
|
||||
driftLeft.current = true;
|
||||
}
|
||||
if (
|
||||
jumpIsHeld.current &&
|
||||
currentSteeringSpeed > 0 &&
|
||||
upPressed &&
|
||||
rightPressed > 0.1 &&
|
||||
!driftLeft.current
|
||||
) {
|
||||
driftRight.current = true;
|
||||
}
|
||||
|
||||
if (!jumpIsHeld.current && !driftLeft.current && !driftRight.current) {
|
||||
mario.current.rotation.y = THREE.MathUtils.lerp(
|
||||
mario.current.rotation.y,
|
||||
0,
|
||||
0.0001 * delta * 144
|
||||
);
|
||||
setTurboColor(0xffffff);
|
||||
accumulatedDriftPower.current = 0;
|
||||
driftSound.current.stop();
|
||||
driftTwoSound.current.stop();
|
||||
driftOrangeSound.current.stop();
|
||||
driftPurpleSound.current.stop();
|
||||
}
|
||||
|
||||
if (driftLeft.current) {
|
||||
driftDirection.current = 1;
|
||||
driftForce.current = 0.4;
|
||||
mario.current.rotation.y = THREE.MathUtils.lerp(
|
||||
mario.current.rotation.y,
|
||||
steeringAngle * 25 + 0.4,
|
||||
0.05 * delta * 144
|
||||
);
|
||||
if (isOnFloor.current) {
|
||||
leftWheel.current.isSpinning = true;
|
||||
accumulatedDriftPower.current +=
|
||||
0.1 * (steeringAngle + 1) * delta * 144;
|
||||
}
|
||||
}
|
||||
if (driftRight.current) {
|
||||
driftDirection.current = -1;
|
||||
driftForce.current = 0.4;
|
||||
mario.current.rotation.y = THREE.MathUtils.lerp(
|
||||
mario.current.rotation.y,
|
||||
-(-steeringAngle * 25 + 0.4),
|
||||
0.05 * delta * 144
|
||||
);
|
||||
if (isOnFloor.current) {
|
||||
leftWheel.current.isSpinning = true;
|
||||
accumulatedDriftPower.current +=
|
||||
0.1 * (-steeringAngle + 1) * delta * 144;
|
||||
}
|
||||
}
|
||||
if (!driftLeft.current && !driftRight.current) {
|
||||
mario.current.rotation.y = THREE.MathUtils.lerp(
|
||||
mario.current.rotation.y,
|
||||
steeringAngle * 30,
|
||||
0.05 * delta * 144
|
||||
);
|
||||
setScale(0);
|
||||
if((leftPressed || rightPressed) && currentSpeed > 20 && isOnFloor.current){
|
||||
leftWheel.current.isSpinning = true;
|
||||
} else {
|
||||
leftWheel.current.isSpinning = false;
|
||||
}
|
||||
}
|
||||
if (accumulatedDriftPower.current > blueTurboThreshold) {
|
||||
setTurboColor(0x00ffff);
|
||||
boostDuration.current = 50;
|
||||
driftBlueSound.current.play();
|
||||
}
|
||||
if (accumulatedDriftPower.current > orangeTurboThreshold) {
|
||||
setTurboColor(0xffcf00);
|
||||
boostDuration.current = 100;
|
||||
driftBlueSound.current.stop();
|
||||
driftOrangeSound.current.play();
|
||||
}
|
||||
if (accumulatedDriftPower.current > purpleTurboThreshold) {
|
||||
setTurboColor(0xff00ff);
|
||||
boostDuration.current = 250;
|
||||
driftOrangeSound.current.stop();
|
||||
driftPurpleSound.current.play();
|
||||
}
|
||||
|
||||
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 {
|
||||
setScale(vibration);
|
||||
}
|
||||
if (isOnFloor.current && !driftSound.current.isPlaying) {
|
||||
driftSound.current.play();
|
||||
driftTwoSound.current.play();
|
||||
landingSound.current.play();
|
||||
}
|
||||
}
|
||||
// RELEASING DRIFT
|
||||
|
||||
if (boostDuration.current > 1 && !jumpIsHeld.current) {
|
||||
setIsBoosting(true);
|
||||
effectiveBoost.current = boostDuration.current;
|
||||
boostDuration.current = 0;
|
||||
} else if (effectiveBoost.current <= 1) {
|
||||
targetZPosition = 8;
|
||||
setIsBoosting(false);
|
||||
}
|
||||
|
||||
if (isBoosting && effectiveBoost.current > 1) {
|
||||
setCurrentSpeed(boostSpeed);
|
||||
effectiveBoost.current -= 1 * delta * 144;
|
||||
targetZPosition = 10;
|
||||
if (!turboSound.current.isPlaying) turboSound.current.play();
|
||||
driftTwoSound.current.play();
|
||||
driftBlueSound.current.stop();
|
||||
driftOrangeSound.current.stop();
|
||||
driftPurpleSound.current.stop();
|
||||
} else if (effectiveBoost.current <= 1) {
|
||||
setIsBoosting(false);
|
||||
targetZPosition = 8;
|
||||
turboSound.current.stop();
|
||||
}
|
||||
|
||||
// CAMERA WORK
|
||||
|
||||
cam.current.updateMatrixWorld();
|
||||
|
||||
cam.current.position.x = THREE.MathUtils.lerp(
|
||||
cam.current.position.x,
|
||||
targetXPosition,
|
||||
0.01 * delta * 144
|
||||
);
|
||||
|
||||
cam.current.position.z = THREE.MathUtils.lerp(
|
||||
cam.current.position.z,
|
||||
targetZPosition,
|
||||
0.01 * delta * 144
|
||||
);
|
||||
|
||||
body.current.applyImpulse(
|
||||
{
|
||||
x: forwardDirection.x * currentSpeed * delta * 144,
|
||||
y: 0 + jumpForce.current * delta * 144,
|
||||
z: forwardDirection.z * currentSpeed * delta * 144,
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
// Update the kart's rotation based on the steering angle
|
||||
setSteeringAngleWheels(steeringAngle * 25);
|
||||
|
||||
// SOUND WORK
|
||||
|
||||
// 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 });
|
||||
setCurrentSpeed(0);
|
||||
setCurrentSteeringSpeed(0);
|
||||
setIsBoosting(false);
|
||||
effectiveBoost.current = 0;
|
||||
setIsOnGround(false);
|
||||
jumpForce.current = 0;
|
||||
driftDirection.current = 0;
|
||||
kart.current.rotation.y = Math.PI / 2;
|
||||
}
|
||||
|
||||
// ITEMS
|
||||
|
||||
if (shootPressed && item === "banana") {
|
||||
const distanceBehind = 2;
|
||||
const scaledBackwardDirection =
|
||||
forwardDirection.multiplyScalar(distanceBehind);
|
||||
|
||||
const kartPosition = new THREE.Vector3(
|
||||
...vec3(body.current.translation())
|
||||
);
|
||||
|
||||
const bananaPosition = kartPosition.sub(scaledBackwardDirection);
|
||||
const newBanana = {
|
||||
id: Math.random() + "-" + +new Date(),
|
||||
position: bananaPosition,
|
||||
player: true,
|
||||
};
|
||||
setNetworkBananas([...networkBananas, newBanana]);
|
||||
|
||||
actions.useItem();
|
||||
}
|
||||
|
||||
if (shootPressed && item === "shell") {
|
||||
const distanceBehind = -2;
|
||||
const scaledBackwardDirection =
|
||||
forwardDirection.multiplyScalar(distanceBehind);
|
||||
|
||||
const kartPosition = new THREE.Vector3(
|
||||
body.current.translation().x,
|
||||
body.current.translation().y,
|
||||
body.current.translation().z
|
||||
);
|
||||
|
||||
const shellPosition = kartPosition.sub(scaledBackwardDirection);
|
||||
const newShell = {
|
||||
id: Math.random() + "-" + +new Date(),
|
||||
position: shellPosition,
|
||||
player: true,
|
||||
rotation: kartRotation,
|
||||
};
|
||||
setNetworkShells([...networkShells, newShell]);
|
||||
actions.useItem();
|
||||
}
|
||||
|
||||
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 player.id === id ? (
|
||||
<group>
|
||||
<RigidBody
|
||||
ref={body}
|
||||
colliders={false}
|
||||
position={[8, 60, -119]}
|
||||
centerOfMass={[0, -1, 0]}
|
||||
mass={3}
|
||||
ccd
|
||||
name="player"
|
||||
type={player.id === id ? "dynamic" : "kinematic"}
|
||||
>
|
||||
<BallCollider
|
||||
args={[0.5]}
|
||||
mass={3}
|
||||
onCollisionEnter={({ other }) => {
|
||||
isOnFloor.current = true;
|
||||
setIsOnGround(true);
|
||||
}}
|
||||
onCollisionExit={({ other }) => {
|
||||
isOnFloor.current = false;
|
||||
setIsOnGround(false);
|
||||
}}
|
||||
/>
|
||||
</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.46, 0.05, 0.3]} ref={leftWheel}></mesh>
|
||||
<mesh position={[0.46, 0.05, 0.3]} ref={rightWheel}></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} />
|
||||
<SmokeParticles
|
||||
driftRight={driftRight.current}
|
||||
driftLeft={driftLeft.current}
|
||||
/>
|
||||
<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} /> */}
|
||||
<PerspectiveCamera
|
||||
makeDefault
|
||||
position={[0, 2, 8]}
|
||||
fov={50}
|
||||
ref={cam}
|
||||
far={5000}
|
||||
/>
|
||||
<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;
|
||||
};
|
|
@ -1,619 +0,0 @@
|
|||
import { Controls } from "../App";
|
||||
import { BallCollider, RigidBody, useRapier, vec3 } from "@react-three/rapier";
|
||||
import {
|
||||
useKeyboardControls,
|
||||
PerspectiveCamera,
|
||||
PositionalAudio,
|
||||
} from "@react-three/drei";
|
||||
import { useFrame, useThree, extend } 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 { SmokeParticles } from "./Particles/smoke/SmokeParticles";
|
||||
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 { geometry } from "maath";
|
||||
import { useGamepad } from "./useGamepad";
|
||||
extend(geometry);
|
||||
|
||||
export const PlayerControllerTouch = ({
|
||||
player,
|
||||
userPlayer,
|
||||
setNetworkBananas,
|
||||
setNetworkShells,
|
||||
networkBananas,
|
||||
networkShells,
|
||||
}) => {
|
||||
|
||||
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 text = useRef();
|
||||
|
||||
const { actions, shouldSlowDown, item, bananas, coins, id, controls, joystickX, driftButton, itemButton, menuButton } = useStore();
|
||||
const slowDownDuration = useRef(1500);
|
||||
const rightWheel = useRef();
|
||||
const leftWheel = useRef();
|
||||
const isDrifting = useRef(false);
|
||||
useEffect(() => {
|
||||
if (leftWheel.current && rightWheel.current && body.current) {
|
||||
actions.setLeftWheel(leftWheel.current);
|
||||
actions.setRightWheel(rightWheel.current);
|
||||
}
|
||||
}, [body.current]);
|
||||
|
||||
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);
|
||||
engineSound.current.setPlaybackRate(currentSpeed / 10 + 0.1);
|
||||
jumpSound.current.setPlaybackRate(1.5);
|
||||
jumpSound.current.setVolume(0.5);
|
||||
driftSound.current.setVolume(0.2);
|
||||
|
||||
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;
|
||||
const forwardDirection = new THREE.Vector3(
|
||||
-Math.sin(kartRotation),
|
||||
0,
|
||||
-Math.cos(kartRotation)
|
||||
);
|
||||
leftWheel.current.kartRotation = kartRotation;
|
||||
if (menuButton) {
|
||||
actions.setGameStarted(false);
|
||||
}
|
||||
|
||||
// mouse steering
|
||||
|
||||
if (!driftLeft.current && !driftRight.current) {
|
||||
steeringAngle = currentSteeringSpeed * -joystickX;
|
||||
targetXPosition = -camMaxOffset * -joystickX;
|
||||
} else if (driftLeft.current && !driftRight.current) {
|
||||
steeringAngle = currentSteeringSpeed * -(joystickX - 1);
|
||||
targetXPosition = -camMaxOffset * -joystickX;
|
||||
} else if (driftRight.current && !driftLeft.current) {
|
||||
steeringAngle = currentSteeringSpeed * -(joystickX + 1);
|
||||
targetXPosition = -camMaxOffset * -joystickX;
|
||||
}
|
||||
// ACCELERATING
|
||||
const shouldSlow = actions.getShouldSlowDown();
|
||||
|
||||
if ( currentSpeed < maxSpeed) {
|
||||
// Accelerate the kart within the maximum speed limit
|
||||
setCurrentSpeed(
|
||||
Math.min(currentSpeed + acceleration * delta * 144, maxSpeed)
|
||||
);
|
||||
} else if (
|
||||
|
||||
currentSpeed > maxSpeed &&
|
||||
effectiveBoost.current > 0
|
||||
) {
|
||||
setCurrentSpeed(
|
||||
Math.max(currentSpeed - decceleration * delta * 144, maxSpeed)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (currentSteeringSpeed < MaxSteeringSpeed) {
|
||||
setCurrentSteeringSpeed(
|
||||
Math.min(
|
||||
currentSteeringSpeed + 0.0001 * delta * 144,
|
||||
MaxSteeringSpeed
|
||||
)
|
||||
);
|
||||
}
|
||||
if (shouldSlow) {
|
||||
rightWheel.current.isSpinning = true;
|
||||
|
||||
setCurrentSpeed(
|
||||
Math.max(currentSpeed - decceleration * 2 * delta * 144, 0)
|
||||
);
|
||||
setCurrentSteeringSpeed(0);
|
||||
slowDownDuration.current -= 1500 * delta;
|
||||
setShouldLaunch(true);
|
||||
if (slowDownDuration.current <= 1) {
|
||||
rightWheel.current.isSpinning = false;
|
||||
|
||||
actions.setShouldSlowDown(false);
|
||||
slowDownDuration.current = 1500;
|
||||
setShouldLaunch(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the kart's rotation based on the steering angle
|
||||
kart.current.rotation.y += steeringAngle * delta * 144;
|
||||
|
||||
// Apply damping to simulate slowdown when no keys are pressed
|
||||
body.current.applyImpulse(
|
||||
{
|
||||
x: -body.current.linvel().x * (1 - damping) * delta * 144,
|
||||
y: 0,
|
||||
z: -body.current.linvel().z * (1 - damping) * delta * 144,
|
||||
},
|
||||
true
|
||||
);
|
||||
const bodyPosition = body.current.translation();
|
||||
kart.current.position.set(
|
||||
bodyPosition.x,
|
||||
bodyPosition.y - 0.5,
|
||||
bodyPosition.z
|
||||
);
|
||||
|
||||
// JUMPING
|
||||
if (driftButton && isOnGround && !jumpIsHeld.current) {
|
||||
jumpForce.current += 10;
|
||||
isOnFloor.current = false;
|
||||
jumpIsHeld.current = true;
|
||||
jumpSound.current.play();
|
||||
setIsOnGround(false);
|
||||
|
||||
if (jumpSound.current.isPlaying) {
|
||||
jumpSound.current.stop();
|
||||
jumpSound.current.play();
|
||||
}
|
||||
}
|
||||
|
||||
if (isOnFloor.current && jumpForce.current > 0) {
|
||||
landingSound.current.play();
|
||||
}
|
||||
if (!isOnGround && jumpForce.current > 0) {
|
||||
jumpForce.current -= 1 * delta * 144;
|
||||
}
|
||||
if (!driftButton) {
|
||||
jumpIsHeld.current = false;
|
||||
driftDirection.current = 0;
|
||||
driftForce.current = 0;
|
||||
driftLeft.current = false;
|
||||
driftRight.current = false;
|
||||
}
|
||||
// DRIFTING
|
||||
if (
|
||||
jumpIsHeld.current &&
|
||||
currentSteeringSpeed > 0 &&
|
||||
joystickX < -0.1 &&
|
||||
!driftRight.current
|
||||
) {
|
||||
driftLeft.current = true;
|
||||
}
|
||||
if (
|
||||
jumpIsHeld.current &&
|
||||
currentSteeringSpeed > 0 &&
|
||||
joystickX > 0.1 &&
|
||||
!driftLeft.current
|
||||
) {
|
||||
driftRight.current = true;
|
||||
}
|
||||
|
||||
if (!jumpIsHeld.current && !driftLeft.current && !driftRight.current) {
|
||||
mario.current.rotation.y = THREE.MathUtils.lerp(
|
||||
mario.current.rotation.y,
|
||||
0,
|
||||
0.0001 * delta * 144
|
||||
);
|
||||
setTurboColor(0xffffff);
|
||||
accumulatedDriftPower.current = 0;
|
||||
driftSound.current.stop();
|
||||
driftTwoSound.current.stop();
|
||||
driftOrangeSound.current.stop();
|
||||
driftPurpleSound.current.stop();
|
||||
}
|
||||
|
||||
if (driftLeft.current) {
|
||||
driftDirection.current = 1;
|
||||
driftForce.current = 0.4;
|
||||
mario.current.rotation.y = THREE.MathUtils.lerp(
|
||||
mario.current.rotation.y,
|
||||
steeringAngle * 25 + 0.4,
|
||||
0.05 * delta * 144
|
||||
);
|
||||
if(isOnFloor.current){
|
||||
leftWheel.current.isSpinning = true;
|
||||
accumulatedDriftPower.current += 0.1 * (steeringAngle + 1) * delta * 144;
|
||||
|
||||
}
|
||||
}
|
||||
if (driftRight.current) {
|
||||
driftDirection.current = -1;
|
||||
driftForce.current = 0.4;
|
||||
mario.current.rotation.y = THREE.MathUtils.lerp(
|
||||
mario.current.rotation.y,
|
||||
-(-steeringAngle * 25 + 0.4),
|
||||
0.05 * delta * 144
|
||||
);
|
||||
if(isOnFloor.current){
|
||||
leftWheel.current.isSpinning = true;
|
||||
accumulatedDriftPower.current += 0.1 * (-steeringAngle + 1) * delta * 144;
|
||||
|
||||
}
|
||||
}
|
||||
if (!driftLeft.current && !driftRight.current) {
|
||||
mario.current.rotation.y = THREE.MathUtils.lerp(
|
||||
mario.current.rotation.y,
|
||||
steeringAngle * 30,
|
||||
0.05 * delta * 144
|
||||
);
|
||||
setScale(0);
|
||||
if((joystickX > 0.8 || joystickX < -0.8) && currentSpeed > 20 && isOnFloor.current){
|
||||
leftWheel.current.isSpinning = true;
|
||||
} else {
|
||||
leftWheel.current.isSpinning = false;
|
||||
}
|
||||
}
|
||||
if (accumulatedDriftPower.current > blueTurboThreshold) {
|
||||
setTurboColor(0x00ffff);
|
||||
boostDuration.current = 50;
|
||||
driftBlueSound.current.play();
|
||||
}
|
||||
if (accumulatedDriftPower.current > orangeTurboThreshold) {
|
||||
setTurboColor(0xffcf00);
|
||||
boostDuration.current = 100;
|
||||
driftBlueSound.current.stop();
|
||||
driftOrangeSound.current.play();
|
||||
}
|
||||
if (accumulatedDriftPower.current > purpleTurboThreshold) {
|
||||
setTurboColor(0xff00ff);
|
||||
boostDuration.current = 250;
|
||||
driftOrangeSound.current.stop();
|
||||
driftPurpleSound.current.play();
|
||||
}
|
||||
|
||||
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 {
|
||||
setScale(vibration);
|
||||
}
|
||||
if (isOnFloor.current && !driftSound.current.isPlaying) {
|
||||
driftSound.current.play();
|
||||
driftTwoSound.current.play();
|
||||
landingSound.current.play();
|
||||
}
|
||||
}
|
||||
// RELEASING DRIFT
|
||||
|
||||
if (boostDuration.current > 1 && !jumpIsHeld.current) {
|
||||
setIsBoosting(true);
|
||||
effectiveBoost.current = boostDuration.current;
|
||||
boostDuration.current = 0;
|
||||
} else if (effectiveBoost.current <= 1) {
|
||||
targetZPosition = 8;
|
||||
setIsBoosting(false);
|
||||
}
|
||||
|
||||
if (isBoosting && effectiveBoost.current > 1) {
|
||||
setCurrentSpeed(boostSpeed);
|
||||
effectiveBoost.current -= 1 * delta * 144;
|
||||
targetZPosition = 10;
|
||||
if (!turboSound.current.isPlaying) turboSound.current.play();
|
||||
driftTwoSound.current.play();
|
||||
driftBlueSound.current.stop();
|
||||
driftOrangeSound.current.stop();
|
||||
driftPurpleSound.current.stop();
|
||||
} else if (effectiveBoost.current <= 1) {
|
||||
setIsBoosting(false);
|
||||
targetZPosition = 8;
|
||||
turboSound.current.stop();
|
||||
}
|
||||
|
||||
// CAMERA WORK
|
||||
|
||||
cam.current.updateMatrixWorld();
|
||||
|
||||
cam.current.position.x = THREE.MathUtils.lerp(
|
||||
cam.current.position.x,
|
||||
targetXPosition,
|
||||
0.01 * delta * 144
|
||||
);
|
||||
|
||||
cam.current.position.z = THREE.MathUtils.lerp(
|
||||
cam.current.position.z,
|
||||
targetZPosition,
|
||||
0.01 * delta * 144
|
||||
);
|
||||
|
||||
body.current.applyImpulse(
|
||||
{
|
||||
x: forwardDirection.x * currentSpeed * delta * 144,
|
||||
y: 0 + jumpForce.current * delta * 144,
|
||||
z: forwardDirection.z * currentSpeed * delta * 144,
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
// Update the kart's rotation based on the steering angle
|
||||
setSteeringAngleWheels(steeringAngle * 25);
|
||||
|
||||
// SOUND WORK
|
||||
|
||||
|
||||
// ITEMS
|
||||
|
||||
if (itemButton && item === "banana") {
|
||||
const distanceBehind = 2;
|
||||
const scaledBackwardDirection =
|
||||
forwardDirection.multiplyScalar(distanceBehind);
|
||||
|
||||
const kartPosition = new THREE.Vector3(
|
||||
...vec3(body.current.translation())
|
||||
);
|
||||
|
||||
const bananaPosition = kartPosition.sub(scaledBackwardDirection);
|
||||
const newBanana = {
|
||||
id: Math.random() + "-" + +new Date(),
|
||||
position: bananaPosition,
|
||||
player: true,
|
||||
};
|
||||
setNetworkBananas([...networkBananas, newBanana]);
|
||||
|
||||
actions.useItem();
|
||||
}
|
||||
|
||||
if (itemButton && item === "shell") {
|
||||
const distanceBehind = -2;
|
||||
const scaledBackwardDirection =
|
||||
forwardDirection.multiplyScalar(distanceBehind);
|
||||
|
||||
const kartPosition = new THREE.Vector3(
|
||||
body.current.translation().x,
|
||||
body.current.translation().y,
|
||||
body.current.translation().z
|
||||
);
|
||||
|
||||
const shellPosition = kartPosition.sub(scaledBackwardDirection);
|
||||
const newShell = {
|
||||
id: Math.random() + "-" + +new Date(),
|
||||
position: shellPosition,
|
||||
player: true,
|
||||
rotation: kartRotation,
|
||||
};
|
||||
setNetworkShells([...networkShells, newShell]);
|
||||
actions.useItem();
|
||||
}
|
||||
|
||||
if (itemButton && 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 player.id === id ? (
|
||||
<group>
|
||||
<RigidBody
|
||||
ref={body}
|
||||
colliders={false}
|
||||
position={[8, 60, -119]}
|
||||
centerOfMass={[0, -1, 0]}
|
||||
mass={3}
|
||||
ccd
|
||||
name="player"
|
||||
type={player.id === id ? "dynamic" : "kinematic"}
|
||||
>
|
||||
<BallCollider
|
||||
args={[0.5]}
|
||||
mass={3}
|
||||
onCollisionEnter={({ other }) => {
|
||||
isOnFloor.current = true;
|
||||
setIsOnGround(true);
|
||||
}}
|
||||
onCollisionExit={({ other }) => {
|
||||
isOnFloor.current = false;
|
||||
setIsOnGround(false);
|
||||
}}
|
||||
/>
|
||||
</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.46, 0.05, 0.3]} ref={leftWheel}></mesh>
|
||||
<mesh position={[0.46, 0.05, 0.3]} ref={rightWheel}></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} />
|
||||
<SmokeParticles driftRight={driftRight.current} driftLeft={driftLeft.current} />
|
||||
<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} /> */}
|
||||
<PerspectiveCamera
|
||||
makeDefault
|
||||
position={[0, 2, 8]}
|
||||
fov={50}
|
||||
ref={cam}
|
||||
far={5000}
|
||||
/>
|
||||
<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;
|
||||
};
|
|
@ -1,271 +0,0 @@
|
|||
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 text = 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? (
|
||||
<>
|
||||
<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}>
|
||||
<Billboard>
|
||||
<Text font={"./fonts/HK.ttf"} ref={text} fontSize={0.4} outlineWidth={0.03} position={[0, 2, 0]}>{player.state.profile.name}</Text>
|
||||
</Billboard>
|
||||
<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;
|
||||
};
|
|
@ -39,11 +39,11 @@ export default function FakeFlame({ falloff = 3, glowInternalRadius = 1.0, glowC
|
|||
float glitchStrength = sin(glitchTime) + sin(glitchTime * .05) + sin(glitchTime * .36);
|
||||
glitchStrength /= 2.0;
|
||||
glitchStrength = smoothstep(0.2, 0.8, glitchStrength);
|
||||
glitchStrength *= 0.;
|
||||
glitchStrength *= 0.05;
|
||||
modelPosition.x += (random2D(modelNormal.xx + time) - 0.5) * glitchStrength;
|
||||
modelPosition.x += (random2D(modelNormal.xx - time) - 0.2) * glitchStrength;
|
||||
modelPosition.y += sin(smoothstep(0.4, vUv.y - 2.5, position.y) * 2.) * sin(time * 48.);
|
||||
modelPosition.z += sin(smoothstep(0., vUv.x - 1.8, position.z) * 2.) * sin(time * 24.);
|
||||
modelPosition.y += sin(smoothstep(0.3, vUv.y - 2.2, position.y) * 2.) * sin(time * 48.);
|
||||
modelPosition.z += sin(smoothstep(0., vUv.x - 0.8, position.z) * 2.) * sin(time * 24.) * .6;
|
||||
|
||||
gl_Position = projectionMatrix * viewMatrix * modelPosition;
|
||||
|
||||
|
@ -107,7 +107,7 @@ export default function FakeFlame({ falloff = 3, glowInternalRadius = 1.0, glowC
|
|||
q.x *= 2.;
|
||||
q.y *= 2.;
|
||||
float strength = floor(q.x+1.5);
|
||||
float T3 = max(2.,2.25*strength)*time * 4.;
|
||||
float T3 = max(2.,2.25*strength)*time * 3.;
|
||||
q.x = mod(q.x,1.)-0.5;
|
||||
q.y -= 0.05;
|
||||
float n = fbm(strength*q + vec2(0,T3));
|
||||
|
|
|
@ -1,56 +1,68 @@
|
|||
import { Euler, Object3D, Vector3, Matrix4, DoubleSide } from 'three'
|
||||
import { useRef, useLayoutEffect } from 'react'
|
||||
import { useFrame } from '@react-three/fiber'
|
||||
import { vec3 } from '@react-three/rapier'
|
||||
import { Euler, Object3D, BackSide, Vector3 } from "three";
|
||||
import { useRef, useLayoutEffect } from "react";
|
||||
import { useFrame } from "@react-three/fiber";
|
||||
import { useStore } from "./store";
|
||||
|
||||
const o = new Object3D();
|
||||
|
||||
import { useStore } from './store'
|
||||
|
||||
|
||||
const e = new Euler()
|
||||
const m = new Matrix4()
|
||||
const o = new Object3D()
|
||||
const v = new Vector3()
|
||||
|
||||
|
||||
|
||||
export function Skid({ count = 50000, opacity = 0.5, size = 0.3 }) {
|
||||
export function Skid({ count = 500, opacity = 1, size = 0.4 }) {
|
||||
const ref = useRef(null);
|
||||
const { leftWheel, rightWheel } = useStore();
|
||||
let index = 0
|
||||
const [bodyPosition, bodyRotation] = useStore((state) => [
|
||||
state.bodyPosition,
|
||||
state.bodyRotation,
|
||||
]);
|
||||
|
||||
let index = 0;
|
||||
useFrame(() => {
|
||||
if(!leftWheel && !rightWheel) return;
|
||||
const rotation = leftWheel.kartRotation;
|
||||
if (leftWheel && rightWheel && ref.current && (leftWheel.isSpinning || rightWheel.isSpinning)) {
|
||||
setItemAt(ref.current, rotation, leftWheel, index++);
|
||||
setItemAt(ref.current, rotation, rightWheel, index++);
|
||||
|
||||
if (index === count) index = 0
|
||||
// console.log(bodyPosition, bodyRotation);
|
||||
if (ref.current && bodyPosition && bodyRotation !== undefined) {
|
||||
setItemAt(ref.current, bodyPosition, bodyRotation, index++);
|
||||
if (index === count) index = 0;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if(ref.current){
|
||||
ref.current.geometry.rotateX(-Math.PI / 2)
|
||||
if (ref.current) {
|
||||
ref.current.geometry.rotateX(-Math.PI / 2);
|
||||
return () => {
|
||||
ref.current.geometry.rotateX(Math.PI / 2)
|
||||
}
|
||||
ref.current.geometry.rotateX(Math.PI / 2);
|
||||
};
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
return (
|
||||
<instancedMesh frustumCulled={false} ref={ref} args={[undefined, undefined, count]}>
|
||||
<planeGeometry args={[size, size]} />
|
||||
<meshBasicMaterial color="black" side={DoubleSide} transparent opacity={opacity} />
|
||||
<instancedMesh ref={ref} args={[undefined, undefined, count]}>
|
||||
<planeGeometry args={[size, size * 2]} />
|
||||
<meshBasicMaterial
|
||||
color={0x000000}
|
||||
transparent
|
||||
opacity={opacity}
|
||||
depthWrite={false}
|
||||
side={BackSide}
|
||||
/>
|
||||
</instancedMesh>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function setItemAt(instances, rotation, body, index) {
|
||||
o.position.copy(body.getWorldPosition(v));
|
||||
o.rotation.set(0, rotation, 0);
|
||||
o.scale.setScalar(1)
|
||||
o.updateMatrix()
|
||||
instances.setMatrixAt(index, o.matrix)
|
||||
instances.instanceMatrix.needsUpdate = true
|
||||
function setItemAt(instances, bodyPosition, bodyRotation, index) {
|
||||
// Calculate the backward offset
|
||||
const backwardOffset = 0.5; // Adjust this value as needed
|
||||
const forwardDirection = new Vector3(
|
||||
-Math.sin(bodyRotation),
|
||||
0,
|
||||
-Math.cos(bodyRotation)
|
||||
);
|
||||
const backwardPosition = forwardDirection
|
||||
.multiplyScalar(-backwardOffset)
|
||||
.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);
|
||||
o.scale.setScalar(1);
|
||||
o.updateMatrix();
|
||||
instances.setMatrixAt(index, o.matrix);
|
||||
instances.instanceMatrix.needsUpdate = true;
|
||||
}
|
||||
|
|
|
@ -3,15 +3,13 @@ Auto-generated by: https://github.com/pmndrs/gltfjsx
|
|||
Command: npx gltfjsx@6.2.16 .\mariokarttest.glb --shadows
|
||||
*/
|
||||
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import React, { 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, shouldLaunch, ...props }) {
|
||||
export function Mario({ currentSpeed, steeringAngleWheels, isBoosting, ...props }) {
|
||||
const { nodes, materials } = useGLTF('./models/characters/mariokarttest.glb')
|
||||
|
||||
const frontLeftWheel = useRef()
|
||||
|
@ -19,9 +17,6 @@ export function Mario({ currentSpeed, steeringAngleWheels, isBoosting, shouldLau
|
|||
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) => {
|
||||
|
@ -35,21 +30,12 @@ export function Mario({ currentSpeed, steeringAngleWheels, isBoosting, shouldLau
|
|||
} else {
|
||||
setScale(Math.max(scale - 0.03 * 144 * delta, 0))
|
||||
}
|
||||
setShouldSlow(actions.getShouldSlowDown());
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldLaunch) {
|
||||
gsap.to(mario.current.rotation, {duration: 1.5, y: Math.PI * 3})
|
||||
mario.current.rotation.set(0, 0, 0);
|
||||
}
|
||||
}, [shouldLaunch])
|
||||
return (
|
||||
<group
|
||||
{...props}
|
||||
rotation={[0, Math.PI, 0]}
|
||||
dispose={null}
|
||||
ref={mario}
|
||||
>
|
||||
<mesh
|
||||
castShadow
|
||||
|
@ -100,7 +86,7 @@ export function Mario({ currentSpeed, steeringAngleWheels, isBoosting, shouldLau
|
|||
|
||||
<Cylinder
|
||||
args={[0.1, 0, 1, 128, 64, true]}
|
||||
position={[0.3, 0.65, -1.35]}
|
||||
position={[0.3, 0.6, -1.2]}
|
||||
rotation={[Math.PI / 1.5, 0, 0]}
|
||||
scale={scale}
|
||||
|
||||
|
@ -110,7 +96,7 @@ export function Mario({ currentSpeed, steeringAngleWheels, isBoosting, shouldLau
|
|||
|
||||
<Cylinder
|
||||
args={[0.1, 0, 1, 128, 64, true]}
|
||||
position={[-0.3, 0.65, -1.35]}
|
||||
position={[-0.3, 0.6, -1.2]}
|
||||
rotation={[Math.PI / 1.5, 0, 0]}
|
||||
scale={scale}
|
||||
>
|
||||
|
@ -118,17 +104,17 @@ export function Mario({ currentSpeed, steeringAngleWheels, isBoosting, shouldLau
|
|||
</Cylinder>
|
||||
<Cylinder
|
||||
args={[0.09, 0, 1, 128, 64, true]}
|
||||
position={[0.18, 0.75, -1.1]}
|
||||
position={[0.18, 0.7, -0.8]}
|
||||
rotation={[Math.PI / 1.5, 0, 0]}
|
||||
scale={scale * 0.8}
|
||||
scale={scale}
|
||||
>
|
||||
<FakeFlame isBoosting={isBoosting} />
|
||||
</Cylinder>
|
||||
<Cylinder
|
||||
args={[0.09, 0, 1, 128, 64, true]}
|
||||
position={[-0.18, 0.75, -1.1]}
|
||||
position={[-0.18, 0.7, -0.8]}
|
||||
rotation={[Math.PI / 1.5, 0, 0]}
|
||||
scale={scale * 0.8}
|
||||
scale={scale}
|
||||
>
|
||||
<FakeFlame isBoosting={isBoosting}/>
|
||||
</Cylinder>
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
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/Yanez-Designs)
|
||||
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, { 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, position, setNetworkBananas, networkBananas}) {
|
||||
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={[position.x, position.y, position.z]}
|
||||
sensor
|
||||
onIntersectionEnter={({other}) => {
|
||||
if(other.rigidBodyObject.name === "player"){
|
||||
actions.setShouldSlowDown(true);
|
||||
setNetworkBananas(networkBananas.filter((banana) => banana.id !== id));
|
||||
}
|
||||
}}
|
||||
colliders={false}
|
||||
name='banana'
|
||||
>
|
||||
<BallCollider args={[0.5]} />
|
||||
|
||||
</RigidBody>
|
||||
|
||||
<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]} />
|
||||
</group>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
useGLTF.preload('./models/items/banana_peel_mario_kart-transformed.glb')
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
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";
|
||||
import { useStore } from "../../store";
|
||||
|
||||
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(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.rotation.z += 0.2 * delta * 144;
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<group dispose={null}>
|
||||
<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");
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
Auto-generated by: https://github.com/pmndrs/gltfjsx
|
||||
Command: npx gltfjsx@6.2.16 .\gift.glb --shadows --transform
|
||||
Files: .\gift.glb [694.14KB] > 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 (
|
||||
<>
|
||||
<RigidBody type="fixed" name="itemBox"
|
||||
sensor
|
||||
ref={body}
|
||||
onIntersectionEnter={({other}) => {
|
||||
if(other.rigidBodyObject.name === "player"){
|
||||
|
||||
actions.setItem();
|
||||
setScale(0);
|
||||
frames.current = 400;
|
||||
body.current.setEnabled(false);
|
||||
}
|
||||
}}
|
||||
position={props.position}
|
||||
colliders={false}
|
||||
>
|
||||
<CuboidCollider args={[1.5, 1.5, 1.5]} />
|
||||
</RigidBody>
|
||||
<group ref={ref} position={props.position} scale={scale} dispose={null}>
|
||||
<mesh castShadow receiveShadow geometry={nodes.Cube000.geometry} material={materials.Material} position={[0.077, 0.5, -0.019]} rotation={[-Math.PI / 2, 0, 0]} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.Cube000_1.geometry} material={materials['Material.001']} position={[0.077, 0.5, -0.019]} rotation={[-Math.PI / 2, 0, 0]} />
|
||||
</group>
|
||||
</>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
useGLTF.preload('./models/misc/gift-transformed.glb')
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
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={() => {
|
||||
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>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
Auto-generated by: https://github.com/pmndrs/gltfjsx
|
||||
Command: npx gltfjsx@6.2.16 .\super_mario_bros_coin.glb --shadows --transform
|
||||
Files: .\super_mario_bros_coin.glb [48.84KB] > C:\Users\mouli\dev\r3f-vite-starter\public\models\misc\super_mario_bros_coin-transformed.glb [6.12KB] (87%)
|
||||
Author: BranHelsing (https://sketchfab.com/BranHelsing)
|
||||
License: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
|
||||
Source: https://sketchfab.com/3d-models/super-mario-bros-coin-aa97e093847a439f9feb064134813806
|
||||
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 { RigidBody } from "@react-three/rapier";
|
||||
import { useStore } from "../../store";
|
||||
|
||||
export function Coin(props) {
|
||||
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;
|
||||
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 (
|
||||
<>
|
||||
<RigidBody
|
||||
type="fixed"
|
||||
name="coin"
|
||||
sensor
|
||||
onIntersectionEnter={({ manifold, target, other}) => {
|
||||
if(other.rigidBodyObject.name === "player"){
|
||||
actions.addCoins();
|
||||
setScale(0);
|
||||
frames.current = 600;
|
||||
body.current.setEnable(false);
|
||||
}
|
||||
}}
|
||||
position={props.position}
|
||||
>
|
||||
<mesh
|
||||
ref={group}
|
||||
castShadow
|
||||
receiveShadow
|
||||
geometry={nodes.Coin_CoinBlinn_0.geometry}
|
||||
material={materials.CoinBlinn}
|
||||
scale={scale}
|
||||
/>
|
||||
</RigidBody>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
useGLTF.preload("./models/misc/super_mario_bros_coin-transformed.glb");
|
|
@ -1,109 +0,0 @@
|
|||
/*
|
||||
Auto-generated by: https://github.com/pmndrs/gltfjsx
|
||||
Command: npx gltfjsx@6.2.16 .\paris-bis.glb --shadows
|
||||
*/
|
||||
|
||||
import React, { useRef } from 'react'
|
||||
import { useGLTF } from '@react-three/drei'
|
||||
import { RigidBody } from '@react-three/rapier'
|
||||
|
||||
export function ParisBis(props) {
|
||||
const { nodes, materials } = useGLTF('./models/tracks/paris-bis.glb')
|
||||
materials.M_Cmn_ShadowCollision.opacity = 0
|
||||
materials.M_Cmn_ShadowCollision.transparent = true
|
||||
return (
|
||||
<group {...props} scale={50} position={[0,-3.6,0]} dispose={null}>
|
||||
<group scale={0.01}>
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Audience_NoMove_01_M_Cmn_AudienceModel_0.geometry} material={materials.M_Cmn_AudienceModel} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.F_Building_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.F_Building_M_Mobp1_Textures01_0.geometry} material={materials.M_Mobp1_Textures01} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.F_Obj_01_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.M_GeneralMansion_Roof_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.M_GeneralMansion_Roof_M_Mobp1_Textures01_0.geometry} material={materials.M_Mobp1_Textures01} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_MansionObj_01_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_MansionObj_01_M_Mobp1_kanban_0.geometry} material={materials.M_Mobp1_kanban} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_MansionObj_01_M_Mobp1_Textures01_0.geometry} material={materials.M_Mobp1_Textures01} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_MansionObj_02_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_MansionObj_02_M_Mobp1_kanban_0.geometry} material={materials.M_Mobp1_kanban} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_MansionObj_02_M_Mobp1_Textures01_0.geometry} material={materials.M_Mobp1_Textures01} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_001_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_001_M_Mobp1_kanban_0.geometry} material={materials.M_Mobp1_kanban} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_002_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_002_M_Mobp1_kanban_0.geometry} material={materials.M_Mobp1_kanban} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_003_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_003_M_Mobp1_kanban_0.geometry} material={materials.M_Mobp1_kanban} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_003_M_Mobp1_Window_0.geometry} material={materials.M_Mobp1_Window} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_004_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_004_M_Mobp1_kanban_0.geometry} material={materials.M_Mobp1_kanban} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_005_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_005_M_Mobp1_kanban_0.geometry} material={materials.M_Mobp1_kanban} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_005_M_Mobp1_Window_0.geometry} material={materials.M_Mobp1_Window} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_006_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_006_M_Mobp1_kanban_0.geometry} material={materials.M_Mobp1_kanban} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_007_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_007_M_Mobp1_kanban_0.geometry} material={materials.M_Mobp1_kanban} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_008_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_008_M_Mobp1_kanban_0.geometry} material={materials.M_Mobp1_kanban} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_009_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_009_M_Mobp1_kanban_0.geometry} material={materials.M_Mobp1_kanban} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_010_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_010_M_Mobp1_kanban_0.geometry} material={materials.M_Mobp1_kanban} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_UniqueBuilding_Parts_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_UniqueBuilding_Parts_M_Mobp1_kanban_0.geometry} material={materials.M_Mobp1_kanban} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.Rainbow_model_M_Mobp1_Rainbow_0.geometry} material={materials.M_Mobp1_Rainbow} position={[-16, 0.14, 0]} rotation={[0, -1.571, 0]} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.F_BlindBuilding_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.F_BlindBuilding_M_Mobp1_Textures01_0.geometry} material={materials.M_Mobp1_Textures01} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.F_effel_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.F_Ground_01_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.F_Ground_01_M_Mobp1_Textures01_0.geometry} material={materials.M_Mobp1_Textures01} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.F_Ground_01_M_Mobp1_Water_0.geometry} material={materials.M_Mobp1_Water} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.F_Ground_01_M_Mobp1_Window_0.geometry} material={materials.M_Mobp1_Window} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.Gmob_Paris_VR_M_Mobp1_VR_0.geometry} material={materials.M_Mobp1_VR} position={[0, -451.06, 0]} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.M_Building_001_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.M_Building_001_M_Mobp1_Textures01_0.geometry} material={materials.M_Mobp1_Textures01} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.M_Building_001_M_Mobp1_Window_0.geometry} material={materials.M_Mobp1_Window} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Building_001_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Building_001_M_Mobp1_Textures01_0.geometry} material={materials.M_Mobp1_Textures01} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Building_001_M_Mobp1_Window_0.geometry} material={materials.M_Mobp1_Window} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Building_002_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Building_002_M_Mobp1_gaisenmon_tex_0.geometry} material={materials.M_Mobp1_gaisenmon_tex} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Building_002_M_Mobp1_kanban_0.geometry} material={materials.M_Mobp1_kanban} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Building_002_M_Mobp1_Textures01_0.geometry} material={materials.M_Mobp1_Textures01} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Building_002_M_Mobp1_Window_0.geometry} material={materials.M_Mobp1_Window} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Building_003_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Building_003_M_Mobp1_Textures01_0.geometry} material={materials.M_Mobp1_Textures01} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Building_003_M_Mobp1_Window_0.geometry} material={materials.M_Mobp1_Window} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Building_004_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Building_004_M_Mobp1_Textures01_0.geometry} material={materials.M_Mobp1_Textures01} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Building_004_M_Mobp1_Window_0.geometry} material={materials.M_Mobp1_Window} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_effel_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_effel_M_Mobp1_Window_0.geometry} material={materials.M_Mobp1_Window} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_000_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_000_M_Mobp1_Textures01_0.geometry} material={materials.M_Mobp1_Textures01} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_000_M_Mobp1_Transparent_0.geometry} material={materials.M_Mobp1_Transparent} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Obj_000_M_Mobp1_Window_0.geometry} material={materials.M_Mobp1_Window} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_UniqueBuilding_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_UniqueBuilding_M_Mobp1_gaisenmon_tex_0.geometry} material={materials.M_Mobp1_gaisenmon_tex} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_UniqueBuilding_M_Mobp1_Textures01_0.geometry} material={materials.M_Mobp1_Textures01} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_UniqueBuilding_M_Mobp1_Window_0.geometry} material={materials.M_Mobp1_Window} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.BlindTree_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.Low_Obj_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.Low_Obj_M_Mobp1_kanban_0.geometry} material={materials.M_Mobp1_kanban} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Road_Ground_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Road_Ground_M_Mobp1_Road_A_0.geometry} material={materials.M_Mobp1_Road_A} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Road_Ground_M_Mobp1_Road_B_0.geometry} material={materials.M_Mobp1_Road_B} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Road_Ground_M_Mobp1_RoadColor_0.geometry} material={materials.M_Mobp1_RoadColor} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Road_Ground_M_Mobp1_Water_0.geometry} material={materials.M_Mobp1_Water} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Road_Ground_M_Mobp1_Window_0.geometry} material={materials.M_Mobp1_Window} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Trocadero_M_Cmn_MainColor_Detail_0.geometry} material={materials.M_Cmn_MainColor_Detail} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Trocadero_M_Mobp1_RoadColor_0.geometry} material={materials.M_Mobp1_RoadColor} />
|
||||
<mesh castShadow receiveShadow geometry={nodes.N_Trocadero_Water_M_Mobp1_Water_0.geometry} material={materials.M_Mobp1_Water} />
|
||||
<RigidBody type="fixed" colliders="trimesh" name="terrain">
|
||||
<mesh castShadow receiveShadow geometry={nodes.ShadowCollision_M_Cmn_ShadowCollision_0.geometry} material={materials.M_Cmn_ShadowCollision} position={[0, 0.244, 0]} />
|
||||
</RigidBody>
|
||||
</group>
|
||||
</group>
|
||||
)
|
||||
}
|
||||
|
||||
useGLTF.preload('./models/tracks/paris-bis.glb')
|