use-cannon icon indicating copy to clipboard operation
use-cannon copied to clipboard

PreStep support

Open Splact opened this issue 5 years ago • 3 comments
trafficstars

Is there a way to define a preStep function on a body?

const [ref, api] = useBox(
  () => ({
    args: [size[0] / 2, size[1] / 2, size[2] / 2],
    preStep: () => {
      console.log("prestep");
    },
    ...props,
  })
);

I tried passing a callback to useBox (as above) but this leads to an error on the worker.

Failed to execute 'postMessage' on 'Worker': function preStep() {
  console.log("preStep");
} could not be cloned.

My goal is to recreate gravity towards a point in space, so I'm trying to apply a constant force through that point in the preStep function. Don't know if I'm following the right approach, I'm open to suggestions.

A super nice solution to this would be having a component that defines an attractor point. An example below:

import { Physics, Attractor } from "use-cannon";

// ...

return (
  <Physics gravity={[0, 0, 0]}>
    {/* ... objects with useCannon hooks ... */}

    <Attractor position={[0, 50, -20]} mass={4} />
    <Attractor position={[0, -20, 60]} mass={6} />
  </Physics>
);

Splact avatar Apr 17 '20 10:04 Splact

Hey @Splact, sorry for the delayed response. The Cannon Body preStep and postStep methods are deprecated, and it's suggested that you use World events instead. However, we don't currently expose a way to add events to the world - and even if we did, we may still need to un-deprecate the Body preStep and postStep events to make the API a little more sane. This will need to be considered.

@drcmda Do you have any thoughts on this?

codynova avatar Apr 22 '20 17:04 codynova

We should also add a way to update world props like gravity, tolerance, allowSleep, etc. through the Provider context. I will try to find some time for this soon.

codynova avatar Apr 25 '20 15:04 codynova

The solution I implemented with the current api is to apply a constant force in the direction of the gravity center on each frame. This is not theoretically correct, since the forces sum up on each frame, but the end result is acceptable in my case.

useFrame(() => {
  // Calculate constant force to the gravity center
  // 1. get direction vector
  force.current
    .subVectors(ref.current.position, gravityCenterVector)
    .normalize();
  // 2. get the distance to the gravity center
  const distance = ref.current.position.distanceTo(
    gravityCenterVector
  );
  // 3. get force's magnitude following a quad curve on the distance
  const forceMagnitude =
    quadOut(Math.max(1 - distance / GRAVITY_MAX_DISTANCE, 0)) *
    GRAVITY_MAX_FORCE;
  force.current.multiplyScalar(-forceMagnitude);

  // ... update the force if needed, in my case here I've a force variation logic due to pointer movement

  // Apply force
  api.applyForce(force.current.toArray(), [0, 0, 0]);
}

Here I obtain the force's magnitude in relation to the distance to the gravity center. The GRAVITY_MAX_DISTANCE is the distance in which the gravity force applied to the object is 0.

Splact avatar Apr 25 '20 23:04 Splact