Giter Site home page Giter Site logo

use-cannon's Introduction

Build Status npm version npm

Imgur

yarn add use-cannon

Experimental React hooks for cannon. Use this in combination with react-three-fiber.

  • Doesn't block the main thread, runs in a web worker
  • Supports instancing out of the box
  • Least amount of friction you'll ever experience with a physics rig ... ๐Ÿ™ˆ

Demos

Ping pong: https://codesandbox.io/s/white-resonance-0mgum

Cube pushing spheres away: https://codesandbox.io/s/r3f-cannon-instanced-physics-devf8

Heap of cubes: https://codesandbox.io/s/r3f-cannon-instanced-physics-g1s88

How it works

  1. Get all the imports that you need.
import { Physics, useBox, ... } from 'use-cannon'
  1. Create a physics world.
<Physics>{/* Physics related objects in here please */}</Physics>
  1. Pick a shape that suits your objects contact surface, it could be a box, plane, sphere, etc. Give it a mass, too.
const [ref, api] = useBox(() => ({ mass: 1 }))
  1. Take your object, it could be a mesh, line, gltf, anything, and tie it to the reference you have just received. Et voilร , it will now be affected by gravity and other objects inside the physics world.
<mesh ref={ref} geometry={...} material={...} />
  1. You can interact with it by using the api, which lets you apply positions and rotations.
useFrame(({ clock }) => api.position.set(Math.sin(clock.getElapsedTime()) * 5, 0, 0))

Simple example

Let's make a cube falling onto a plane. You can play with a sandbox here.

import { Canvas } from 'react-three-fiber'
import { Physics, usePlane, useBox } from 'use-cannon'

function Plane(props) {
  const [ref] = usePlane(() => ({ rotation: [-Math.PI / 2, 0, 0], ...props }))
  return (
    <mesh ref={ref}>
      <planeBufferGeometry attach="geometry" args={[100, 100]} />
    </mesh>
  )
}

function Cube(props) {
  const [ref] = useBox(() => ({ mass: 1, position: [0, 5, 0], ...props }))
  return (
    <mesh ref={ref}>
      <boxBufferGeometry attach="geometry" />
    </mesh>
  )
}

ReactDOM.render(
  <Canvas>
    <Physics>
      <Plane />
      <Cube />
    </Physics>
  </Canvas>,
  document.getElementById('root')
)

Api

Exports

function Physics({
  children,
  step = 1 / 60,
  gravity = [0, -10, 0],
  tolerance = 0.001,
  iterations = 5,
  allowSleep = true,
  broadphase = 'Naive',
  axisIndex = 0,
  defaultContactMaterial = {
    contactEquationStiffness: 1e6,
  },
  // Maximum amount of physics objects inside your scene
  // Lower this value to save memory, increase if 1000 isn't enough
  size = 1000,
}: ProviderProps): JSX.Element

function usePlane(fn: PlaneFn, deps?: any[]): Api
function useBox(fn: BoxFn, deps?: any[]): Api
function useCylinder(fn: CylinderFn, deps?: any[]): Api
function useHeightfield(fn: HeightfieldFn, deps?: any[]): Api
function useParticle(fn: ParticleFn, deps?: any[]): Api
function useSphere(fn: SphereFn, deps?: any[]): Api
function useTrimesh(fn: TrimeshFn, deps?: any[]): Api
function useConvexPolyhedron(fn: ConvexPolyhedronFn, deps?: any[]): Api
function useCompoundBody(fn: CompoundBodyFn, deps?: any[]): Api

function usePointToPointConstraint(
  bodyA: React.MutableRefObject<THREE.Object3D>,
  bodyB: React.MutableRefObject<THREE.Object3D>,
  optns: PointToPointConstraintOpts,
  deps: any[]
): ConstraintApi

function useConeTwistConstraint(
  bodyA: React.MutableRefObject<THREE.Object3D>,
  bodyB: React.MutableRefObject<THREE.Object3D>,
  optns: ConeTwistConstraintOpts,
  deps: any[]
): ConstraintApi

function useDistanceConstraint(
  bodyA: React.MutableRefObject<THREE.Object3D>,
  bodyB: React.MutableRefObject<THREE.Object3D>,
  optns: DistanceConstraintOpts,
  deps: any[]
): ConstraintApi

function useHingeConstraint(
  bodyA: React.MutableRefObject<THREE.Object3D>,
  bodyB: React.MutableRefObject<THREE.Object3D>,
  optns: HingeConstraintOpts,
  deps: any[]
): ConstraintApi

function useLockConstraint(
  bodyA: React.MutableRefObject<THREE.Object3D>,
  bodyB: React.MutableRefObject<THREE.Object3D>,
  optns: LockConstraintOpts,
  deps: any[]
): ConstraintApi

function useSpring(
  bodyA: React.MutableRefObject<THREE.Object3D>,
  bodyB: React.MutableRefObject<THREE.Object3D>,
  optns?: any,
  deps?: any[]
): void

Returned api

type WorkerApi = AtomicProps & {
  position: WorkerVec
  rotation: WorkerVec
  velocity: WorkerVec
  angularVelocity: WorkerVec
  applyForce: (force: number[], worldPoint: number[]) => void
  applyImpulse: (impulse: number[], worldPoint: number[]) => void
  applyLocalForce: (force: number[], localPoint: number[]) => void
  applyLocalImpulse: (impulse: number[], localPoint: number[]) => void
}

type Api = [
  React.MutableRefObject<THREE.Object3D | undefined>,
  WorkerApi & {
    at: (index: number) => WorkerApi
  }
]

type ConstraintApi = [
  React.MutableRefObject<THREE.Object3D>,
  React.MutableRefObject<THREE.Object3D>,
  {
    enable: () => void
    disable: () => void
  }
]

Props

type ProviderProps = {
  children: React.ReactNode
  gravity?: number[]
  tolerance?: number
  step?: number
  iterations?: number
  allowSleep?: boolean
  broadphase?: 'Naive' | 'SAP'
  axisIndex?: number
  defaultContactMaterial?: {
    friction?: number
    restitution?: number
    contactEquationStiffness?: number
    contactEquationRelaxation?: number
    frictionEquationStiffness?: number
    frictionEquationRelaxation?: number
  }
  size?: number
}

type AtomicProps = {
  mass?: number
  material?: { friction?: number; restitution?: number }
  linearDamping?: number
  angularDamping?: number
  allowSleep?: boolean
  sleepSpeedLimit?: number
  sleepTimeLimit?: number
  collisionFilterGroup?: number
  collisionFilterMask?: number
  fixedRotation?: boolean
}

type BodyProps = AtomicProps & {
  ref?: React.MutableRefObject<THREE.Object3D>
  args?: any
  position?: number[]
  rotation?: number[]
  velocity?: number[]
  angularVelocity?: number[]
  scale?: number[]
  type?: 'Dynamic' | 'Static' | 'Kinematic'
  onCollide?: (e: Event) => void
}

type Event = {
  op: string
  type: string
  body: THREE.Object3D
  target: THREE.Object3D
  contact: {
    ni: number[]
    ri: number[]
    rj: number[]
    impactVelocity: number
  }
  collisionFilters: {
    bodyFilterGroup: number
    bodyFilterMask: number
    targetFilterGroup: number
    targetFilterMask: number
  }
}

type PlaneProps = BodyProps & {}
type ParticleProps = BodyProps & {}
type BoxProps = BodyProps & {
  args?: number[] // hafExtents: [x, y, z]
}
type CylinderProps = BodyProps & {
  args?: [number, number, number, number] // radiusTop, radiusBottom, height, numSegments
}
type SphereProps = BodyProps & {
  args?: number // radius
}
type TrimeshProps = BodyProps & {
  args?: [number[][], number[][]] // vertices: [[x, y, z], ...], indices: [[a, b, c], ...]
}
type ConvexPolyhedronProps = BodyProps & {
  args?:
    | THREE.Geometry
    // vertices: [[x, y, z], ...], faces: [[a, b, c], ...]
    | [(THREE.Vector3 | number[])[], (THREE.Face3 | number[])[]]
}
type HeightfieldProps = BodyProps & {
  args?: [
    number[], // data
    {
      minValue?: number
      maxValue?: number
      elementSize?: number
    }
  ]
}
type CompoundBodyProps = BodyProps & {
  shapes: {
    type: ShapeType
    args?: any
    position?: number[]
    rotation?: number[]
  }[]
}

type PlaneFn = (index: number) => PlaneProps
type BoxFn = (index: number) => BoxProps
type CylinderFn = (index: number) => CylinderProps
type HeightfieldFn = (index: number) => HeightfieldProps
type ParticleFn = (index: number) => ParticleProps
type SphereFn = (index: number) => SphereProps
type TrimeshFn = (index: number) => TrimeshProps
type ConvexPolyhedronFn = (index: number) => ConvexPolyhedronProps
type CompoundBodyFn = (index: number) => CompoundBodyProps

FAQ

Broadphases

  • NaiveBroadphase is as simple as it gets. It considers every body to be a potential collider with every other body. This results in the maximum number of narrowphase checks.
  • SAPBroadphase sorts bodies along an axis and then moves down that list finding pairs by looking at body size and position of the next bodies. Control what axis to sort along by setting the axisIndex property.

Types

  • A dynamic body is fully simulated. Can be moved manually by the user, but normally they move according to forces. A dynamic body can collide with all body types. A dynamic body always has finite, non-zero mass.
  • A static body does not move during simulation and behaves as if it has infinite mass. Static bodies can be moved manually by setting the position of the body. The velocity of a static body is always zero. Static bodies do not collide with other static or kinematic bodies.
  • A kinematic body moves under simulation according to its velocity. They do not respond to forces. They can be moved manually, but normally a kinematic body is moved by setting its velocity. A kinematic body behaves as if it has infinite mass. Kinematic bodies do not collide with other static or kinematic bodies.

use-cannon's People

Contributors

codynova avatar dependabot[bot] avatar developit avatar drcmda avatar kbooz avatar nevernotsean avatar stockhuman avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.