| import { useLayoutEffect, useRef } from "react"; |
| import type { RefObject } from "react"; |
| import type { Group } from "three"; |
|
|
| type ActorPosition = readonly [number, number, number]; |
|
|
| type CompletePreviousTickPositionOptions = { |
| groupRef: RefObject<Group | null>; |
| tick: number; |
| target: ActorPosition; |
| }; |
|
|
| const SETTLED_DISTANCE = 0.025; |
|
|
| export function useCompletePreviousTickPosition({ |
| groupRef, |
| tick, |
| target, |
| }: CompletePreviousTickPositionOptions) { |
| const previousTickRef = useRef(tick); |
| const previousTargetRef = useRef<ActorPosition>(target); |
|
|
| useLayoutEffect(() => { |
| const group = groupRef.current; |
| const previousTarget = previousTargetRef.current; |
| if (group && tick !== previousTickRef.current && !isAtPosition(group, previousTarget)) { |
| group.position.set(previousTarget[0], previousTarget[1], previousTarget[2]); |
| } |
|
|
| previousTickRef.current = tick; |
| previousTargetRef.current = target; |
| }, [groupRef, target, tick]); |
| } |
|
|
| function isAtPosition(group: Group, target: ActorPosition): boolean { |
| return ( |
| Math.abs(group.position.y - target[1]) <= SETTLED_DISTANCE && |
| Math.hypot(group.position.x - target[0], group.position.z - target[2]) <= SETTLED_DISTANCE |
| ); |
| } |
|
|