Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d9623cac8 | ||
|
|
17543f3b5c | ||
|
|
1b58a27e9d | ||
|
|
b0d0a9126c | ||
|
|
c0895c0c84 | ||
|
|
22f2461cc7 | ||
|
|
cd1d099392 | ||
|
|
ba5be77ae5 | ||
|
|
9f61b3e53c | ||
|
|
a96849f10d | ||
|
|
c93290cd6d | ||
|
|
7665cd70fa | ||
|
|
8b08815d5c | ||
|
|
64f52c4aa9 | ||
|
|
0422ac68c9 | ||
|
|
7275250fe0 | ||
|
|
764a3d2f30 | ||
|
|
4d0200845c | ||
|
|
35085055bc | ||
|
|
e466e32483 | ||
|
|
f25076b904 | ||
|
|
5ac25a1de8 | ||
|
|
5aa2731168 | ||
|
|
fa5c8b4f60 | ||
|
|
e89f666184 | ||
|
|
e4a4d22374 | ||
|
|
a12ccb3452 | ||
|
|
ef51e33385 | ||
|
|
2a78567df5 | ||
|
|
f19e940c3a | ||
|
|
1a0c1b9b28 | ||
|
|
66e1900296 | ||
|
|
c4b9175658 | ||
|
|
9b0f6cbdc6 | ||
|
|
d49e47b504 | ||
|
|
628cf726ae | ||
|
|
e169e12e55 | ||
|
|
b6e723dadc | ||
|
|
06b8beff00 | ||
|
|
aab364eb0a | ||
|
|
1504f44959 | ||
|
|
6ed6c0ff27 | ||
|
|
5cc900ab35 | ||
|
|
c22c9e9012 | ||
|
|
3ef3ec7d25 | ||
|
|
310e471fab | ||
|
|
140413399f | ||
|
|
ef9e58fa21 | ||
|
|
42680aa707 | ||
|
|
b825b0fc20 | ||
|
|
df76bb5f35 | ||
|
|
bfd691e7ab | ||
|
|
db52f49e09 | ||
|
|
cff143c925 | ||
|
|
bf52a80c29 | ||
|
|
8138f4338f | ||
|
|
51c2f3f8f8 | ||
|
|
f22f19590d | ||
|
|
256ee77f1f | ||
|
|
77a14c7733 | ||
|
|
11be02d977 | ||
|
|
f356585be2 | ||
|
|
faad40aa9d | ||
|
|
bfccc00f4d | ||
|
|
54810a73cd | ||
|
|
fdd821e630 | ||
|
|
2d9230b8ea |
No files matched your search
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://triplex.dev/config.schema.json",
|
||||||
|
"components": ["../src/components/**/*.(j|t)sx"],
|
||||||
|
"files": ["../src/components/**/*.(j|t)sx"],
|
||||||
|
"provider": "./provider.tsx",
|
||||||
|
"assetsDir": "models"
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) [2022] [Ron Waller]
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
# Mario Kart 3.js - JavaScript/WebGL Mario Kart
|
||||||
|
|
||||||
|
[Link](https://mario-kart-3-js.vercel.app/)
|
||||||
|
|
||||||
|
[](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
|
||||||
|
|
||||||
|
[](https://opensource.org/licenses/MIT)
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
Auto-generated by: https://github.com/pmndrs/gltfjsx
|
|
||||||
Command: npx gltfjsx@6.2.16 c:\Users\mouli\Downloads\mario_kart.glb -o c:\Users\mouli\Desktop\mario_kart.tsx --types
|
|
||||||
Author: TheShibeLord (https://sketchfab.com/TheShibeLord)
|
|
||||||
License: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
|
|
||||||
Source: https://sketchfab.com/3d-models/mario-kart-66cc131575344ab69238ec5872f24927
|
|
||||||
Title: Mario Kart
|
|
||||||
*/
|
|
||||||
|
|
||||||
import * as THREE from 'three'
|
|
||||||
import React, { useRef } from 'react'
|
|
||||||
import { useGLTF } from '@react-three/drei'
|
|
||||||
import { GLTF } from 'three-stdlib'
|
|
||||||
|
|
||||||
type GLTFResult = GLTF & {
|
|
||||||
nodes: {
|
|
||||||
mt_mario: THREE.Mesh
|
|
||||||
mt_kart_Mario_S: THREE.Mesh
|
|
||||||
mt_Kart_Mario_Tire_S: THREE.Mesh
|
|
||||||
}
|
|
||||||
materials: {
|
|
||||||
mt_mario: THREE.MeshStandardMaterial
|
|
||||||
mt_kart_Mario_S: THREE.MeshStandardMaterial
|
|
||||||
mt_Kart_Mario_Tire_S: THREE.MeshStandardMaterial
|
|
||||||
}
|
|
||||||
animations: GLTFAction[]
|
|
||||||
}
|
|
||||||
|
|
||||||
type ContextType = Record<string, React.ForwardRefExoticComponent<JSX.IntrinsicElements['mesh']>>
|
|
||||||
|
|
||||||
export function Model(props: JSX.IntrinsicElements['group']) {
|
|
||||||
const { nodes, materials } = useGLTF('/mario_kart.glb') as GLTFResult
|
|
||||||
return (
|
|
||||||
<group {...props} dispose={null}>
|
|
||||||
<group rotation={[-Math.PI / 2, 0, 0]}>
|
|
||||||
<group rotation={[Math.PI / 2, 0, 0]}>
|
|
||||||
<mesh geometry={nodes.mt_mario.geometry} material={materials.mt_mario} />
|
|
||||||
<mesh geometry={nodes.mt_kart_Mario_S.geometry} material={materials.mt_kart_Mario_S} />
|
|
||||||
<mesh geometry={nodes.mt_Kart_Mario_Tire_S.geometry} material={materials.mt_Kart_Mario_Tire_S} />
|
|
||||||
</group>
|
|
||||||
</group>
|
|
||||||
</group>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
useGLTF.preload('/mario_kart.glb')
|
|
||||||
@@ -8,15 +8,19 @@
|
|||||||
"name": "vite-starter",
|
"name": "vite-starter",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-three/drei": "^9.93.0",
|
"@react-three/drei": "^9.96.4",
|
||||||
"@react-three/fiber": "^8.15.13",
|
"@react-three/fiber": "^8.15.15",
|
||||||
"@react-three/postprocessing": "^2.15.11",
|
"@react-three/postprocessing": "^2.15.11",
|
||||||
"@react-three/rapier": "^1.2.1",
|
"@react-three/rapier": "^1.2.1",
|
||||||
"gsap": "^3.12.5",
|
"gsap": "^3.12.5",
|
||||||
"leva": "^0.9.35",
|
"leva": "^0.9.35",
|
||||||
|
"playroomkit": "^0.0.66",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"three": "^0.160.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"
|
"zustand": "^4.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -932,9 +936,9 @@
|
|||||||
"integrity": "sha512-POu8Mk0hIU3lRXB3bGIGe4VHIwwDsQyoD1F394OK7STTiX9w4dG3cTLljjYswkQN+hDSHRrj4O36kuVa7KPU8Q=="
|
"integrity": "sha512-POu8Mk0hIU3lRXB3bGIGe4VHIwwDsQyoD1F394OK7STTiX9w4dG3cTLljjYswkQN+hDSHRrj4O36kuVa7KPU8Q=="
|
||||||
},
|
},
|
||||||
"node_modules/@react-three/drei": {
|
"node_modules/@react-three/drei": {
|
||||||
"version": "9.93.0",
|
"version": "9.96.4",
|
||||||
"resolved": "https://registry.npmjs.org/@react-three/drei/-/drei-9.93.0.tgz",
|
"resolved": "https://registry.npmjs.org/@react-three/drei/-/drei-9.96.4.tgz",
|
||||||
"integrity": "sha512-G59IZqPzpIZPvVLmzdCITXJQB+mnKMtFv7FvSRFogeelLzOFkyfnkED9QiY0WQCBMFOFLnSx6vb5xzmbQjHyQA==",
|
"integrity": "sha512-Zmy5felOamD7DkD5EeLfijNkohDxHNtXomGAf3C/0G6ml/ocf1+VrJ6mLDQRE+DhRnF1RDHV+WC6nuvpPPkx1w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.11.2",
|
"@babel/runtime": "^7.11.2",
|
||||||
"@mediapipe/tasks-vision": "0.10.8",
|
"@mediapipe/tasks-vision": "0.10.8",
|
||||||
@@ -944,9 +948,6 @@
|
|||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"detect-gpu": "^5.0.28",
|
"detect-gpu": "^5.0.28",
|
||||||
"glsl-noise": "^0.0.0",
|
"glsl-noise": "^0.0.0",
|
||||||
"lodash.clamp": "^4.0.3",
|
|
||||||
"lodash.omit": "^4.5.0",
|
|
||||||
"lodash.pick": "^4.4.0",
|
|
||||||
"maath": "^0.10.7",
|
"maath": "^0.10.7",
|
||||||
"meshline": "^3.1.6",
|
"meshline": "^3.1.6",
|
||||||
"react-composer": "^5.0.3",
|
"react-composer": "^5.0.3",
|
||||||
@@ -954,12 +955,13 @@
|
|||||||
"stats-gl": "^2.0.0",
|
"stats-gl": "^2.0.0",
|
||||||
"stats.js": "^0.17.0",
|
"stats.js": "^0.17.0",
|
||||||
"suspend-react": "^0.1.3",
|
"suspend-react": "^0.1.3",
|
||||||
"three-mesh-bvh": "^0.6.7",
|
"three-mesh-bvh": "^0.7.0",
|
||||||
"three-stdlib": "^2.28.0",
|
"three-stdlib": "^2.29.4",
|
||||||
"troika-three-text": "^0.47.2",
|
"troika-three-text": "^0.47.2",
|
||||||
|
"tunnel-rat": "^0.1.2",
|
||||||
"utility-types": "^3.10.0",
|
"utility-types": "^3.10.0",
|
||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
"zustand": "^3.5.13"
|
"zustand": "^3.7.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@react-three/fiber": ">=8.0",
|
"@react-three/fiber": ">=8.0",
|
||||||
@@ -990,9 +992,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@react-three/fiber": {
|
"node_modules/@react-three/fiber": {
|
||||||
"version": "8.15.13",
|
"version": "8.15.15",
|
||||||
"resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.15.13.tgz",
|
"resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.15.15.tgz",
|
||||||
"integrity": "sha512-FS6F/k69q2KEf7nxdce1Rzd5qyp6VHtTgjouTMfiotWNiNwlhfQQeAxfcnDg0i2XVaOUGkLaD9BK8LBVnpfzUA==",
|
"integrity": "sha512-Z5POnzgpYxrgnYuiCv+8t7lpynEcGcn0/323kV1NtE7Cwq16aMqEuC6nF2Y/tK+crJpKNEqsRtvng/eJy0xxOA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.17.8",
|
"@babel/runtime": "^7.17.8",
|
||||||
"@types/react-reconciler": "^0.26.7",
|
"@types/react-reconciler": "^0.26.7",
|
||||||
@@ -1395,9 +1397,9 @@
|
|||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/three": {
|
"node_modules/@types/three": {
|
||||||
"version": "0.160.0",
|
"version": "0.161.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.160.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.161.2.tgz",
|
||||||
"integrity": "sha512-jWlbUBovicUKaOYxzgkLlhkiEQJkhCVvg4W2IYD2trqD2om3VK4DGLpHH5zQHNr7RweZK/5re/4IVhbhvxbV9w==",
|
"integrity": "sha512-DazpZ+cIfBzbW/p0zm6G8CS03HBMd748A3R1ZOXHpqaXZLv2I5zNgQUrRG//UfJ6zYFp2cUoCQaOLaz8ubH07w==",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/stats.js": "*",
|
"@types/stats.js": "*",
|
||||||
@@ -2194,21 +2196,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
},
|
},
|
||||||
"node_modules/lodash.clamp": {
|
|
||||||
"version": "4.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.clamp/-/lodash.clamp-4.0.3.tgz",
|
|
||||||
"integrity": "sha512-HvzRFWjtcguTW7yd8NJBshuNaCa8aqNFtnswdT7f/cMd/1YKy5Zzoq4W/Oxvnx9l7aeY258uSdDfM793+eLsVg=="
|
|
||||||
},
|
|
||||||
"node_modules/lodash.omit": {
|
|
||||||
"version": "4.5.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz",
|
|
||||||
"integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg=="
|
|
||||||
},
|
|
||||||
"node_modules/lodash.pick": {
|
|
||||||
"version": "4.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz",
|
|
||||||
"integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q=="
|
|
||||||
},
|
|
||||||
"node_modules/loose-envify": {
|
"node_modules/loose-envify": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||||
@@ -2438,6 +2425,15 @@
|
|||||||
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
|
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
|
||||||
"dev": true
|
"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": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.33",
|
"version": "8.4.33",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz",
|
||||||
@@ -2599,11 +2595,28 @@
|
|||||||
"react": ">= 16.8"
|
"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": {
|
"node_modules/react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
"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": {
|
"node_modules/react-merge-refs": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-merge-refs/-/react-merge-refs-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-merge-refs/-/react-merge-refs-1.1.0.tgz",
|
||||||
@@ -2893,22 +2906,22 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/three": {
|
"node_modules/three": {
|
||||||
"version": "0.160.0",
|
"version": "0.160.1",
|
||||||
"resolved": "https://registry.npmjs.org/three/-/three-0.160.0.tgz",
|
"resolved": "https://registry.npmjs.org/three/-/three-0.160.1.tgz",
|
||||||
"integrity": "sha512-DLU8lc0zNIPkM7rH5/e1Ks1Z8tWCGRq6g8mPowdDJpw1CFBJMU7UoJjC6PefXW7z//SSl0b2+GCw14LB+uDhng=="
|
"integrity": "sha512-Bgl2wPJypDOZ1stAxwfWAcJ0WQf7QzlptsxkjYiURPz+n5k4RBDLsq+6f9Y75TYxn6aHLcWz+JNmwTOXWrQTBQ=="
|
||||||
},
|
},
|
||||||
"node_modules/three-mesh-bvh": {
|
"node_modules/three-mesh-bvh": {
|
||||||
"version": "0.6.8",
|
"version": "0.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.6.8.tgz",
|
"resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.7.0.tgz",
|
||||||
"integrity": "sha512-EGebF9DZx1S8+7OZYNNTT80GXJZVf+UYXD/HyTg/e2kR/ApofIFfUS4ZzIHNnUVIadpnLSzM4n96wX+l7GMbnQ==",
|
"integrity": "sha512-Hj0Z1Rp02yy5H+/xtMBu/dYAeRsSONaBaVLZoST9sMpZxycHypRiUeMHucPOLWFHnpc5hwelOnONcLpkfhDg0Q==",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"three": ">= 0.151.0"
|
"three": ">= 0.151.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/three-stdlib": {
|
"node_modules/three-stdlib": {
|
||||||
"version": "2.28.12",
|
"version": "2.29.4",
|
||||||
"resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.28.12.tgz",
|
"resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.29.4.tgz",
|
||||||
"integrity": "sha512-6ZAomFjrtDVNxI56F3QNgV7uVn8JlEZVgzZP+UE9h/zpKmeD3pIZvmWymw9sYPoteof0hLDFom3cETRhErQh3g==",
|
"integrity": "sha512-XNzGCrz/uAk9XoLwd35eN7dQyI4ggXZTeqjcN034YdYBpBlNO9kmLHehl/0Nw9jCelblB7jla+unHAOIyLyV6Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/draco3d": "^1.4.0",
|
"@types/draco3d": "^1.4.0",
|
||||||
"@types/offscreencanvas": "^2019.6.4",
|
"@types/offscreencanvas": "^2019.6.4",
|
||||||
@@ -2966,6 +2979,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
||||||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
||||||
},
|
},
|
||||||
|
"node_modules/tunnel-rat": {
|
||||||
|
"version": "0.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/tunnel-rat/-/tunnel-rat-0.1.2.tgz",
|
||||||
|
"integrity": "sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"zustand": "^4.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/type-is": {
|
"node_modules/type-is": {
|
||||||
"version": "1.6.18",
|
"version": "1.6.18",
|
||||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||||
@@ -3006,9 +3027,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/utility-types": {
|
"node_modules/utility-types": {
|
||||||
"version": "3.10.0",
|
"version": "3.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz",
|
||||||
"integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==",
|
"integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 4"
|
"node": ">= 4"
|
||||||
}
|
}
|
||||||
@@ -3047,9 +3068,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "4.5.1",
|
"version": "4.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz",
|
||||||
"integrity": "sha512-AXXFaAJ8yebyqzoNB9fu2pHoo/nWX+xZlaRwoeYUxEqBO+Zj4msE5G+BhGBll9lYEKv9Hfks52PAF2X7qDYXQA==",
|
"integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.18.10",
|
"esbuild": "^0.18.10",
|
||||||
|
|||||||
@@ -4,20 +4,24 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite --host",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-three/drei": "^9.93.0",
|
"@react-three/drei": "^9.96.4",
|
||||||
"@react-three/fiber": "^8.15.13",
|
"@react-three/fiber": "^8.15.15",
|
||||||
"@react-three/postprocessing": "^2.15.11",
|
"@react-three/postprocessing": "^2.15.11",
|
||||||
"@react-three/rapier": "^1.2.1",
|
"@react-three/rapier": "^1.2.1",
|
||||||
"gsap": "^3.12.5",
|
"gsap": "^3.12.5",
|
||||||
"leva": "^0.9.35",
|
"leva": "^0.9.35",
|
||||||
|
"playroomkit": "^0.0.66",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"three": "^0.160.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"
|
"zustand": "^4.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
|
After Width: | Height: | Size: 932 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 500 KiB |
|
After Width: | Height: | Size: 407 KiB |
|
After Width: | Height: | Size: 393 KiB |
|
After Width: | Height: | Size: 510 KiB |
|
After Width: | Height: | Size: 450 KiB |
|
After Width: | Height: | Size: 641 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 95 KiB |
|
After Width: | Height: | Size: 95 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 95 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 9.9 KiB |
@@ -1,8 +1,12 @@
|
|||||||
import { Canvas } from '@react-three/fiber'
|
import { Canvas } from '@react-three/fiber'
|
||||||
import { Experience } from './components/Experience'
|
import { Experience } from './components/Experience'
|
||||||
import { Suspense, useMemo } from 'react'
|
import { Suspense, useEffect, useMemo } from 'react'
|
||||||
import { Physics } from '@react-three/rapier'
|
import { Physics } from '@react-three/rapier'
|
||||||
import { KeyboardControls, Loader, OrbitControls, Preload, Stats } from '@react-three/drei'
|
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'
|
||||||
|
|
||||||
export const Controls = {
|
export const Controls = {
|
||||||
up: 'up',
|
up: 'up',
|
||||||
@@ -12,8 +16,10 @@ export const Controls = {
|
|||||||
boost: 'boost',
|
boost: 'boost',
|
||||||
shoot: 'shoot',
|
shoot: 'shoot',
|
||||||
slow: 'slow',
|
slow: 'slow',
|
||||||
reset: 'reset'
|
reset: 'reset',
|
||||||
|
escape: 'escape'
|
||||||
}
|
}
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const map = useMemo(
|
const map = useMemo(
|
||||||
() => [
|
() => [
|
||||||
@@ -24,18 +30,46 @@ function App() {
|
|||||||
{ name: Controls.jump, keys: ['Space'] },
|
{ name: Controls.jump, keys: ['Space'] },
|
||||||
{ name: Controls.slow, keys: ['Shift'] },
|
{ name: Controls.slow, keys: ['Shift'] },
|
||||||
{ name: Controls.shoot, keys: ['KeyE', 'Click'] },
|
{ name: Controls.shoot, keys: ['KeyE', 'Click'] },
|
||||||
{ name: Controls.reset, keys: ['KeyR'] }
|
{ name: Controls.reset, keys: ['KeyR'] },
|
||||||
|
{ name: Controls.escape, keys: ['Escape']}
|
||||||
],
|
],
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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 (
|
return (
|
||||||
|
<>
|
||||||
|
<Loader />
|
||||||
<Canvas
|
<Canvas
|
||||||
shadows
|
// shadows
|
||||||
dpr={1}
|
dpr={1}
|
||||||
gl={{ antialias: false, stencil: false, powerPreference: 'high-performance' }}
|
gl={{ antialias: false, stencil: false, depth:false, powerPreference: 'high-performance' }}
|
||||||
>
|
mode="concurrent"
|
||||||
|
onCreated={({ gl, camera }) => {
|
||||||
|
gl.toneMapping = THREE.AgXToneMapping
|
||||||
|
gl.setClearColor(0x000000, 0)
|
||||||
|
}}>
|
||||||
<Suspense fallback={null}>
|
<Suspense fallback={null}>
|
||||||
|
<Preload all />
|
||||||
<Physics
|
<Physics
|
||||||
gravity={[0, -90, 0]}
|
gravity={[0, -90, 0]}
|
||||||
timeStep={'vary'}
|
timeStep={'vary'}
|
||||||
@@ -43,10 +77,10 @@ function App() {
|
|||||||
<KeyboardControls map={map}>
|
<KeyboardControls map={map}>
|
||||||
<Experience />
|
<Experience />
|
||||||
</KeyboardControls>
|
</KeyboardControls>
|
||||||
{/* <Stats /> */}
|
|
||||||
</Physics>
|
</Physics>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import React, { useEffect, useRef } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
|
import { useStore } from "./components/store";
|
||||||
|
import { Joystick } from "react-joystick-component";
|
||||||
|
|
||||||
export const HUD = () => {
|
export const HUD = () => {
|
||||||
const wheel = useRef();
|
const wheel = useRef();
|
||||||
|
const [image, setImage] = useState("");
|
||||||
|
const { item, gameStarted, actions, controls } = useStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleMouseMove = (e) => {
|
const handleMouseMove = (e) => {
|
||||||
@@ -23,24 +27,118 @@ 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 (
|
return (
|
||||||
<div className="overlay"> dadasd
|
<div className="overlay">
|
||||||
<div className="logo">
|
{gameStarted && (
|
||||||
<img src="./logo.png" alt="logo" />
|
<>
|
||||||
|
<div className="item">
|
||||||
|
<div className="borderOut">
|
||||||
|
<div className="borderIn">
|
||||||
|
<div className="background">
|
||||||
|
{image && <img src={image} alt="item" width={90} />}
|
||||||
</div>
|
</div>
|
||||||
<div className="wheel">
|
</div>
|
||||||
<img
|
</div>
|
||||||
ref={wheel}
|
</div>
|
||||||
src="./steering_wheel.png"
|
{controls === "touch" && (
|
||||||
alt="steering wheel"
|
<>
|
||||||
className="steering-wheel"
|
<div className="controls joystick">
|
||||||
style={{
|
<Joystick
|
||||||
position: "absolute",
|
size={100}
|
||||||
pointerEvents: "none",
|
sticky={false}
|
||||||
transformOrigin: "center",
|
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>
|
||||||
|
<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>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
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,27 +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} />
|
|
||||||
|
|
||||||
<Particles4 turboColor={turboColor} scale={scale} />
|
|
||||||
|
|
||||||
|
|
||||||
</group>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
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,25 +1,182 @@
|
|||||||
import { Environment, OrbitControls, PerspectiveCamera, Lightformer } from '@react-three/drei'
|
import {
|
||||||
import { Ground } from './Ground'
|
Environment,
|
||||||
import { RigidBody } from '@react-three/rapier'
|
OrbitControls,
|
||||||
import { PlayerController } from './PlayerController'
|
PerspectiveCamera,
|
||||||
import { Track } from './models/Spafrancorchamps-REALISTIC'
|
Lightformer,
|
||||||
import { Paris } from './models/Tour_paris_promenade'
|
Bvh,
|
||||||
import { EffectComposer, N8AO, Bloom, DepthOfField, TiltShift2, HueSaturation, SMAA, ChromaticAberration, Vignette } from '@react-three/postprocessing'
|
} from "@react-three/drei";
|
||||||
import { PlayerControllerAgain } from './PlayerControllerAgain'
|
import { Ground } from "./Ground";
|
||||||
import { Skid } from './Skid'
|
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";
|
||||||
|
|
||||||
export const Experience = () => {
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<PlayerController />
|
{gameStarted &&
|
||||||
<Skid />
|
players.map((player) => {
|
||||||
{/* <PlayerControllerAgain /> */}
|
const ControllerComponent =
|
||||||
<Ground position={[0, 0, 0]} />
|
controls === "keyboard"
|
||||||
<Environment
|
? PlayerControllerKeyboard
|
||||||
resolution={256}
|
: controls === "gamepad"
|
||||||
preset='lobby'
|
? 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 />
|
||||||
|
|
||||||
|
<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}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
|
||||||
<directionalLight
|
<directionalLight
|
||||||
position={[10, 50, -30]}
|
position={[10, 50, -30]}
|
||||||
@@ -29,39 +186,29 @@ export const Experience = () => {
|
|||||||
shadow-camera-left={-300}
|
shadow-camera-left={-300}
|
||||||
shadow-camera-right={300}
|
shadow-camera-right={300}
|
||||||
shadow-camera-top={300}
|
shadow-camera-top={300}
|
||||||
shadow-camera-bottom={-3000}
|
shadow-camera-bottom={-300}
|
||||||
castShadow
|
castShadow
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* <ambientLight intensity={0.2} /> */}
|
|
||||||
{/* <spotLight position={[10, 20, 10]} angle={0.12} penumbra={1} intensity={1} castShadow shadow-mapSize={1024} /> */}
|
|
||||||
<Paris position={[0, 0, 0]} />
|
|
||||||
<EffectComposer
|
<EffectComposer
|
||||||
multisampling={0}
|
multisampling={0}
|
||||||
disableNormalPass
|
disableNormalPass
|
||||||
disableSSAO
|
disableSSAO
|
||||||
disableDepthPass
|
disableDepthPass
|
||||||
|
|
||||||
>
|
>
|
||||||
<SMAA />
|
<SMAA />
|
||||||
<N8AO distanceFalloff={1} aoRadius={1} intensity={3} />
|
{/* <N8AO distanceFalloff={1} aoRadius={1} intensity={3} /> */}
|
||||||
<Bloom
|
<Bloom
|
||||||
luminanceThreshold={0}
|
luminanceThreshold={0}
|
||||||
mipmapBlur
|
mipmapBlur
|
||||||
luminanceSmoothing={0.01}
|
luminanceSmoothing={0.01}
|
||||||
intensity={0.5}
|
intensity={0.5}
|
||||||
/>
|
/>
|
||||||
{/* <DepthOfField
|
|
||||||
target={[0, 0, 12]}
|
|
||||||
focalLength={15}
|
|
||||||
bokehScale={60}
|
|
||||||
resolutionScale={1}
|
|
||||||
/> */}
|
|
||||||
<TiltShift2 />
|
<TiltShift2 />
|
||||||
<ChromaticAberration offset={[0.0006, 0.0006]} />
|
{/* <ChromaticAberration offset={[0.0006, 0.0006]} /> */}
|
||||||
<HueSaturation saturation={0.1} />
|
<HueSaturation saturation={0.05} />
|
||||||
<Vignette eskil={false} offset={0.1} darkness={0.4} />
|
{/* <Vignette eskil={false} offset={0.1} darkness={0.4} /> */}
|
||||||
</EffectComposer>
|
</EffectComposer>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
import React, { useState, useEffect, useRef } from "react";
|
|
||||||
import { useLoader, useFrame } from "@react-three/fiber";
|
|
||||||
import * as THREE from "three";
|
|
||||||
|
|
||||||
export const FlameParticle = ({ position, png, turboColor, delay = 0 }) => {
|
|
||||||
const texture = useLoader(THREE.TextureLoader, png);
|
|
||||||
const pointsRef = useRef();
|
|
||||||
const [size, setSize] = useState(1);
|
|
||||||
const [opacity, setOpacity] = useState(1);
|
|
||||||
const [initialized, setInitialized] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const timer = setTimeout(() => {
|
|
||||||
setInitialized(true);
|
|
||||||
}, delay);
|
|
||||||
return () => clearTimeout(timer);
|
|
||||||
}, [delay]);
|
|
||||||
|
|
||||||
const points = React.useMemo(() => {
|
|
||||||
const geom = new THREE.BufferGeometry();
|
|
||||||
geom.setAttribute(
|
|
||||||
"position",
|
|
||||||
new THREE.Float32BufferAttribute(position, 3)
|
|
||||||
);
|
|
||||||
return geom;
|
|
||||||
}, [position]);
|
|
||||||
|
|
||||||
useFrame(({clock}, delta) => {
|
|
||||||
if (!initialized) return;
|
|
||||||
|
|
||||||
pointsRef.current.position.y += 0.03 * delta * 144;
|
|
||||||
pointsRef.current.position.z += 0.06 * delta * 144;
|
|
||||||
if(pointsRef.current.position.y > 0.4) {
|
|
||||||
pointsRef.current.position.y = 0;
|
|
||||||
pointsRef.current.position.z = 0;
|
|
||||||
setOpacity(1);
|
|
||||||
}
|
|
||||||
if(opacity > 0) {
|
|
||||||
setOpacity((opacity) => opacity - 0.05 * delta * 144);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<points ref={pointsRef} geometry={points}>
|
|
||||||
<pointsMaterial
|
|
||||||
size={size}
|
|
||||||
alphaMap={texture}
|
|
||||||
transparent={true}
|
|
||||||
depthWrite={false}
|
|
||||||
color={0x000000}
|
|
||||||
opacity={opacity}
|
|
||||||
toneMapped={false}
|
|
||||||
/>
|
|
||||||
</points>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import React, { useEffect,useRef, useState } from "react";
|
||||||
|
import { useLoader, useFrame } from "@react-three/fiber";
|
||||||
|
import * as THREE from "three";
|
||||||
|
|
||||||
|
export const CircleCoinParticle = ({ position, coins }) => {
|
||||||
|
const texture = useLoader(THREE.TextureLoader, "./particles/circle_coin.png");
|
||||||
|
const pointsRef = useRef();
|
||||||
|
const materialRef = useRef();
|
||||||
|
const [size, setSize] = useState(1);
|
||||||
|
const [opacity, setOpacity] = useState(1);
|
||||||
|
|
||||||
|
const points = React.useMemo(() => {
|
||||||
|
const geom = new THREE.BufferGeometry();
|
||||||
|
geom.setAttribute(
|
||||||
|
"position",
|
||||||
|
new THREE.Float32BufferAttribute(position, 3)
|
||||||
|
);
|
||||||
|
return geom;
|
||||||
|
}, [position]);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (materialRef.current) {
|
||||||
|
materialRef.current.color.multiplyScalar(4);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSize(0);
|
||||||
|
setOpacity(1);
|
||||||
|
}, [coins]);
|
||||||
|
|
||||||
|
useFrame((_, delta) => {
|
||||||
|
if (size < 5) {
|
||||||
|
setSize((size) => Math.min(size + 0.2 * delta * 144, 5));
|
||||||
|
} else if (opacity > 0) {
|
||||||
|
setOpacity((opacity) => Math.max(opacity - 0.1 * delta * 144, 0));
|
||||||
|
setSize((size) => Math.max(size - 0.1 * delta * 144, 0));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<points ref={pointsRef} geometry={points}>
|
||||||
|
<pointsMaterial
|
||||||
|
ref={materialRef}
|
||||||
|
size={size}
|
||||||
|
alphaMap={texture}
|
||||||
|
transparent={true}
|
||||||
|
depthWrite={false}
|
||||||
|
opacity={opacity}
|
||||||
|
toneMapped={false}
|
||||||
|
color={0xbf8717}
|
||||||
|
/>
|
||||||
|
</points>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
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}/>
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import React, { useEffect, useRef } from "react";
|
||||||
|
import { useLoader, useFrame } from "@react-three/fiber";
|
||||||
|
import * as THREE from "three";
|
||||||
|
|
||||||
|
export const StarCoinParticle = ({ position, coins, timeModifier }) => {
|
||||||
|
const texture = useLoader(THREE.TextureLoader, "./particles/star_coin.png");
|
||||||
|
const pointsRef = useRef();
|
||||||
|
const materialRef = useRef();
|
||||||
|
const sizeRef = useRef(1);
|
||||||
|
const opacityRef = useRef(1);
|
||||||
|
const originalYpos = useRef(0);
|
||||||
|
|
||||||
|
const points = React.useMemo(() => {
|
||||||
|
const geom = new THREE.BufferGeometry();
|
||||||
|
geom.setAttribute(
|
||||||
|
"position",
|
||||||
|
new THREE.Float32BufferAttribute(position, 3)
|
||||||
|
);
|
||||||
|
return geom;
|
||||||
|
}, [position]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (materialRef.current) {
|
||||||
|
materialRef.current.color.multiplyScalar(6);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
sizeRef.current = 0;
|
||||||
|
opacityRef.current = 1;
|
||||||
|
pointsRef.current.position.x = Math.random() * 1 - 0.5;
|
||||||
|
pointsRef.current.position.y = Math.random() * 0.5 - 0.25;
|
||||||
|
originalYpos.current = pointsRef.current.position.y;
|
||||||
|
}, [coins]);
|
||||||
|
|
||||||
|
useFrame((state, delta) => {
|
||||||
|
const time = state.clock.getElapsedTime();
|
||||||
|
pointsRef.current.position.y += 0.008 * delta * 144;
|
||||||
|
if (sizeRef.current < 1) {
|
||||||
|
sizeRef.current = Math.min(sizeRef.current + 0.01 * delta * 144, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pointsRef.current.position.y > originalYpos.current + 0.01) {
|
||||||
|
opacityRef.current = Math.max(opacityRef.current - 0.01 * delta * 144, 0);
|
||||||
|
} else {
|
||||||
|
opacityRef.current = Math.abs(Math.sin(time * timeModifier * 1500));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update material properties directly
|
||||||
|
if (materialRef.current) {
|
||||||
|
materialRef.current.size = sizeRef.current;
|
||||||
|
materialRef.current.opacity = opacityRef.current;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<points ref={pointsRef} geometry={points}>
|
||||||
|
<pointsMaterial
|
||||||
|
ref={materialRef}
|
||||||
|
alphaMap={texture}
|
||||||
|
transparent={true}
|
||||||
|
depthWrite={false}
|
||||||
|
toneMapped={false}
|
||||||
|
color={0xbf8717}
|
||||||
|
/>
|
||||||
|
</points>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -3,9 +3,9 @@ import { Particles3 } from "./Particles3";
|
|||||||
|
|
||||||
export const DriftParticlesLeft = ({turboColor,scale, ...props}) => {
|
export const DriftParticlesLeft = ({turboColor,scale, ...props}) => {
|
||||||
|
|
||||||
if(scale < 0.8) {
|
// if(scale < 0.8) {
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group {...props}>
|
<group {...props}>
|
||||||
@@ -18,8 +18,16 @@ export const DriftParticlesLeft = ({turboColor,scale, ...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} />
|
||||||
<Particles3 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>
|
</group>
|
||||||
)
|
)
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
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>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -15,10 +15,9 @@ export const Particles2 = ({ turboColor, scale, ...props }) => {
|
|||||||
let position = ref.current.position;
|
let position = ref.current.position;
|
||||||
let velocityVector = new THREE.Vector3(velocity.current.x, velocity.current.y, velocity.current.z);
|
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
|
velocity.current.y += gravity * delta * 144;
|
||||||
|
|
||||||
position.x += velocity.current.x * delta * 144;
|
position.x += velocity.current.x * delta * 144;
|
||||||
position.y += velocity.current.y * delta * 144;
|
position.y += velocity.current.y * delta * 144;
|
||||||
position.z += velocity.current.z * delta * 144;
|
position.z += velocity.current.z * delta * 144;
|
||||||
@@ -5,6 +5,7 @@ import * as THREE from "three";
|
|||||||
export const PointParticle = ({ position, png, turboColor }) => {
|
export const PointParticle = ({ position, png, turboColor }) => {
|
||||||
const texture = useLoader(THREE.TextureLoader, png);
|
const texture = useLoader(THREE.TextureLoader, png);
|
||||||
const pointsRef = useRef();
|
const pointsRef = useRef();
|
||||||
|
const materialRef = useRef();
|
||||||
const [size, setSize] = useState(0);
|
const [size, setSize] = useState(0);
|
||||||
const [opacity, setOpacity] = useState(1);
|
const [opacity, setOpacity] = useState(1);
|
||||||
|
|
||||||
@@ -18,7 +19,9 @@ export const PointParticle = ({ position, png, turboColor }) => {
|
|||||||
}, [position]);
|
}, [position]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (materialRef.current) {
|
||||||
|
materialRef.current.color.multiplyScalar(10);
|
||||||
|
}
|
||||||
setSize(0);
|
setSize(0);
|
||||||
setOpacity(1);
|
setOpacity(1);
|
||||||
}, [turboColor]);
|
}, [turboColor]);
|
||||||
@@ -36,6 +39,7 @@ export const PointParticle = ({ position, png, turboColor }) => {
|
|||||||
return (
|
return (
|
||||||
<points ref={pointsRef} geometry={points}>
|
<points ref={pointsRef} geometry={points}>
|
||||||
<pointsMaterial
|
<pointsMaterial
|
||||||
|
ref={materialRef}
|
||||||
size={size}
|
size={size}
|
||||||
alphaMap={texture}
|
alphaMap={texture}
|
||||||
transparent={true}
|
transparent={true}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
import React, { useRef, useMemo } from "react";
|
||||||
|
import { useLoader, useFrame } from "@react-three/fiber";
|
||||||
|
import * as THREE from "three";
|
||||||
|
|
||||||
|
export const FlameParticle = ({ position, png, isBoosting, 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 (isBoosting) {
|
||||||
|
// Update logic when boosting
|
||||||
|
pointsCurrent.position.y += 0.03 * delta * 144;
|
||||||
|
pointsCurrent.position.z += 0.06 * delta * 144;
|
||||||
|
|
||||||
|
if(pointsCurrent.position.y > 0.4) {
|
||||||
|
pointsCurrent.position.y = 0;
|
||||||
|
pointsCurrent.position.z = 0;
|
||||||
|
pointsCurrent.material.opacity = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pointsCurrent.material.opacity > 0) {
|
||||||
|
pointsCurrent.material.opacity -= 0.05 * delta * 144;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Reset position and opacity when not boosting
|
||||||
|
pointsCurrent.position.y = 0;
|
||||||
|
pointsCurrent.position.z = 0;
|
||||||
|
pointsCurrent.material.opacity = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<points ref={pointsRef} geometry={points}>
|
||||||
|
<pointsMaterial
|
||||||
|
size={1}
|
||||||
|
alphaMap={texture}
|
||||||
|
transparent={true}
|
||||||
|
depthWrite={false}
|
||||||
|
color={0xff9900}
|
||||||
|
opacity={1}
|
||||||
|
toneMapped={false}
|
||||||
|
/>
|
||||||
|
</points>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -2,9 +2,7 @@ import { FlameParticle } from "./FlameParticle";
|
|||||||
|
|
||||||
export const FlameParticles = ({ isBoosting }) => {
|
export const FlameParticles = ({ isBoosting }) => {
|
||||||
|
|
||||||
if (!isBoosting) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<group>
|
<group>
|
||||||
{/* bottom left */}
|
{/* bottom left */}
|
||||||
@@ -12,37 +10,37 @@ export const FlameParticles = ({ isBoosting }) => {
|
|||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_01.png"
|
png="./fire_01.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={0}
|
delay={0}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_02.png"
|
png="./fire_02.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={100}
|
delay={100}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_01.png"
|
png="./fire_01.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={200}
|
delay={200}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_02.png"
|
png="./fire_02.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={300}
|
delay={300}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_02.png"
|
png="./fire_02.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={400}
|
delay={400}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_01.png"
|
png="./fire_01.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={500}
|
delay={500}
|
||||||
/>
|
/>
|
||||||
</group>
|
</group>
|
||||||
@@ -52,37 +50,37 @@ export const FlameParticles = ({ isBoosting }) => {
|
|||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_01.png"
|
png="./fire_01.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={0}
|
delay={0}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_02.png"
|
png="./fire_02.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={100}
|
delay={100}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_01.png"
|
png="./fire_01.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={200}
|
delay={200}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_02.png"
|
png="./fire_02.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={300}
|
delay={300}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_01.png"
|
png="./fire_01.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={400}
|
delay={400}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_02.png"
|
png="./fire_02.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={500}
|
delay={500}
|
||||||
/>
|
/>
|
||||||
</group>
|
</group>
|
||||||
@@ -91,37 +89,37 @@ export const FlameParticles = ({ isBoosting }) => {
|
|||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_02.png"
|
png="./fire_02.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={0}
|
delay={0}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_01.png"
|
png="./fire_01.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={100}
|
delay={100}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_02.png"
|
png="./fire_02.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={200}
|
delay={200}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_01.png"
|
png="./fire_01.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={300}
|
delay={300}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_02.png"
|
png="./fire_02.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={400}
|
delay={400}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_01.png"
|
png="./fire_01.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={500}
|
delay={500}
|
||||||
/>
|
/>
|
||||||
</group>
|
</group>
|
||||||
@@ -129,37 +127,37 @@ export const FlameParticles = ({ isBoosting }) => {
|
|||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_02.png"
|
png="./fire_02.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={0}
|
delay={0}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_01.png"
|
png="./fire_01.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={100}
|
delay={100}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_02.png"
|
png="./fire_02.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={200}
|
delay={200}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_01.png"
|
png="./fire_01.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={300}
|
delay={300}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_02.png"
|
png="./fire_02.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={400}
|
delay={400}
|
||||||
/>
|
/>
|
||||||
<FlameParticle
|
<FlameParticle
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, 0]}
|
||||||
png="./fire_01.png"
|
png="./fire_01.png"
|
||||||
turboColor={0xfea347}
|
isBoosting={isBoosting}
|
||||||
delay={500}
|
delay={500}
|
||||||
/>
|
/>
|
||||||
</group>
|
</group>
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
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 });
|
||||||
|
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
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>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
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}/>
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import React, { useEffect,useRef, useState } from "react";
|
||||||
|
import { useLoader, useFrame } from "@react-three/fiber";
|
||||||
|
import * as THREE from "three";
|
||||||
|
|
||||||
|
export const CircleItemParticle = ({ position, item, color }) => {
|
||||||
|
const texture = useLoader(THREE.TextureLoader, "./particles/circle_coin.png");
|
||||||
|
const pointsRef = useRef();
|
||||||
|
const materialRef = useRef();
|
||||||
|
const [size, setSize] = useState(1);
|
||||||
|
const [opacity, setOpacity] = useState(1);
|
||||||
|
|
||||||
|
const [currentColor, setCurrentColor] = useState(color);
|
||||||
|
|
||||||
|
const points = React.useMemo(() => {
|
||||||
|
const geom = new THREE.BufferGeometry();
|
||||||
|
geom.setAttribute(
|
||||||
|
"position",
|
||||||
|
new THREE.Float32BufferAttribute(position, 3)
|
||||||
|
);
|
||||||
|
return geom;
|
||||||
|
}, [position]);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (materialRef.current) {
|
||||||
|
materialRef.current.color.multiplyScalar(4);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(item){
|
||||||
|
setSize(0);
|
||||||
|
setOpacity(1);
|
||||||
|
}
|
||||||
|
}, [item]);
|
||||||
|
|
||||||
|
useFrame((_, delta) => {
|
||||||
|
if (size < 5) {
|
||||||
|
setSize((size) => Math.min(size + 0.2 * delta * 144, 5));
|
||||||
|
} else if (opacity > 0) {
|
||||||
|
setOpacity((opacity) => Math.max(opacity - 0.1 * delta * 144, 0));
|
||||||
|
setSize((size) => Math.max(size - 0.1 * delta * 144, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<points ref={pointsRef} geometry={points}>
|
||||||
|
<pointsMaterial
|
||||||
|
ref={materialRef}
|
||||||
|
size={size}
|
||||||
|
alphaMap={texture}
|
||||||
|
transparent={true}
|
||||||
|
depthWrite={false}
|
||||||
|
opacity={opacity}
|
||||||
|
toneMapped={false}
|
||||||
|
color={currentColor}
|
||||||
|
/>
|
||||||
|
</points>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
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}/>
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import React, { useEffect, useRef } from "react";
|
||||||
|
import { useLoader, useFrame } from "@react-three/fiber";
|
||||||
|
import * as THREE from "three";
|
||||||
|
|
||||||
|
export const SmallCircleParticle = ({ position, item, timeModifier, color }) => {
|
||||||
|
const texture = useLoader(THREE.TextureLoader, "./particles/circle_01.png");
|
||||||
|
const pointsRef = useRef();
|
||||||
|
const materialRef = useRef();
|
||||||
|
const sizeRef = useRef(1);
|
||||||
|
const opacityRef = useRef(1);
|
||||||
|
const originalYpos = useRef(0);
|
||||||
|
|
||||||
|
const points = React.useMemo(() => {
|
||||||
|
const geom = new THREE.BufferGeometry();
|
||||||
|
geom.setAttribute(
|
||||||
|
"position",
|
||||||
|
new THREE.Float32BufferAttribute(position, 3)
|
||||||
|
);
|
||||||
|
return geom;
|
||||||
|
}, [position]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (materialRef.current) {
|
||||||
|
materialRef.current.color.multiplyScalar(6);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(item){
|
||||||
|
sizeRef.current = 0;
|
||||||
|
opacityRef.current = 1;
|
||||||
|
pointsRef.current.position.x = Math.random() * 1 - 0.5;
|
||||||
|
pointsRef.current.position.y = Math.random() * 0.5 - 0.25;
|
||||||
|
originalYpos.current = pointsRef.current.position.y;
|
||||||
|
}
|
||||||
|
}, [item]);
|
||||||
|
|
||||||
|
useFrame((state, delta) => {
|
||||||
|
const time = state.clock.getElapsedTime();
|
||||||
|
pointsRef.current.position.y += 0.008 * delta * 144;
|
||||||
|
if (sizeRef.current < 1) {
|
||||||
|
sizeRef.current = Math.min(sizeRef.current + 0.01 * delta * 144, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pointsRef.current.position.y > originalYpos.current + 0.01) {
|
||||||
|
opacityRef.current = Math.max(opacityRef.current - 0.01 * delta * 144, 0);
|
||||||
|
} else {
|
||||||
|
opacityRef.current = Math.abs(Math.sin(time * timeModifier * 1500));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update material properties directly
|
||||||
|
if (materialRef.current) {
|
||||||
|
materialRef.current.size = sizeRef.current;
|
||||||
|
materialRef.current.opacity = opacityRef.current;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<points ref={pointsRef} geometry={points}>
|
||||||
|
<pointsMaterial
|
||||||
|
ref={materialRef}
|
||||||
|
alphaMap={texture}
|
||||||
|
transparent={true}
|
||||||
|
depthWrite={false}
|
||||||
|
toneMapped={false}
|
||||||
|
color={color}
|
||||||
|
/>
|
||||||
|
</points>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import React, { useEffect, useRef } from "react";
|
||||||
|
import { useLoader, useFrame } from "@react-three/fiber";
|
||||||
|
import * as THREE from "three";
|
||||||
|
|
||||||
|
export const StarItemParticle = ({ position, item, timeModifier, color }) => {
|
||||||
|
const texture = useLoader(THREE.TextureLoader, "./particles/star_coin.png");
|
||||||
|
const pointsRef = useRef();
|
||||||
|
const materialRef = useRef();
|
||||||
|
const sizeRef = useRef(1);
|
||||||
|
const opacityRef = useRef(1);
|
||||||
|
const originalYpos = useRef(0);
|
||||||
|
|
||||||
|
const points = React.useMemo(() => {
|
||||||
|
const geom = new THREE.BufferGeometry();
|
||||||
|
geom.setAttribute(
|
||||||
|
"position",
|
||||||
|
new THREE.Float32BufferAttribute(position, 3)
|
||||||
|
);
|
||||||
|
return geom;
|
||||||
|
}, [position]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (materialRef.current) {
|
||||||
|
materialRef.current.color.multiplyScalar(6);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(item){
|
||||||
|
sizeRef.current = 0;
|
||||||
|
opacityRef.current = 1;
|
||||||
|
pointsRef.current.position.x = Math.random() * 1 - 0.5;
|
||||||
|
pointsRef.current.position.y = Math.random() * 0.5 - 0.25;
|
||||||
|
originalYpos.current = pointsRef.current.position.y;
|
||||||
|
}
|
||||||
|
}, [item]);
|
||||||
|
|
||||||
|
useFrame((state, delta) => {
|
||||||
|
const time = state.clock.getElapsedTime();
|
||||||
|
pointsRef.current.position.y += 0.008 * delta * 144;
|
||||||
|
if (sizeRef.current < 1) {
|
||||||
|
sizeRef.current = Math.min(sizeRef.current + 0.01 * delta * 144, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pointsRef.current.position.y > originalYpos.current + 0.01) {
|
||||||
|
opacityRef.current = Math.max(opacityRef.current - 0.01 * delta * 144, 0);
|
||||||
|
} else {
|
||||||
|
opacityRef.current = Math.abs(Math.sin(time * timeModifier * 1500));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update material properties directly
|
||||||
|
if (materialRef.current) {
|
||||||
|
materialRef.current.size = sizeRef.current;
|
||||||
|
materialRef.current.opacity = opacityRef.current;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<points ref={pointsRef} geometry={points}>
|
||||||
|
<pointsMaterial
|
||||||
|
ref={materialRef}
|
||||||
|
alphaMap={texture}
|
||||||
|
transparent={true}
|
||||||
|
depthWrite={false}
|
||||||
|
toneMapped={false}
|
||||||
|
color={color}
|
||||||
|
/>
|
||||||
|
</points>
|
||||||
|
);
|
||||||
|
};
|
||||||