usePhysics

usePhysics provides an imperative API for controlling a Rapier rigid body. Use it inside children of a physics-enabled Actor to apply impulses, set velocities, teleport, and more.

tsx
import { usePhysics } from "@carverjs/core/hooks";

Prerequisites #

  1. Install @react-three/rapier:

    bash
    pnpm add @react-three/rapier
  2. Enable physics on the World:

    tsx
    <World physics={{ gravity: [0, -9.81, 0] }}>
  3. Add a physics prop to the Actor:

    tsx
    <Actor type="primitive" shape="box" physics={{ bodyType: "dynamic" }}>
      <PlayerController />
    </Actor>
  4. Call usePhysics() inside <PlayerController />.


Quick Start #

tsx
import { usePhysics } from "@carverjs/core/hooks";
import { useInput, useGameLoop } from "@carverjs/core/hooks";

function PlayerController() {
  const physics = usePhysics();
  const { isAction } = useInput({
    actions: { jump: ["Space"], left: ["KeyA"], right: ["KeyD"] },
  });

  useGameLoop(() => {
    if (!physics) return;

    if (isAction("left")) physics.setLinearVelocity([-5, 0, 0]);
    if (isAction("right")) physics.setLinearVelocity([5, 0, 0]);
    if (isAction("jump")) physics.applyImpulse([0, 10, 0]);
  });

  return null;
}

Return Value #

Returns UsePhysicsReturn | null. Returns null when no physics context exists or the component is not inside a physics-enabled Actor.

MethodTypeDescription
applyImpulse(impulse)([number, number, number]) => voidApply an instantaneous force
applyForce(force)([number, number, number]) => voidApply a continuous force (resets each physics step)
setLinearVelocity(vel)([number, number, number]) => voidSet linear velocity directly
getLinearVelocity()() => [number, number, number]Get current linear velocity
setAngularVelocity(vel)([number, number, number]) => voidSet angular velocity
setTranslation(pos)([number, number, number]) => voidTeleport the body to a position
getTranslation()() => [number, number, number]Get current position
setRotation(quat)([number, number, number, number]) => voidSet rotation as quaternion [x, y, z, w]
setEnabled(enabled)(boolean) => voidEnable or disable the rigid body

Full Example #

tsx
import { Game, World, Actor } from "@carverjs/core/components";
import { usePhysics, useInput, useGameLoop } from "@carverjs/core/hooks";

function PlayerController() {
  const physics = usePhysics();
  const { isActionJustPressed } = useInput({
    actions: { jump: ["Space"] },
  });

  useGameLoop(() => {
    if (!physics) return;
    if (isActionJustPressed("jump")) {
      physics.applyImpulse([0, 8, 0]);
    }
  });

  return null;
}

function App() {
  return (
    <Game>
      <World physics={{ gravity: [0, -9.81, 0] }}>
        {/* Dynamic player */}
        <Actor type="primitive" shape="box" color="blue" position={[0, 5, 0]}
          physics={{ bodyType: "dynamic", mass: 1 }}
        >
          <PlayerController />
        </Actor>

        {/* Static ground */}
        <Actor type="primitive" shape="plane" color="#eee" size={20}
          rotation={[-Math.PI / 2, 0, 0]}
          physics={{ bodyType: "fixed" }}
        />
      </World>
    </Game>
  );
}

Type Definitions #

See Types for UsePhysicsReturn, ActorPhysicsProps, RigidBodyType, PhysicsColliderType, and WorldPhysicsConfig.