I’m building a 3D application using Three.js, React Three Fiber, and React Rapier. My goal is to control the avatar using physics. I’ve tried various methods, but I can’t seem to get it working as expected.
Here’s what I’ve tried so far:
RigidBody for the avatar.
Applying forces to move the avatar forward, backward, and rotate.
Adjusting gravity and friction to simulate more realistic movement.
Despite this, the avatar doesn’t move as expected, and the physics either don’t apply correctly or don’t affect the movement at all. Ideally, I want the avatar to be fully controlled by physics, reacting to inputs like walking and jumping while maintaining realistic interactions with the environment.
What I expect:
The avatar should be able to walk, run, and jump using physics-based controls.
The movement should feel realistic with proper gravity, inertia, and friction applied.
Relevant Code Snippet:
// Apply movement, rotation, and jumping using Rapier's kinematicPosition
useFrame((state, delta) => {
const rb = rigidBodyRef.current;
if (rb) {
// Update the animation mixer
mixer.update(delta);
let rotationChanged = false;
// Handle rotation based on input.left and input.right
if (input.left || input.right) {
const rotationDirection = input.left ? 1 : -1; // Left: positive rotation, Right: negative rotation
const rotationAmount = rotationSpeed * delta * rotationDirection;
// Update the avatar's rotation state
avatarRotation.current.y += rotationAmount;
rotationChanged = true;
}
// Calculate forward movement based on current rotation
const forward = new THREE.Vector3(0, 0, 1).applyEuler(avatarRotation.current).normalize();
// Determine movement direction
let moveDirection = new THREE.Vector3();
if (input.forward) moveDirection.add(forward);
if (input.backward) moveDirection.sub(forward);
if (moveDirection.length() > 0) {
moveDirection.normalize().multiplyScalar(moveSpeed * delta);
avatarPosition.current.add(moveDirection);
}
// Apply rotation if it has changed
if (rotationChanged) {
const quaternion = new THREE.Quaternion().setFromEuler(avatarRotation.current);
rb.setNextKinematicRotation(quaternion, true);
}
// Handle Jump Initiation
if (input.jump && !prevJump.current && !isJumping.current) {
isJumping.current = true;
jumpStartTime.current = state.clock.elapsedTime;
// Play jump animation
actions['jump']?.reset().fadeIn(0.2).play();
}
// Update the previous jump state
prevJump.current = input.jump;
// Handle Jump Animation and Y-Position
if (isJumping.current) {
const elapsed = state.clock.elapsedTime - jumpStartTime.current;
if (elapsed < jumpDuration.current) {
const t = elapsed / jumpDuration.current; // Progress from 0 to 1
const jumpY = Math.sin(t * Math.PI) * jumpHeight; // Sine curve for smooth jump
avatarPosition.current.y = groundY + jumpY;
} else {
// Jump has completed
avatarPosition.current.y = groundY;
isJumping.current = false;
}
} else {
// Ensure the avatar stays on the ground
avatarPosition.current.y = groundY;
}
// Apply the updated position to the RigidBody
rb.setNextKinematicTranslation(avatarPosition.current, true);
}
// Ensure the model's Y-position remains zero to prevent conflicting Y movements
if (avatarRef.current) {
avatarRef.current.position.y = 0;
}
});
I’ve looked into the documentation, but I’m still stuck. Does anyone have suggestions for how to properly control the avatar using physics in this setup?
Tools I’m using:
Three.js
React Three Fiber
React Rapier
Any help would be greatly appreciated!