You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The application previously operated on a simple day/night cycle with no concept of long-term progression or seasons. The weather was static unless manually changed. A request was made to simulate a full year.
12
+
13
+
## Decision
14
+
15
+
We implemented a `day` (1-365) and `year` counter in the `WeatherSystem`. The year is divided into four distinct seasons based on day ranges:
16
+
***Winter**: Days 1-90
17
+
***Spring**: Days 91-180
18
+
***Summer**: Days 181-270
19
+
***Autumn**: Days 271-365
20
+
21
+
## Consequences
22
+
23
+
***Positive**: Adds depth and variety to the gameplay loop; creates a sense of time progression.
24
+
***Negative**: Adds state complexity to the `WeatherSystem`.
Weather needed to change dynamically without user input, but purely random selection (noise) would lack realism (e.g., snow in summer).
12
+
13
+
## Decision
14
+
15
+
We implemented a probabilistic approach where the `currentSeason` determines the likelihood of specific weather types. The system checks for a weather change every 2-4 in-game hours.
16
+
17
+
***Winter**: High chance of Snow.
18
+
***Summer**: High chance of Sun.
19
+
***Spring/Autumn**: Mixed probabilities.
20
+
21
+
## Consequences
22
+
23
+
***Positive**: Weather feels organic and season-appropriate.
24
+
***Negative**: Predictability is reduced; rigorous testing requires time acceleration or mocking.
The speed of the day/night cycle impacts the pacing of the game.
12
+
13
+
## Decision
14
+
15
+
The time scale is fixed such that 1 in-game day equals 10 minutes of real time. This is achieved by setting the time increment `hoursPerSec` to `0.04` (24 hours / 600 seconds).
16
+
17
+
## Consequences
18
+
19
+
***Positive**: Provides a balanced cycle that is long enough to enjoy but short enough to see transitions during a play session.
20
+
***Negative**: Fixed scaling might not suit all players (though this is standard for this genre).
With the introduction of the automatic seasonal system, manual overrides (keyboard shortcuts 1, 2, 3) conflicted with the simulation logic (e.g., manually setting Sun during a calculated Snow period would be immediately overwritten or break immersion).
12
+
13
+
## Decision
14
+
15
+
We removed the manual keyboard event listeners and the corresponding on-screen UI instructions.
16
+
17
+
## Consequences
18
+
19
+
***Positive**: Ensures the integrity of the seasonal simulation; cleans up the UI.
20
+
***Negative**: Developers and users lose the ability to instantly force weather states for debugging or screenshot purposes. A "Debug Mode" may need to be reintroduced later.
Players want the in-game season to initially match the real-world season to enhance immersion. For example, if playing in December, the game should start in Winter.
12
+
13
+
## Decision
14
+
15
+
We query the system's current date (`new Date()`) at startup and calculate the day of the year (1-366). We initialize the game's `day` counter with this value.
16
+
17
+
## Consequences
18
+
19
+
***Positive**: Immediate immersion boost; the game feels "live" and connected to reality.
20
+
***Negative**: A new player starting in Winter might face harder weather conditions (snow) immediately compared to starting in Summer.
The game generates an infinite world using chunks. Each chunk contained hundreds of individual meshes for buildings, windows, road markings, and vegetation. This led to a very high number of draw calls (thousands per frame) and significant GPU overhead, preventing the game from maintaining a steady 60 FPS, especially on lower-end devices.
12
+
13
+
## Decision
14
+
15
+
We refactored the chunk generation system (`world.js` and `createCityChunk`) to implement **Geometry Merging**.
16
+
17
+
Instead of creating a `THREE.Mesh` for every single building part:
18
+
1. We pass a `geoms` accumulator object to all building functions.
19
+
2. Each function pushes `THREE.BufferGeometry` instances into arrays keyed by material type (e.g., `geoms.concrete`, `geoms.glass`).
20
+
3. At the end of chunk generation, we use `BufferGeometryUtils.mergeGeometries` to combine all geometries of the same material into a single mesh.
21
+
4. The final chunk contains only ~10-15 meshes (one per unique material) instead of hundreds.
22
+
23
+
## Consequences
24
+
25
+
### Positive
26
+
***Drastically Reduced Draw Calls**: From ~500+ per chunk to ~15 per chunk.
27
+
***Improved Frame Rate**: Significant CPU and GPU optimization.
28
+
***Consistent Visuals**: The visual output remains identical.
29
+
30
+
### Negative
31
+
***Loss of Individual Object Identity**: Individual buildings are no longer separate objects. We cannot easily interact with (e.g., click, move, destroy) a specific building instance anymore without complex raycasting logic on the merged mesh.
32
+
***Increased Memory during Generation**: All geometries must be held in memory arrays before merging.
33
+
***Slightly Slower Chunk Generation**: The merge operation itself is CPU intensive, but it happens once per chunk load and saves frame time forever after.
The infinite runner nature of the game requires constant spawning and despawning of traffic cars as new chunks load and old ones unload. Creating new `THREE.Group` hierarchies and geometries for complex cars triggers frequent Garbage Collection (GC) pauses and frame drops (stutter) whenever the player crosses a chunk boundary.
12
+
13
+
## Decision
14
+
15
+
We implemented an **Object Pooling** system for the `TrafficSystem`.
16
+
17
+
1. A `CarPool` dictionary organizes inactive car objects by type (`sedan`, `taxi`, etc.).
18
+
2. When a chunk loads, cars are retrieved from the pool (`getCarFromPool`). If empty, a new car is created.
19
+
3. When a chunk unloads, cars are hidden and returned to the pool (`returnCarToPool`) instead of being disposed.
20
+
4. The `utils.js` disposal logic is bypassed for pooled objects during normal gameplay.
21
+
22
+
## Consequences
23
+
24
+
### Positive
25
+
***Reduced Stutter**: Elimination of instantiation lag when generating chunks.
26
+
***Reduced GC Pressure**: Memory usage stabilizes as objects are reused rather than constantly allocated and discarded.
27
+
***Smoother Gameplay**: Consistent framerate across chunk boundaries.
28
+
29
+
### Negative
30
+
***Memory Overhead**: Unused cars remain in memory (hidden) rather than being fully freed.
31
+
***State Management Risk**: If a car is not properly reset (e.g., position, rotation, damage state) when retrieved from the pool, "ghost" behaviors could occur. We explicitly reset visibility and scene presence.
0 commit comments