fix(complement-race): ensure continuous position broadcasting during train movement
Fixed an issue where ghost trains only updated when players stopped moving. Root cause: clientPosition in useEffect dependency array caused the position broadcasting interval to restart on every position change, creating gaps in broadcasts during continuous movement. Solution: - Use useRef to track latest clientPosition without triggering effect - Keep ref synced with position via separate useEffect - Read position from ref inside interval callback - Remove clientPosition from broadcasting useEffect dependencies Now positions broadcast smoothly every 200ms regardless of movement state. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -325,6 +325,9 @@ export function ComplementRaceProvider({ children }: { children: ReactNode }) {
|
|||||||
const [clientMomentum, setClientMomentum] = useState(10) // Start at 10 for gentle push
|
const [clientMomentum, setClientMomentum] = useState(10) // Start at 10 for gentle push
|
||||||
const [clientPosition, setClientPosition] = useState(0)
|
const [clientPosition, setClientPosition] = useState(0)
|
||||||
const [clientPressure, setClientPressure] = useState(0)
|
const [clientPressure, setClientPressure] = useState(0)
|
||||||
|
|
||||||
|
// Ref to track latest position for broadcasting (avoids recreating interval on every position change)
|
||||||
|
const clientPositionRef = useRef(clientPosition)
|
||||||
const [clientAIRacers, setClientAIRacers] = useState<
|
const [clientAIRacers, setClientAIRacers] = useState<
|
||||||
Array<{
|
Array<{
|
||||||
id: string
|
id: string
|
||||||
@@ -564,31 +567,29 @@ export function ComplementRaceProvider({ children }: { children: ReactNode }) {
|
|||||||
}
|
}
|
||||||
}, [multiplayerState.currentRoute, compatibleState.style, multiplayerState.passengers.length])
|
}, [multiplayerState.currentRoute, compatibleState.style, multiplayerState.passengers.length])
|
||||||
|
|
||||||
|
// Keep position ref in sync with latest position
|
||||||
|
useEffect(() => {
|
||||||
|
clientPositionRef.current = clientPosition
|
||||||
|
}, [clientPosition])
|
||||||
|
|
||||||
// Broadcast position to server for multiplayer ghost trains
|
// Broadcast position to server for multiplayer ghost trains
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!compatibleState.isGameActive || compatibleState.style !== 'sprint' || !localPlayerId) {
|
if (!compatibleState.isGameActive || compatibleState.style !== 'sprint' || !localPlayerId) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send position update every 200ms
|
// Send position update every 200ms (reads from ref to avoid restarting interval)
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
sendMove({
|
sendMove({
|
||||||
type: 'UPDATE_POSITION',
|
type: 'UPDATE_POSITION',
|
||||||
playerId: localPlayerId,
|
playerId: localPlayerId,
|
||||||
userId: viewerId || '',
|
userId: viewerId || '',
|
||||||
data: { position: clientPosition },
|
data: { position: clientPositionRef.current },
|
||||||
} as ComplementRaceMove)
|
} as ComplementRaceMove)
|
||||||
}, 200)
|
}, 200)
|
||||||
|
|
||||||
return () => clearInterval(interval)
|
return () => clearInterval(interval)
|
||||||
}, [
|
}, [compatibleState.isGameActive, compatibleState.style, localPlayerId, viewerId, sendMove])
|
||||||
compatibleState.isGameActive,
|
|
||||||
compatibleState.style,
|
|
||||||
clientPosition,
|
|
||||||
localPlayerId,
|
|
||||||
viewerId,
|
|
||||||
sendMove,
|
|
||||||
])
|
|
||||||
|
|
||||||
// Keep lastLogRef for future debugging needs
|
// Keep lastLogRef for future debugging needs
|
||||||
// (removed debug logging)
|
// (removed debug logging)
|
||||||
|
|||||||
Reference in New Issue
Block a user