Skip to content

Commit

Permalink
useSphere args must be an array (#291)
Browse files Browse the repository at this point in the history
* useSphere args must be an array

* Make failure mode more friendly
  • Loading branch information
bjornstar authored Oct 5, 2021
1 parent f47b416 commit 8ed8e6b
Show file tree
Hide file tree
Showing 13 changed files with 37 additions and 26 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ type Quad = [x: number, y: number, z: number, w: number]
type VectorProps = Record<VectorName, Triplet>
type BodyProps<T = unknown> = Partial<AtomicProps> &
type BodyProps<T extends any[] = unknown[]> = Partial<AtomicProps> &
Partial<VectorProps> & {
args?: T
onCollide?: (e: CollideEvent) => void
Expand Down Expand Up @@ -460,6 +460,7 @@ type RayhitEvent = {
}
type CylinderArgs = [radiusTop?: number, radiusBottom?: number, height?: number, numSegments?: number]
type SphereArgs = [radius: number]
type TrimeshArgs = [vertices: ArrayLike<number>, indices: ArrayLike<number>]
type HeightfieldArgs = [
data: number[][],
Expand All @@ -477,7 +478,7 @@ interface PlaneProps extends BodyProps {}
interface BoxProps extends BodyProps<Triplet> {} // extents: [x, y, z]
interface CylinderProps extends BodyProps<CylinderArgs> {}
interface ParticleProps extends BodyProps {}
interface SphereProps extends BodyProps<number> {} // radius
interface SphereProps extends BodyProps<SphereArgs> {}
interface TrimeshProps extends BodyPropsArgsRequired<TrimeshArgs> {}
interface HeightfieldProps extends BodyPropsArgsRequired<HeightfieldArgs> {}
interface ConvexPolyhedronProps extends BodyProps<ConvexPolyhedronArgs> {}
Expand Down
8 changes: 4 additions & 4 deletions examples/src/demos/Chain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ const ChainLink = ({ children }: PropsWithChildren<{}>) => {
)
}

const Handle = ({ children }: PropsWithChildren<{}>) => {
const [ref, { position }] = useSphere(() => ({ type: 'Static', args: 0.5, position: [0, 0, 0] }))
const Handle = ({ children, radius }: PropsWithChildren<{ radius: number }>) => {
const [ref, { position }] = useSphere(() => ({ type: 'Static', args: [radius], position: [0, 0, 0] }))
useFrame(({ mouse: { x, y }, viewport: { height, width } }) =>
position.set((x * width) / 2, (y * height) / 2, 0),
)
return (
<group>
<mesh ref={ref}>
<sphereBufferGeometry args={[0.5, 64, 64]} />
<sphereBufferGeometry args={[radius, 64, 64]} />
<meshStandardMaterial />
</mesh>
<parent.Provider value={ref}>{children}</parent.Provider>
Expand All @@ -59,7 +59,7 @@ const ChainScene = () => {
<pointLight position={[-10, -10, -10]} />
<spotLight position={[10, 10, 10]} angle={0.3} penumbra={1} intensity={1} castShadow />
<Physics gravity={[0, -40, 0]} allowSleep={false}>
<Handle>
<Handle radius={0.5}>
<ChainLink>
<ChainLink>
<ChainLink>
Expand Down
2 changes: 1 addition & 1 deletion examples/src/demos/Constraints.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const Box = forwardRef<Object3D, BoxProps>((props, ref) => {
})

const Ball = forwardRef<Object3D, SphereProps>((props, ref) => {
const [, { position }] = useSphere(() => ({ type: 'Kinematic', args: 0.5, ...props }), ref)
const [, { position }] = useSphere(() => ({ type: 'Kinematic', args: [0.5], ...props }), ref)
useFrame(({ mouse: { x, y }, viewport: { height, width } }) =>
position.set((x * width) / 2, (y * height) / 2, 0),
)
Expand Down
6 changes: 3 additions & 3 deletions examples/src/demos/CubeHeap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ type InstancedGeometryProps = {
size: number
}

const Spheres = ({ colors, number, size: args }: InstancedGeometryProps) => {
const Spheres = ({ colors, number, size }: InstancedGeometryProps) => {
const [ref, { at }] = useSphere(() => ({
args,
args: [size],
mass: 1,
position: [Math.random() - 0.5, Math.random() * 2, Math.random() - 0.5],
}))
useFrame(() => at(Math.floor(Math.random() * number)).position.set(0, Math.random() * 2, 0))
return (
<instancedMesh receiveShadow castShadow ref={ref} args={[undefined, undefined, number]}>
<sphereBufferGeometry args={[args, 48]}>
<sphereBufferGeometry args={[size, 48]}>
<instancedBufferAttribute attachObject={['attributes', 'color']} args={[colors, 3]} />
</sphereBufferGeometry>
<meshLambertMaterial vertexColors />
Expand Down
2 changes: 1 addition & 1 deletion examples/src/demos/Heightfield.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,13 @@ type SpheresProps = {
function Spheres({ rows, columns, spread }: SpheresProps) {
const number = rows * columns
const [ref] = useSphere((index) => ({
args: [0.2],
mass: 1,
position: [
((index % columns) - (columns - 1) / 2) * spread,
2.0,
(Math.floor(index / columns) - (rows - 1) / 2) * spread,
],
args: 0.2,
}))
const colors = useMemo(() => {
const array = new Float32Array(number * 3)
Expand Down
2 changes: 1 addition & 1 deletion examples/src/demos/KinematicCube.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ function Box() {

function InstancedSpheres({ number = 100 }) {
const [ref] = useSphere((index) => ({
args: [1],
mass: 1,
position: [Math.random() - 0.5, Math.random() - 0.5, index * 2],
args: 1,
}))
const colors = useMemo(() => {
const array = new Float32Array(number * 3)
Expand Down
4 changes: 2 additions & 2 deletions examples/src/demos/MondayMorning/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const BodyPart = ({ config = {}, children, render, name, ...props }: BodyPartPro
function Ragdoll(props: Pick<MeshProps, 'position'>) {
const mouth = useRef<Object3D>(null!)
const eyes = useRef<Object3D>(null!)
const [ref, api] = useSphere(() => ({ type: 'Static', args: 0.5, position: [0, 0, 10000] }), cursor)
const [ref, api] = useSphere(() => ({ type: 'Static', args: [0.5], position: [0, 0, 10000] }), cursor)
useFrame((e) => {
eyes.current.position.y = Math.sin(e.clock.getElapsedTime() * 1) * 0.06
mouth.current.scale.y = (1 + Math.sin(e.clock.getElapsedTime())) * 1.5
Expand Down Expand Up @@ -256,7 +256,7 @@ function Table() {

const Lamp = () => {
const light = useRef()
const [fixed] = useSphere(() => ({ type: 'Static', args: 1, position: [0, 16, 0] }))
const [fixed] = useSphere(() => ({ type: 'Static', args: [1], position: [0, 16, 0] }))
const [lamp] = useBox(() => ({
mass: 1,
args: [1, 0, 5],
Expand Down
2 changes: 1 addition & 1 deletion examples/src/demos/Pingpong/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ function Paddle() {

function Ball() {
const map = useLoader(TextureLoader, earthImg)
const [ref] = useSphere(() => ({ mass: 1, args: 0.5, position: [0, 5, 0] }))
const [ref] = useSphere(() => ({ mass: 1, args: [0.5], position: [0, 5, 0] }))
return (
<mesh castShadow ref={ref}>
<sphereBufferGeometry args={[0.5, 64, 64]} />
Expand Down
2 changes: 1 addition & 1 deletion examples/src/demos/Raycast/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type SphereProps = {
}

function Sphere({ radius, position }: SphereProps) {
const [ref, api] = useSphere(() => ({ type: 'Static', args: radius, position }))
const [ref, api] = useSphere(() => ({ type: 'Static', args: [radius], position }))
useFrame(({ clock: { elapsedTime } }) => {
api.position.set(position[0], position[1], Math.sin(elapsedTime / 3) * 2)
})
Expand Down
2 changes: 1 addition & 1 deletion examples/src/demos/SphereDebug.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { Debug, Physics, useSphere, usePlane } from '@react-three/cannon'

function ScalableBall() {
const [ref, api] = useSphere(() => ({
args: [1],
mass: 1,
args: 1,
position: [0, 5, 0],
}))
const [sleeping, setSleeping] = useState(false)
Expand Down
2 changes: 1 addition & 1 deletion examples/src/demos/Triggers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ function BoxTrigger({ args, onCollide, position }: BoxProps) {

function Ball() {
const [ref] = useSphere(() => ({
args: [1],
mass: 1,
position: [0, 10, 0],
args: 1,
}))
return (
<mesh castShadow receiveShadow ref={ref}>
Expand Down
6 changes: 3 additions & 3 deletions examples/src/demos/Trimesh.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ function Controls() {
)
}

const WeirdCheerio = ({ args = 0.1, position }: Pick<SphereProps, 'args' | 'position'>) => {
const WeirdCheerio = ({ args = [0.1], position }: Pick<SphereProps, 'args' | 'position'>) => {
const [ref] = useSphere(() => ({ args, mass: 1, position }))

const [radius] = args
return (
<TorusKnot ref={ref} args={[args, args / 2]}>
<TorusKnot ref={ref} args={[radius, radius / 2]}>
<meshNormalMaterial />
</TorusKnot>
)
Expand Down
20 changes: 15 additions & 5 deletions src/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type VectorTypes = Vector3 | Triplet

export type Quad = [x: number, y: number, z: number, w: number]

export type BodyProps<T = unknown> = Partial<AtomicProps> &
export type BodyProps<T extends any[] = unknown[]> = Partial<AtomicProps> &
Partial<VectorProps> & {
args?: T
onCollide?: (e: CollideEvent) => void
Expand All @@ -54,7 +54,7 @@ export type BodyProps<T = unknown> = Partial<AtomicProps> &
type?: 'Dynamic' | 'Static' | 'Kinematic'
}

export type BodyPropsArgsRequired<T = unknown> = BodyProps<T> & {
export type BodyPropsArgsRequired<T extends any[] = unknown[]> = BodyProps<T> & {
args: T
}

Expand All @@ -70,6 +70,7 @@ export type ShapeType =
export type BodyShapeType = ShapeType | 'Compound'

export type CylinderArgs = [radiusTop?: number, radiusBottom?: number, height?: number, numSegments?: number]
export type SphereArgs = [radius: number]
export type TrimeshArgs = [vertices: ArrayLike<number>, indices: ArrayLike<number>]
export type HeightfieldArgs = [
data: number[][],
Expand All @@ -87,7 +88,7 @@ export type PlaneProps = BodyProps
export type BoxProps = BodyProps<Triplet>
export type CylinderProps = BodyProps<CylinderArgs>
export type ParticleProps = BodyProps
export type SphereProps = BodyProps<number>
export type SphereProps = BodyProps<SphereArgs>
export type TrimeshProps = BodyPropsArgsRequired<TrimeshArgs>
export type HeightfieldProps = BodyPropsArgsRequired<HeightfieldArgs>
export type ConvexPolyhedronProps = BodyProps<ConvexPolyhedronArgs>
Expand Down Expand Up @@ -251,7 +252,7 @@ function setupCollision(
type GetByIndex<T extends BodyProps> = (index: number) => T
type ArgFn<T> = (args: T) => unknown[]

function useBody<B extends BodyProps<unknown>>(
function useBody<B extends BodyProps<unknown[]>>(
type: BodyShapeType,
fn: GetByIndex<B>,
argsFn: ArgFn<B['args']>,
Expand Down Expand Up @@ -487,7 +488,16 @@ export function useParticle(
return useBody('Particle', fn, () => [], fwdRef, deps)
}
export function useSphere(fn: GetByIndex<SphereProps>, fwdRef: Ref<Object3D> = null, deps?: DependencyList) {
return useBody('Sphere', fn, (radius = 1): [number] => [radius], fwdRef, deps)
return useBody(
'Sphere',
fn,
(args: SphereArgs = [1]): SphereArgs => {
if (!Array.isArray(args)) throw new Error('useSphere args must be an array')
return [args[0]]
},
fwdRef,
deps,
)
}
export function useTrimesh(
fn: GetByIndex<TrimeshProps>,
Expand Down

1 comment on commit 8ed8e6b

@vercel
Copy link

@vercel vercel bot commented on 8ed8e6b Oct 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.