feat: preserve track and passengers during route transitions
- Store pending track data and only apply when train resets to beginning - Preserve passenger list display until entire train exits - Prevent visual jumps by keeping old route data visible during fade-out - Track transitions now seamless: old track/passengers persist until trainPosition < 0 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
e704a28524
commit
f2e71657dc
|
|
@ -142,11 +142,65 @@ export function SteamTrainJourney({ momentum, trainPosition, pressure, elapsedTi
|
|||
// Get current route theme
|
||||
const routeTheme = getRouteTheme(state.currentRoute)
|
||||
|
||||
// Track previous route data to maintain visuals during transition
|
||||
const previousRouteRef = useRef(state.currentRoute)
|
||||
const [pendingTrackData, setPendingTrackData] = useState<ReturnType<typeof trackGenerator.generateTrack> | null>(null)
|
||||
|
||||
// Preserve passengers during route transition
|
||||
const [displayPassengers, setDisplayPassengers] = useState(state.passengers)
|
||||
const previousPassengersRef = useRef(state.passengers)
|
||||
|
||||
// Generate track on mount and when route changes
|
||||
useEffect(() => {
|
||||
const track = trackGenerator.generateTrack(state.currentRoute)
|
||||
setTrackData(track)
|
||||
}, [trackGenerator, state.currentRoute])
|
||||
|
||||
// If we're in the middle of a route (position > 0), store as pending
|
||||
// Only apply new track when position resets to beginning (< 0)
|
||||
if (state.trainPosition > 0 && previousRouteRef.current !== state.currentRoute) {
|
||||
setPendingTrackData(track)
|
||||
} else {
|
||||
setTrackData(track)
|
||||
previousRouteRef.current = state.currentRoute
|
||||
setPendingTrackData(null)
|
||||
}
|
||||
}, [trackGenerator, state.currentRoute, state.trainPosition])
|
||||
|
||||
// Apply pending track when train resets to beginning
|
||||
useEffect(() => {
|
||||
if (pendingTrackData && state.trainPosition < 0) {
|
||||
setTrackData(pendingTrackData)
|
||||
previousRouteRef.current = state.currentRoute
|
||||
setPendingTrackData(null)
|
||||
}
|
||||
}, [pendingTrackData, state.trainPosition, state.currentRoute])
|
||||
|
||||
// Manage passenger display during route transitions
|
||||
useEffect(() => {
|
||||
// If we're starting a new route (position < 0) or passengers haven't changed, update immediately
|
||||
if (state.trainPosition < 0 || state.passengers === previousPassengersRef.current) {
|
||||
setDisplayPassengers(state.passengers)
|
||||
previousPassengersRef.current = state.passengers
|
||||
}
|
||||
// Otherwise, if we're mid-route and passengers changed, keep showing old passengers
|
||||
else if (state.trainPosition > 0 && state.passengers !== previousPassengersRef.current) {
|
||||
// Keep displaying old passengers until train exits
|
||||
// Don't update displayPassengers yet
|
||||
}
|
||||
|
||||
// When train resets to beginning, switch to new passengers
|
||||
if (state.trainPosition < 0 && state.passengers !== previousPassengersRef.current) {
|
||||
setDisplayPassengers(state.passengers)
|
||||
previousPassengersRef.current = state.passengers
|
||||
}
|
||||
}, [state.passengers, state.trainPosition])
|
||||
|
||||
// Update display passengers during gameplay (same route)
|
||||
useEffect(() => {
|
||||
// Only update if we're in the same route (not transitioning)
|
||||
if (previousRouteRef.current === state.currentRoute && state.trainPosition >= 0 && state.trainPosition < 100) {
|
||||
setDisplayPassengers(state.passengers)
|
||||
}
|
||||
}, [state.passengers, state.currentRoute, state.trainPosition])
|
||||
|
||||
// Generate ties and rails when path is ready
|
||||
useEffect(() => {
|
||||
|
|
@ -372,13 +426,13 @@ export function SteamTrainJourney({ momentum, trainPosition, pressure, elapsedTi
|
|||
|
||||
// Memoize filtered passenger lists to avoid recalculating on every render
|
||||
const boardedPassengers = useMemo(() =>
|
||||
state.passengers.filter(p => p.isBoarded && !p.isDelivered),
|
||||
[state.passengers]
|
||||
displayPassengers.filter(p => p.isBoarded && !p.isDelivered),
|
||||
[displayPassengers]
|
||||
)
|
||||
|
||||
const nonDeliveredPassengers = useMemo(() =>
|
||||
state.passengers.filter(p => !p.isDelivered),
|
||||
[state.passengers]
|
||||
displayPassengers.filter(p => !p.isDelivered),
|
||||
[displayPassengers]
|
||||
)
|
||||
|
||||
// Memoize ground texture circles to avoid recreating on every render
|
||||
|
|
|
|||
|
|
@ -374,11 +374,11 @@ function gameReducer(state: GameState, action: GameAction): GameState {
|
|||
...state,
|
||||
currentRoute: action.routeNumber,
|
||||
stations: action.stations,
|
||||
trainPosition: 0,
|
||||
trainPosition: -5, // Start off-screen to the left for smooth fade-in
|
||||
deliveredPassengers: 0,
|
||||
showRouteCelebration: false,
|
||||
momentum: 0,
|
||||
pressure: 0
|
||||
momentum: 50, // Give some starting momentum for the new route
|
||||
pressure: 50
|
||||
}
|
||||
|
||||
case 'COMPLETE_ROUTE':
|
||||
|
|
|
|||
Loading…
Reference in New Issue