1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
import { PerspectiveCamera, PointerLockControls } from "@react-three/drei";
import { useFrame, useThree } from "@react-three/fiber";
import { useContext, useEffect, useRef } from "react";
import { AppContext } from "../App";
import { CapsuleCollider, RigidBody, useRapier, vec3 } from "@react-three/rapier";
import { Vector3 } from "three";
import { useBeforePhysicsStep } from "@react-three/rapier";
import { Raycaster } from "three";
const _movespeed = 3.0;
export default function Player() {
const controlsRef = useRef();
const { keys, setMessages, apiToken } = useContext(AppContext);
const rapier = useRapier();
const controller = useRef();
const collider = useRef();
const rigidbody = useRef();
const camera = useRef();
const raycaster = useRef(new Raycaster());
const { scene, pointer } = useThree();
const refState = useRef({
grounded: false,
velocity: vec3(),
});
const onClick = (_) => {
raycaster.current.setFromCamera(pointer, camera.current);
const intersect = raycaster.current.intersectObjects(scene.children).at(0);
if (intersect && intersect.object.name === 'ground' && intersect.distance < 10 && controlsRef.current.isLocked) {
const message = prompt();
if (message) {
let data = new FormData();
data.append("position", JSON.stringify(intersect.point.toArray()));
data.append("message", message);
data.append("token", apiToken.current);
fetch('/api/new_message', {
method: "POST",
body: data,
}).then(() => {
fetch('/api/message').then((res) => res.json()).then((data) => {
console.log(data);
setMessages(data);
});
});
}
controlsRef.current.lock();
}
};
useEffect(() => {
window.addEventListener("click", onClick);
return () => window.removeEventListener("click", onClick);
}, []);
useEffect(() => {
const c = rapier.world.createCharacterController(0.1);
c.setApplyImpulsesToDynamicBodies(true);
c.setCharacterMass(0.2);
controller.current = c;
}, []);
useFrame((_, delta) => {
const fov_axis = +(keys.current.includes('Minus')) - +(keys.current.includes('Equal'));
if (fov_axis != 0) {
camera.current.fov += 45 * fov_axis * delta;
camera.current.updateProjectionMatrix();
}
});
useBeforePhysicsStep((world) => {
if (controller.current && rigidbody.current && collider.current) {
const move_axis_x = +(keys.current.includes('KeyD')) - +(keys.current.includes('KeyA'));
const move_axis_z = +(keys.current.includes('KeyW')) - +(keys.current.includes('KeyS'));
const { velocity } = refState.current;
const position = vec3(rigidbody.current.translation());
const movement = vec3();
const forward = new Vector3();
camera.current.getWorldDirection(forward);
const left = new Vector3().crossVectors(forward, camera.current.up);
movement.x += move_axis_z * world.timestep * _movespeed * forward.x;
movement.z += move_axis_z * world.timestep * _movespeed * forward.z;
movement.x += move_axis_x * world.timestep * _movespeed * left.x;
movement.z += move_axis_x * world.timestep * _movespeed * left.z;
if (refState.current.grounded) {
velocity.y = 0;
} else {
velocity.y -= 9.81 * world.timestep * world.timestep;
}
movement.add(velocity);
controller.current.computeColliderMovement(collider.current, movement);
refState.current.grounded = controller.current.computedGrounded();
let correctedMovement = controller.current.computedMovement();
position.add(vec3(correctedMovement));
rigidbody.current.setNextKinematicTranslation(position);
}
});
return (
<RigidBody type="kinematicPosition" colliders={false} ref={rigidbody} position={[0, 2, 0]}>
<PerspectiveCamera makeDefault position={[0, .9, 0]} ref={camera} fov={80} />
<PointerLockControls ref={controlsRef} />
<CapsuleCollider ref={collider} args={[1, 0.5]} />
</RigidBody>
);
}
|