Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

one-way-platform issue #603

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions demo/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
useState
} from "react";
import { NavLink, NavLinkProps, Route, Routes } from "react-router-dom";
import { ActiveCollisionTypesExample } from "./examples/active-collision-types/ActiveCollisionTypesExample";
import { AllCollidersExample } from "./examples/all-colliders/AllCollidersExample";
import { AllShapesExample } from "./examples/all-shapes/AllShapesExample";
import { ApiUsage } from "./examples/api-usage/ApiUsageExample";
Expand All @@ -33,6 +34,7 @@ import { Kinematics } from "./examples/kinematics/KinematicsExample";
import { LockedTransformsExample } from "./examples/locked-transforms/LockedTransformsExample";
import { ManualStepExample } from "./examples/manual-step/ManualStepExamples";
import { MeshColliderTest } from "./examples/mesh-collider-test/MeshColliderExample";
import { OneWayPlatform } from "./examples/one-way-platform/OneWayPlatform";
import { PerformanceExample } from "./examples/performance/PeformanceExample";
import Shapes from "./examples/plinko/ShapesExample";
import { RopeJointExample } from "./examples/rope-joint/RopeJointExample";
Expand All @@ -41,7 +43,6 @@ import { SnapshotExample } from "./examples/snapshot/SnapshotExample";
import { SpringExample } from "./examples/spring/SpringExample";
import { StutteringExample } from "./examples/stuttering/StutteringExample";
import { Transforms } from "./examples/transforms/TransformsExample";
import { ActiveCollisionTypesExample } from "./examples/active-collision-types/ActiveCollisionTypesExample";

const demoContext = createContext<{
setDebug?(f: boolean): void;
Expand Down Expand Up @@ -93,7 +94,8 @@ const Floor = () => {
};

const routes: Record<string, ReactNode> = {
"": <Shapes />,
"": <OneWayPlatform />,
shapes: Shapes,
joints: <Joints />,
components: <ComponentsExample />,
cradle: <CradleExample />,
Expand Down Expand Up @@ -206,7 +208,7 @@ export const App = () => {
>
{Object.keys(routes).map((key) => (
<Link key={key} to={key} end>
{key.replace(/-/g, " ") || "Plinko"}
{key.replace(/-/g, " ") || "One Way Platform"}
</Link>
))}

Expand Down
101 changes: 101 additions & 0 deletions demo/src/examples/one-way-platform/OneWayPlatform.tsx
Original file line number Diff line number Diff line change
@@ -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<RapierRigidBody>(null);
const collider = useRef<RapierCollider>(null);

const ball = useRef<RapierRigidBody>(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 (
<group>
<RigidBody
ref={ball}
colliders="ball"
position={[0, -5, 0]}
userData={{ type: "ball" }}
>
<Sphere castShadow receiveShadow>
<meshPhysicalMaterial color="red" />
</Sphere>
</RigidBody>
<mesh>
<boxGeometry args={[10, 0.1, 10]} />
<meshStandardMaterial color={"grey"} opacity={0.5} transparent={true} />
</mesh>
<RigidBody type="fixed" userData={{ type: "platform" }} ref={ref}>
<CuboidCollider args={[10, 0.1, 10]} ref={collider} />
</RigidBody>
</group>
);
};
49 changes: 47 additions & 2 deletions packages/react-three-rapier/src/components/Physics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import {
Collider,
ColliderHandle,
EventQueue,
PhysicsHooks,
RigidBody,
RigidBodyHandle,
SolverFlags,
World
} from "@dimforge/rapier3d-compat";
import { useThree } from "@react-three/fiber";
Expand Down Expand Up @@ -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<RapierContext | undefined>(
Expand Down Expand Up @@ -428,6 +443,34 @@ export const Physics: FC<PhysicsProps> = (props) => {
const rigidBodyEvents = useConst<EventMap>(() => new Map());
const colliderEvents = useConst<EventMap>(() => 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<PhysicsHooks>(() => ({
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<WorldStepCallbackSet>(() => new Set());
const afterStepCallbacks = useConst<WorldStepCallbackSet>(() => new Set());

Expand Down Expand Up @@ -549,7 +592,7 @@ export const Physics: FC<PhysicsProps> = (props) => {
});

world.timestep = delta;
world.step(eventQueue);
world.step(eventQueue, hooks);

// Trigger afterStep callbacks
afterStepCallbacks.forEach((callback) => {
Expand Down Expand Up @@ -808,7 +851,9 @@ export const Physics: FC<PhysicsProps> = (props) => {
afterStepCallbacks,
isPaused: paused,
isDebug: debug,
step
step,
filterContactPairHooks,
filterIntersectionPairHooks
}),
[paused, step, debug, colliders, gravity]
);
Expand Down