From 770e7fad0df9a737728fd71c4755e8b309c34294 Mon Sep 17 00:00:00 2001 From: Dries Croons Date: Mon, 22 Jan 2024 01:00:08 +0100 Subject: [PATCH] test: one way platform issue --- demo/src/App.tsx | 7 +- .../one-way-platform/OneWayPlatform.tsx | 101 ++++++++++++++++++ .../src/components/Physics.tsx | 49 ++++++++- 3 files changed, 152 insertions(+), 5 deletions(-) create mode 100644 demo/src/examples/one-way-platform/OneWayPlatform.tsx diff --git a/demo/src/App.tsx b/demo/src/App.tsx index e4699111..4169db8f 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -38,7 +38,8 @@ import { PerformanceExample } from "./examples/performance/PeformanceExample"; import { DynamicTypeChangeExample } from "./examples/dynamic-type-change/DynamicTypeChangeExample"; import { StutteringExample } from "./examples/stuttering/StutteringExample"; import { ImmutablePropsExample } from "./examples/immutable-props/ImmutablePropsExample"; -import { SnapshotExample } from './examples/snapshot/SnapshotExample'; +import { SnapshotExample } from "./examples/snapshot/SnapshotExample"; +import { OneWayPlatform } from "./examples/one-way-platform/OneWayPlatform"; const demoContext = createContext<{ setDebug?(f: boolean): void; @@ -90,7 +91,7 @@ const Floor = () => { }; const routes: Record = { - "": , + "": , joints: , components: , cradle: , @@ -200,7 +201,7 @@ export const App = () => { > {Object.keys(routes).map((key) => ( - {key.replace(/-/g, " ") || "Plinko"} + {key.replace(/-/g, " ") || "One Way Platform"} ))} diff --git a/demo/src/examples/one-way-platform/OneWayPlatform.tsx b/demo/src/examples/one-way-platform/OneWayPlatform.tsx new file mode 100644 index 00000000..171e549b --- /dev/null +++ b/demo/src/examples/one-way-platform/OneWayPlatform.tsx @@ -0,0 +1,101 @@ +import { Sphere } from "@react-three/drei"; +import { useThree } from "@react-three/fiber"; +import { + CuboidCollider, + RapierCollider, + RapierRigidBody, + RigidBody, + useRapier +} from "@react-three/rapier"; +import { useCallback, useEffect, useRef } from "react"; +import { Vector3 } from "three"; +import { Demo } from "../../App"; + +export const OneWayPlatform: Demo = () => { + const ref = useRef(null); + const collider = useRef(null); + + const ball = useRef(null); + const { camera } = useThree(); + + useEffect(() => { + camera.position.set(0, 10, 20); + camera.lookAt(0, 0, 0); + camera.updateProjectionMatrix(); + + window.addEventListener("click", () => { + ball.current?.applyImpulse(new Vector3(0, 50, 0), true); + }); + }, []); + + const { filterContactPairHooks, world } = useRapier(); + + const hook = useCallback( + (c1: number, c2: number, b1: number, b2: number) => { + try { + const collider1 = world.getCollider(c1); + const collider2 = world.getCollider(c2); + + const body1 = world.getRigidBody(b1); + const body2 = world.getRigidBody(b2); + + if ( + (body1.userData as any)?.type && + (body1.userData as any).type === "platform" && + (body2.userData as any)?.type && + (body2.userData as any)?.type === "ball" + ) { + // Once we get try to get access to the ball and platform, the "hook" that we pass to filterContactPairHooks crashes + + // why does this crash here? what's wrong with the below setup? + const platformPosition = body1.translation(); + const ballVelocity = body2.linvel(); + const ballPosition = body2.translation(); + + // also doesn't work + // const platformPosition = ref.current!.translation(); + // const ballVelocity = ball.current!.linvel(); + // const ballPosition = ref.current!.translation(); + + // Allow collision if the ball is moving downwards and above the platform + if (ballVelocity.y < 0 && ballPosition.y > platformPosition.y) { + return 1; // Process the collision + } + } + + return 0; // Ignore the collision + } catch (error) { + console.log(error); + return null; + } + }, + [world] + ); + + useEffect(() => { + collider.current?.setActiveHooks(1); + filterContactPairHooks.push(hook); + }, []); + + return ( + + + + + + + + + + + + + + + ); +}; diff --git a/packages/react-three-rapier/src/components/Physics.tsx b/packages/react-three-rapier/src/components/Physics.tsx index 3efae2f1..c394e7cf 100644 --- a/packages/react-three-rapier/src/components/Physics.tsx +++ b/packages/react-three-rapier/src/components/Physics.tsx @@ -3,8 +3,10 @@ import { Collider, ColliderHandle, EventQueue, + PhysicsHooks, RigidBody, RigidBodyHandle, + SolverFlags, World } from "@dimforge/rapier3d-compat"; import { useThree } from "@react-three/fiber"; @@ -187,6 +189,19 @@ export interface RapierContext { * Is debug mode enabled */ isDebug: boolean; + + filterContactPairHooks: (( + collider1: ColliderHandle, + collider2: ColliderHandle, + body1: RigidBodyHandle, + body2: RigidBodyHandle + ) => SolverFlags | null)[]; + filterIntersectionPairHooks: (( + collider1: ColliderHandle, + collider2: ColliderHandle, + body1: RigidBodyHandle, + body2: RigidBodyHandle + ) => boolean)[]; } export const rapierContext = createContext( @@ -394,6 +409,34 @@ export const Physics: FC = (props) => { const rigidBodyEvents = useConst(() => new Map()); const colliderEvents = useConst(() => new Map()); const eventQueue = useConst(() => new EventQueue(false)); + + const filterContactPairHooks = useConst< + (( + collider1: ColliderHandle, + collider2: ColliderHandle, + body1: RigidBodyHandle, + body2: RigidBodyHandle + ) => SolverFlags | null)[] + >(() => []); + const filterIntersectionPairHooks = useConst< + (( + collider1: ColliderHandle, + collider2: ColliderHandle, + body1: RigidBodyHandle, + body2: RigidBodyHandle + ) => boolean)[] + >(() => []); + + const hooks = useConst(() => ({ + filterContactPair: (...args) => { + const hook = filterContactPairHooks.find((hook) => hook(...args)); + return hook ? hook(...args) : null; + }, + filterIntersectionPair: (...args) => { + const hook = filterIntersectionPairHooks.find((hook) => hook(...args)); + return hook ? hook(...args) : false; + } + })); const beforeStepCallbacks = useConst(() => new Set()); const afterStepCallbacks = useConst(() => new Set()); @@ -504,7 +547,7 @@ export const Physics: FC = (props) => { }); world.timestep = delta; - world.step(eventQueue); + world.step(eventQueue, hooks); // Trigger afterStep callbacks afterStepCallbacks.forEach((callback) => { @@ -763,7 +806,9 @@ export const Physics: FC = (props) => { afterStepCallbacks, isPaused: paused, isDebug: debug, - step + step, + filterContactPairHooks, + filterIntersectionPairHooks }), [paused, step, debug, colliders, gravity] );