pmndrs / use-cannon

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

ref.current.position didn't update #378

Open jacky0707 opened 2 years ago

jacky0707 commented 2 years ago

👋 Hi there, I was learning react-three-fiber with https://youtu.be/ZnXKmODEFHA?t=961

When I'm try to use camera.position.copy(ref.current.position) to move with the sphere I just created, I found ref.current.position doesn't update.

image image

Here's my code:

export const User = () => {
  // user Sphere
  const { camera } = useThree()
  const [ref, api] = useSphere(() => ({
    mass: 1,
    type: 'Dynamic',
    position: [0, 10, 0],
  }))

  // get movement
  const { moveForward, moveBackward, moveLeft, moveRight } = useKeyboardControls()
  // initial velocity
  const velocity = useRef([0, 0, 0])
  // subscribe to properties to get updates on each frame.
  useEffect(() => {
    const unsubscribe = api.velocity.subscribe((v) =>  velocity.current = v)
    return unsubscribe
  }, [])

  useFrame(() => {
    camera.position.copy(ref.current.position)

    // get direction
    const direction = new Vector3()
    // horizontal direction, z-direction
    const frontVector = new Vector3(0, 0, Number(moveBackward) - Number(moveForward))
    // horizontal direction, x-direction
    const sideVector = new Vector3(Number(moveLeft) - Number(moveRight), 0, 0)

    // vertical, y-direction
    const SPEED = speedUp ? 15 : 5

    // apply horizontal movement to direction
    direction
      .subVectors(frontVector, sideVector)
      .normalize()
      .multiplyScalar(SPEED)
      .applyEuler(camera.rotation)

    api.velocity.set(direction.x, velocity.current[1], direction.z)
  })

  return (
    <>
      <mesh ref={ref}>
        <sphereGeometry />
      </mesh>
    </>
  )
}

and my dependency:

    "@react-three/cannon": "^6.3.0",
    "@react-three/drei": "^9.4.3",
    "@react-three/fiber": "^8.0.11",
Russo-creation commented 2 years ago

hi, You have to get the position from API by subscribing it like you did with velocity :

 const pos = useRef(new THREE.Vector3(0, 0, 0));
  useEffect(
    () =>
      api.position.subscribe((v) => {
        return (pos.current = new THREE.Vector3(v[0], v[1], v[2]));
      }),
    []
  );

and then try to apply to the camera camera.position.copy(pos)

jacky0707 commented 2 years ago

get the position from API by subscribing it like you did with velocity :

 const pos = useRef(new THREE.Vector3(0, 0, 0));

this help me fix this issue, thank you very much.

however I still have some queries point on this issue,

  1. current I'm able to move with the sphere, but ref.current.position still didn't update value when ref is from

    const [ref, api] = useSphere(() => ({
    mass: 1,
    type: 'Dynamic',
    position: [0, 10, 0],
    }))

    same code as above works when I'm using

    "@react-three/cannon": "^2.2.1",
    "@react-three/drei": "^6.0.5",
    "@react-three/fiber": "^7.0.1",
  2. If in recent version we'll need to subscribe position from api, in what case will we use ref from useSphere?

Glavin001 commented 2 years ago

I ended up subscribing and setting the position and quaternion components manually:

  const [bodyRef, physicsApi] = useCompoundBody(/* ... */)

  useEffect(() => {
    return physicsApi.position.subscribe((v) => {
      bodyRef.current.position.fromArray(v);
    });
  }, [physicsApi, bodyRef]);

  useEffect(() => {
    return physicsApi.quaternion.subscribe((v) => {
      bodyRef.current.quaternion.fromArray(v);
    });
  }, [physicsApi, bodyRef]);

Then I could do stuff like this successfully:

otherObject.position.copy(bodyRef.current.position);
otherObject.quaternion.copy(bodyRef.current.quaternion);

🤔 Does using existing bodyRef.current.position instead of a new pos vector as proposed above have any disadvantages?