1- # ADR-0011: Real-Time Game Loop Architecture
1+ ---
2+ status : accepted
3+ date : 2026-02-11
4+ title : Real-Time Game Loop Architecture
5+ decision-makers :
6+ consulted :
7+ informed :
8+ ---
29
3- ** Status:** Accepted
4- ** Date:** 2026-02-11
10+ # Real-Time Game Loop Architecture
511
612---
713
8- ## Context
14+ ## Context and Problem Statement
915
1016Tank Royale is a real-time programming game where multiple bots battle simultaneously.
1117
1218** Problem:** How to synchronize actions of multiple bots while ensuring deterministic, fair gameplay?
1319
14- ** Requirements: **
20+ ## Decision Drivers
1521- Consistent frame rate (30 TPS target)
1622- Deterministic physics (reproducible results)
1723- Fair synchronization (all bots see same state)
18- - Handle bot timeouts gracefully
19- - Support pause/resume for debugging
24+ - Graceful handling of bot timeouts
25+ - Support for pause/resume for debugging
2026
2127---
2228
23- ## Decision
29+ ## Decision Outcome
2430
2531Use a ** turn-based discrete tick loop** at ** 30 TPS** with:
2632- Server as authoritative game state manager
@@ -30,14 +36,31 @@ Use a **turn-based discrete tick loop** at **30 TPS** with:
3036
3137---
3238
33- ## Rationale
39+ ## Considered Options
40+ - Discrete tick-based loop at fixed 30 TPS (chosen)
41+ - Continuous real-time loop
42+ - Event-driven async processing
43+ - Client-side lockstep synchronization
44+ - Hybrid tick + event approach
45+
46+ ## Pros and Cons of the Options
47+
48+ ### Discrete tick-based loop at 30 TPS (chosen)
49+ Good, because deterministic, fair synchronization, predictable performance, and robust timeout handling.
50+
51+ Bad, because fixed frame rate and quantized movement.
3452
35- ** Why tick-based loop:**
36- - ✅ ** Deterministic** : Same inputs → same outputs (reproducible)
37- - ✅ ** Fair synchronization** : All bots receive identical game state simultaneously
38- - ✅ ** Timeout handling** : Bots can't stall the game (fixed deadline)
39- - ✅ ** Predictable performance** : 30 TPS = ~ 33ms per turn budget
40- - ✅ ** Network-friendly** : 30 TPS matches typical latency constraints
53+ ### Continuous real-time
54+ Bad, because non-deterministic and synchronization issues.
55+
56+ ### Event-driven async
57+ Bad, because race conditions and unfair network advantages.
58+
59+ ### Client-side lockstep
60+ Bad, because slow clients can stall the entire game.
61+
62+ ### Hybrid tick + event
63+ Bad, because added complexity without clear benefit in this context.
4164
4265### Synchronization Pattern
4366
@@ -75,60 +98,13 @@ sequenceDiagram
7598
7699---
77100
78- ## Implementation
79-
80- ### Game Loop State Machine
81-
82- ``` mermaid
83- stateDiagram-v2
84- [*] --> WAIT_FOR_PARTICIPANTS: Server starts
85- WAIT_FOR_PARTICIPANTS --> WAIT_FOR_READY: All bots connected
86- WAIT_FOR_READY --> GAME_RUNNING: All bots ready
87- GAME_RUNNING --> GAME_PAUSED: Pause requested
88- GAME_PAUSED --> GAME_RUNNING: Resume requested
89- GAME_RUNNING --> GAME_STOPPED: Battle ends
90- GAME_STOPPED --> [*]
91-
92- note right of GAME_RUNNING
93- Main tick loop: 30 iterations/sec
94- end note
95- ```
96-
97- ### Per-Tick Execution
98-
99- ``` kotlin
100- fun executeTurn () {
101- // 1. Send tick events to all bots (same game state)
102- bots.forEach { it.sendTickEvent(gameState) }
103-
104- // 2. Collect intents with timeout (~30ms)
105- val intents = bots.associateWith { bot ->
106- try {
107- bot.receiveIntent(timeout = botTimeoutMs)
108- } catch (e: TimeoutException ) {
109- bot.sendSkippedTurnEvent()
110- null // Late response
111- }
112- }
113-
114- // 3. Apply all valid intents to physics
115- applyIntents(intents.filterNotNull())
116- updatePhysics()
117- checkCollisions()
118-
119- // 4. Maintain 30 TPS
120- sleepToMaintainTPS()
121- }
122- ```
101+ ## More Information
123102
124- ** Configuration:**
125- ``` bash
126- java -jar server.jar --tps=30 --turn-timeout=30 --max-inactivity=30
127- ```
103+ - Detailed design, diagrams, and pseudo-code: ` /docs/design/game-loop-architecture.md `
128104
129105---
130106
131- ## Consequences
107+ ### Consequences
132108
133109- ✅ Deterministic physics (fair competition)
134110- ✅ Timeout enforcement prevents game stalling
@@ -141,8 +117,8 @@ java -jar server.jar --tps=30 --turn-timeout=30 --max-inactivity=30
141117
142118---
143119
144- ## References
120+ ## More Information
145121
146- - [ Game Loop Patterns] ( https://gameprogrammingpatterns.com/game-loop.html )
147- - [ Server Implementation] ( /server/README.md )
122+ - Game Loop Patterns: https://gameprogrammingpatterns.com/game-loop.html
123+ - Server Implementation: ` /server/README.md `
148124
0 commit comments