Game Loop and Time Management
Building the Heartbeat: From Clicks to Time
In the previous lesson, you wired up player actions and reducer updates. As a quick reminder, your GameActions component dispatches events, and the reducer applies guarded, immutable updates. Today, you will make the café feel alive by introducing time. You will create a game loop that dispatches a TICK every second, pause it based on state, and clean up intervals to avoid leaks.
Implementing the Interval in GameScreen.jsx
We attach the loop in the screen component with a useEffect that sets up a setInterval. The interval dispatches TICK once per second only when the game is running and not paused. Cleanup ensures we stop the timer when the component unmounts or the dependencies change.
src/components/GameScreen.jsx
What is happening:
- Guard clause: If we are not in the
PLAYINGphase or the game is paused, do not start an interval. - Interval: Dispatches
{ type: 'TICK' }every 1000 ms. - Cleanup:
clearIntervalprevents memory leaks and duplicate timers. - Dependency array: Restarting the interval when
phaseorisPausedchanges ensures the loop tracks the current state.
Processing TICK in the Reducer
The reducer is still the “brain.” For now, each tick reduces the remaining time and converts real seconds to in-game hours and minutes (1 sec = 3 game minutes). You will expand this logic in the next unit.
src/reducers/gameReducer.js
Key ideas:
- Guard early if not
PLAYINGor paused to keep updates predictable. - Convert remaining real-time seconds into a fast-forwarded in-game clock.
- Return a new state object to maintain immutability and clean re-renders.
Summary and Next Steps
You now have a reliable game loop:
- A
useEffect-backed interval that ticks only when the game is active. - Proper cleanup to avoid multiple overlapping timers.
- A reducer that updates time consistently and safely.
Next, you will practice making the loop feel real with events and dynamic state. Let’s head to the practice section and bring more motion into the café.
