fix: prevent premature passenger display during route transitions

Fix bug where new route passengers would appear on train cars before
all cars from the previous route had exited through the tunnel.

The issue occurred because passengers were switched when trainPosition < 0
(locomotive exits), but train cars trail behind by up to 35% (5 cars × 7%
spacing). This caused new passengers to briefly appear on the old cars that
were still fading out (positions 65-97%).

Solution: Calculate the last car's position and only switch passengers when:
1. Train has reset to start position (trainPosition < 0), OR
2. All cars have fully faded out (lastCarPosition >= 97%)

Changes:
- useTrackManagement: Added maxCars and carSpacing parameters
- Updated passenger display logic to check lastCarPosition >= fadeOutEnd
- SteamTrainJourney: Pass maxCars and carSpacing from useTrainTransforms

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock
2025-10-01 10:15:43 -05:00
parent 78d5234a79
commit fe9ea67f56
3 changed files with 31 additions and 21 deletions

View File

@@ -169,7 +169,8 @@
"Bash(open http://localhost:6006)",
"Bash(open http://localhost:3002/games/matching)",
"Bash(open http://localhost:3002/create)",
"Bash(open http://localhost:3002/games/complement-race/practice)"
"Bash(open http://localhost:3002/games/complement-race/practice)",
"Bash(open http://localhost:3002/games/complement-race)"
],
"deny": [],
"ask": []

View File

@@ -98,6 +98,13 @@ export function SteamTrainJourney({ momentum, trainPosition, pressure, elapsedTi
const pathRef = useRef<SVGPathElement>(null)
const [trackGenerator] = useState(() => new RailroadTrackGenerator(800, 600))
// Train transforms (extracted to hook) - called first to get maxCars and carSpacing
const { trainTransform, trainCars, locomotiveOpacity, maxCars, carSpacing } = useTrainTransforms({
trainPosition,
trackGenerator,
pathRef
})
// Track management (extracted to hook)
const { trackData, tiesAndRails, stationPositions, landmarks, landmarkPositions, displayPassengers } = useTrackManagement({
currentRoute: state.currentRoute,
@@ -105,14 +112,9 @@ export function SteamTrainJourney({ momentum, trainPosition, pressure, elapsedTi
trackGenerator,
pathRef,
stations: state.stations,
passengers: state.passengers
})
// Train transforms (extracted to hook)
const { trainTransform, trainCars, locomotiveOpacity, maxCars, carSpacing } = useTrainTransforms({
trainPosition,
trackGenerator,
pathRef
passengers: state.passengers,
maxCars,
carSpacing
})
// Passenger animations (extracted to hook)

View File

@@ -10,6 +10,8 @@ interface UseTrackManagementParams {
pathRef: React.RefObject<SVGPathElement>
stations: Station[]
passengers: Passenger[]
maxCars?: number
carSpacing?: number
}
export function useTrackManagement({
@@ -18,7 +20,9 @@ export function useTrackManagement({
trackGenerator,
pathRef,
stations,
passengers
passengers,
maxCars = 5,
carSpacing = 7
}: UseTrackManagementParams) {
const [trackData, setTrackData] = useState<ReturnType<typeof trackGenerator.generateTrack> | null>(null)
const [tiesAndRails, setTiesAndRails] = useState<{
@@ -68,23 +72,26 @@ export function useTrackManagement({
// Manage passenger display during route transitions
useEffect(() => {
// If we're starting a new route (position < 0) or passengers haven't changed, update immediately
if (trainPosition < 0 || passengers === previousPassengersRef.current) {
// Calculate the position of the last train car
const lastCarPosition = trainPosition - maxCars * carSpacing
const fadeOutEnd = 97 // Position where cars are fully faded out
// Only switch to new passengers when:
// 1. Train has reset to start position (< 0), OR
// 2. All cars (including the last one) have exited (last car position >= fadeOutEnd)
const allCarsExited = lastCarPosition >= fadeOutEnd
const trainReset = trainPosition < 0
if (trainReset || allCarsExited || passengers === previousPassengersRef.current) {
setDisplayPassengers(passengers)
previousPassengersRef.current = passengers
}
// Otherwise, if we're mid-route and passengers changed, keep showing old passengers
else if (trainPosition > 0 && passengers !== previousPassengersRef.current) {
// Keep displaying old passengers until train exits
else if (passengers !== previousPassengersRef.current) {
// Keep displaying old passengers until all cars exit
// Don't update displayPassengers yet
}
// When train resets to beginning, switch to new passengers
if (trainPosition < 0 && passengers !== previousPassengersRef.current) {
setDisplayPassengers(passengers)
previousPassengersRef.current = passengers
}
}, [passengers, trainPosition])
}, [passengers, trainPosition, maxCars, carSpacing])
// Update display passengers during gameplay (same route)
useEffect(() => {