pmndrs / use-cannon

👋💣 physics based hooks for @react-three/fiber
https://cannon.pmnd.rs
2.74k stars 153 forks source link

adding a pause functionality #341

Closed grndctrl closed 2 years ago

grndctrl commented 2 years ago

212

This branch implements a simple paused boolean prop that when set to true prevents the world from stepping.

I cooked up a simple example here: Click the crates, then click Pause.

vercel[bot] commented 2 years ago

This pull request is being automatically deployed with Vercel (learn more).
To see the status of your deployment, click below or on the icon next to each commit.

🔍 Inspect: https://vercel.com/pmndrs/use-cannon/4Xdbvj2r9aj3cN6uARo71ZYSPA1L
✅ Preview: https://use-cannon-git-fork-grndctrl-pause-pmndrs.vercel.app

bjornstar commented 2 years ago

If you don't call step, the world won't run.

It seems like the real problem is that you can't control the delta of the step.

grndctrl commented 2 years ago

If you don't call step, the world won't run.

For my use case this is exactly what I want though :) I want to pause the world when the window is not focussed. So that when you return, te world picks up where you left it.

It seems like the real problem is that you can't control the delta of the step.

I actually thought of this as well, a way I could envision this is when we have access to the state through something like usePhysics hook, which would return the state like useThree does. Then you would be able to do something like:

const [isPaused, togglePaused] = useState(false)
const { lastTimeCalled, config }  = usePhysics()

useEffect(() => {
  config.step = isPaused ? 0 : 1 / 60
  lastTimeCalled = Date.now() / 1000
}, [isPaused])

But I'm not sure if this is the way to go.

bjornstar commented 2 years ago

For some reason I was thinking this was in cannon-es.

I think the step worker message event should have the same arguments as world.step: stepSize & delta

grndctrl commented 2 years ago

That would be a good thing anyhow, to keep them alike in functionality.

bjornstar commented 2 years ago

What do you think about changing the approach to making the step event match cannon-es?

We can still have a client side property paused which skips sending the step event.

grndctrl commented 2 years ago

What do you think about changing the approach to making the step event match cannon-es?

Sure, I can have a shot at it! I think it's best if I do it on another branch.

bjornstar commented 2 years ago

I think it's fine to do it on this branch, it will be the best solution to implement pausing.

grndctrl commented 2 years ago

Welp, I am running into a brick wall here, since my reasoning doesn't appear to be working. I tried to do something like:

export type State = {
  config: { step: number | [number, number?] }
  ...
}
case 'step': {
      const now = performance.now() / 1000

      if (!state.lastCallTime) {
        if (typeof state.config.step === 'number') {
          state.world.step(state.config.step)
        } else {
          state.world.step(state.config.step[0], state.config.step[1])
        }
      } else {
        if (typeof state.config.step === 'number') {
          const timeSinceLastCall = now - state.lastCallTime
          state.world.step(state.config.step, timeSinceLastCall)
        } else {
          const timeSinceLastCall = state.config.step[1] ? state.config.step[1] : now - state.lastCallTime
          state.world.step(state.config.step[0], timeSinceLastCall)
        }
      }

      state.lastCallTime = now

As I mentioned before, I actually came here while trying to make use-p2 pause. Which I got working by just using <Physics step={isPaused ? 0 : 1/ 60} />, the problem was when I resumed it tried to play catch up.

However <Physics step={isPaused ? 0 : 1/ 60} /> breaks cannon, in this example the physical objects just disappear.

So I'm guessing I'm having the wrong approach here.

I think it's fine to do it on this branch, it will be the best solution to implement pausing.

Is it though? The cannon-es examples have a 'paused' toggle, which is more like my original approach. It completely prevents the world from stepping, it's bypassing this.updatePhysics(), which is I guess the equivalent of the worker step event.

bjornstar commented 2 years ago

I guess it wasn't as clear as I thought it would be, I'll go ahead and take a stab at it.

Do you mind if I add your pausing demo?

grndctrl commented 2 years ago

Do you mind if I add your pausing demo?

By all means, of course!

bjornstar commented 2 years ago

Please take a look at #342

There's some unrelated demo cleanup there, but the change should be pretty clear.

bjornstar commented 2 years ago

Thanks for getting started on this! I've gone ahead and merged my PR with your demo. I'll release it shortly.

grndctrl commented 2 years ago

Your approach is much better, do you mind if I try to copy your work and implement a similar solution to use-p2?

bjornstar commented 2 years ago

Your approach is much better, do you mind if I try to copy your work and implement a similar solution to use-p2?

Please do, I was thinking it would be nice to do it over there too :)

joergjaeckel commented 2 years ago

Would love to see the recent changes in p2 but we need also do some of the previous PRs of cannon over there too. Might be good to do that first.

yyynnn commented 2 years ago

Any progress on the usePhysics hook? It would be nice to just read some metrics like dt, time, etc.