-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d9afc32
commit bde836a
Showing
13 changed files
with
1,877 additions
and
122 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/* | ||
Auto-generated by: https://github.com/pmndrs/gltfjsx | ||
Command: npx gltfjsx@6.2.3 public/models/character.glb -o src/components/Character.jsx -r public | ||
*/ | ||
|
||
import { useAnimations, useGLTF } from "@react-three/drei"; | ||
import React, { useEffect, useRef } from "react"; | ||
|
||
export function Character({ animation, ...props }) { | ||
const group = useRef(); | ||
const { nodes, materials, animations } = useGLTF("/models/character.glb"); | ||
const { actions } = useAnimations(animations, group); | ||
useEffect(() => { | ||
actions[animation]?.reset().fadeIn(0.24).play(); | ||
return () => actions?.[animation]?.fadeOut(0.24); | ||
}, [animation]); | ||
return ( | ||
<group ref={group} {...props} dispose={null}> | ||
<group name="Scene"> | ||
<group name="fall_guys"> | ||
<primitive object={nodes._rootJoint} /> | ||
<skinnedMesh | ||
name="body" | ||
geometry={nodes.body.geometry} | ||
material={materials.Material} | ||
skeleton={nodes.body.skeleton} | ||
castShadow | ||
receiveShadow | ||
/> | ||
<skinnedMesh | ||
name="eye" | ||
geometry={nodes.eye.geometry} | ||
material={materials.Material} | ||
skeleton={nodes.eye.skeleton} | ||
castShadow | ||
receiveShadow | ||
/> | ||
<skinnedMesh | ||
name="hand-" | ||
geometry={nodes["hand-"].geometry} | ||
material={materials.Material} | ||
skeleton={nodes["hand-"].skeleton} | ||
castShadow | ||
receiveShadow | ||
/> | ||
<skinnedMesh | ||
name="leg" | ||
geometry={nodes.leg.geometry} | ||
material={materials.Material} | ||
skeleton={nodes.leg.skeleton} | ||
castShadow | ||
receiveShadow | ||
/> | ||
</group> | ||
</group> | ||
</group> | ||
); | ||
} | ||
|
||
useGLTF.preload("/models/character.glb"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
import { useEffect, useRef, useState } from "react"; | ||
import { Character } from "./Character"; | ||
import { CapsuleCollider, RigidBody } from "@react-three/rapier"; | ||
import { MathUtils, MOUSE, Vector3 } from "three"; | ||
import { useFrame } from "@react-three/fiber"; | ||
import { useControls } from "leva"; | ||
import { useKeyboardControls } from "@react-three/drei"; | ||
import { degToRad } from "three/src/math/MathUtils"; | ||
|
||
const normalizeAngle = (angle) => { | ||
while (angle > Math.PI) angle -= 2 * Math.PI; | ||
while (angle < -Math.PI) angle += 2 * Math.PI; | ||
return angle; | ||
}; | ||
|
||
const lerpAngle = (start, end, t) => { | ||
start = normalizeAngle(start); | ||
end = normalizeAngle(end); | ||
|
||
if (Math.abs(end - start) > Math.PI) { | ||
if (end > start) { | ||
start += 2 * Math.PI; | ||
} else { | ||
end += 2 * Math.PI; | ||
} | ||
} | ||
|
||
return normalizeAngle(start + (end - start) * t); | ||
}; | ||
|
||
const CharacterController = () => { | ||
// LevaControls | ||
const { WALK_SPEED, RUN_SPEED, ROTATION_SPEED } = useControls( | ||
"Character Controls", | ||
{ | ||
WALK_SPEED: { value: 0.8, min: 0.1, max: 4, step: 0.1 }, | ||
RUN_SPEED: { value: 1.6, min: 0.2, max: 12, step: 0.1 }, | ||
ROTATION_SPEED: { | ||
value: degToRad(1), | ||
min: degToRad(0.1), | ||
max: degToRad(5), | ||
step: degToRad(0.1), | ||
}, | ||
} | ||
); | ||
//Variables | ||
const rb = useRef(); | ||
const container = useRef(); | ||
|
||
const cameraTarget = useRef(); | ||
const cameraPosition = useRef(); | ||
|
||
const [animation, setAnimation] = useState("idle"); | ||
const character = useRef(); | ||
const characterRotationTarget = useRef(0); | ||
const rotationTarget = useRef(0); | ||
|
||
const cameraWorldPosition = useRef(new Vector3()); | ||
const cameraLookAtWorldPosition = useRef(new Vector3()); | ||
const cameraLookAt = useRef(new Vector3()); | ||
const [, get] = useKeyboardControls(); | ||
const isClicking = useRef(false); | ||
|
||
//MOUSE CLICK | ||
useEffect(() => { | ||
const onMouseDown = (e) => (isClicking.current = true); | ||
const onMouseUp = (e) => (isClicking.current = false); | ||
document.addEventListener("mousedown", onMouseDown); | ||
document.addEventListener("mouseup", onMouseUp); | ||
//TOUCH | ||
document.addEventListener("touchstart", onMouseDown); | ||
document.addEventListener("touchend",onMouseUp) | ||
return () => { | ||
document.removeEventListener("mousedown", onMouseDown); | ||
document.removeEventListener("mouseup", onMouseUp); | ||
document.removeEventListener("touchstart", onMouseDown); | ||
document.removeEventListener("touchend",onMouseUp) | ||
}; | ||
}, []); | ||
|
||
useFrame(({ camera, mouse }) => { | ||
if (rb.current) { | ||
const vel = rb.current.linvel(); | ||
|
||
const movement = { | ||
x: 0, | ||
z: 0, | ||
}; | ||
|
||
//MOVEMENT DIRECTION | ||
if (get().forward) { | ||
movement.z = 1; | ||
} | ||
if (get().backward) { | ||
movement.z = -1; | ||
} | ||
if (get().left) { | ||
movement.x = 1; | ||
} | ||
if (get().right) { | ||
movement.x = -1; | ||
} | ||
|
||
//MOVEMENT SPEED | ||
let speed = get().run ? RUN_SPEED : WALK_SPEED; | ||
|
||
if (isClicking.current) { | ||
console.log("clicking", mouse.x, mouse.y); | ||
if(Math.abs(mouse.x)>0.1){ | ||
movement.x = -mouse.x; | ||
} | ||
|
||
movement.z = mouse.y+0.4; | ||
if(Math.abs(movement.x)>0.5||Math.abs(movement.z)>0.5){ | ||
speed = RUN_SPEED; | ||
} | ||
} | ||
|
||
if (movement.x !== 0 || movement.z !== 0) { | ||
characterRotationTarget.current = Math.atan2(movement.x, movement.z); | ||
vel.x = | ||
Math.sin(rotationTarget.current + characterRotationTarget.current) * | ||
speed; | ||
vel.z = | ||
Math.cos(rotationTarget.current + characterRotationTarget.current) * | ||
speed; | ||
if (speed === RUN_SPEED) { | ||
setAnimation("run"); | ||
} else { | ||
setAnimation("walk"); | ||
} | ||
} else { | ||
setAnimation("idle"); | ||
} | ||
character.current.rotation.y = lerpAngle( | ||
character.current.rotation.y, | ||
characterRotationTarget.current, | ||
0.1 | ||
); | ||
rb.current.setLinvel(vel, true); | ||
|
||
//ROTATION | ||
if (movement.x !== 0 || movement.z !== 0) { | ||
rotationTarget.current += ROTATION_SPEED * movement.x; | ||
} | ||
} | ||
|
||
//CAMERA | ||
container.current.rotation.y = MathUtils.lerp( | ||
container.current.rotation.y, | ||
rotationTarget.current, | ||
0.1 | ||
); | ||
cameraPosition.current.getWorldPosition(cameraWorldPosition.current); | ||
camera.position.lerp(cameraWorldPosition.current, 0.1); | ||
|
||
if (cameraTarget.current) { | ||
cameraTarget.current.getWorldPosition(cameraLookAtWorldPosition.current); | ||
cameraLookAt.current.lerp(cameraLookAtWorldPosition.current, 0.1); | ||
|
||
camera.lookAt(cameraLookAt.current); | ||
} | ||
}); | ||
|
||
return ( | ||
<RigidBody colliders={false} lockRotations ref={rb}> | ||
<group ref={container}> | ||
<group ref={cameraTarget} position-z={1.5} /> | ||
<group ref={cameraPosition} position-y={4} position-z={-4} /> | ||
<group ref={character}> | ||
<Character scale={0.18} position-y={-0.25} animation={animation} /> | ||
</group> | ||
</group> | ||
<CapsuleCollider args={[0.08, 0.2]} /> | ||
</RigidBody> | ||
); | ||
}; | ||
|
||
export default CharacterController; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
"use client"; | ||
import { | ||
Environment, | ||
OrbitControls, | ||
OrthographicCamera, | ||
} from "@react-three/drei"; | ||
import { useControls } from "leva"; | ||
import { useRef } from "react"; | ||
import { Character } from "./Character"; | ||
import { Map } from "./Map"; | ||
import { Physics } from "@react-three/rapier"; | ||
import CharacterController from "./CharacterController"; | ||
|
||
const maps = { | ||
castle_on_hills: { | ||
scale: 3, | ||
position: [-6, -7, 0], | ||
}, | ||
animal_crossing_map: { | ||
scale: 20, | ||
position: [-15, -1, 10], | ||
}, | ||
city_scene_tokyo: { | ||
scale: 0.72, | ||
position: [0, -1, -3.5], | ||
}, | ||
de_dust_2_with_real_light: { | ||
scale: 0.3, | ||
position: [-5, -3, 13], | ||
}, | ||
medieval_fantasy_book: { | ||
scale: 0.4, | ||
position: [-4, 0, -6], | ||
}, | ||
}; | ||
|
||
export const Experience = () => { | ||
const shadowCameraRef = useRef(); | ||
const { map } = useControls("Map", { | ||
map: { | ||
value: "castle_on_hills", | ||
options: Object.keys(maps), | ||
}, | ||
}); | ||
|
||
return ( | ||
<> | ||
{/* <OrbitControls /> */} | ||
<Environment preset="sunset" /> | ||
<directionalLight | ||
intensity={0.65} | ||
castShadow | ||
position={[-15, 10, 15]} | ||
shadow-mapSize-width={2048} | ||
shadow-mapSize-height={2048} | ||
shadow-bias={-0.00005} | ||
> | ||
<OrthographicCamera | ||
left={-22} | ||
right={15} | ||
top={10} | ||
bottom={-20} | ||
ref={shadowCameraRef} | ||
attach={"shadow-camera"} | ||
/> | ||
</directionalLight> | ||
<Physics debug key={map}> | ||
<Map | ||
scale={maps[map].scale} | ||
position={maps[map].position} | ||
model={`models/${map}.glb`} | ||
/> | ||
<CharacterController /> | ||
</Physics> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { useAnimations, useGLTF } from "@react-three/drei"; | ||
import { RigidBody } from "@react-three/rapier"; | ||
import { useEffect, useRef } from "react"; | ||
|
||
export const Map = ({ model, ...props }) => { | ||
const { scene, animations } = useGLTF(model); | ||
const group = useRef(); | ||
const { actions } = useAnimations(animations, group); | ||
useEffect(() => { | ||
scene.traverse((child) => { | ||
if (child.isMesh) { | ||
child.castShadow = true; | ||
child.receiveShadow = true; | ||
} | ||
}); | ||
}, [scene]); | ||
|
||
useEffect(() => { | ||
if (actions && animations.length > 0) { | ||
actions[animations[0].name].play(); | ||
} | ||
}, [actions]); | ||
|
||
return ( | ||
<group> | ||
<RigidBody type="fixed" colliders="trimesh"> | ||
<primitive object={scene} {...props} ref={group} /> | ||
</RigidBody> | ||
</group> | ||
); | ||
}; |
Oops, something went wrong.