Demo: https://youtube.com/shorts/nAOBHJdSWW0?si=7FuiB8lojU4RU6aD
A mobile-first strategy simulation game where players guide a nation through real-time historical development. Built with Flutter, the game features a province-based SVG map, daily tick progression, discrete unit movement, and military front management. Designed to be cross-platform and offline-first for now.
Game Type: 2D Strategy Simulation
Core Mechanics:
- Day-by-day progression (tick-based time system)
- Province-based unit control
- Discrete unit movements (1 province at a time)
- Battle simulation when multiple armies enter the same province
Technologies:
- Flutter (Dart)
flutter_svgfor SVG map renderingproviderorriverpodfor state managementhiveorisarfor offline persistence
lib/
main.dart
app.dart
core/
game_loop.dart
tick_engine.dart
game_clock.dart
models/
army.dart
battle.dart
province.dart
game_state.dart
services/
battle_service.dart
movement_service.dart
storage_service.dart
ui/
home_screen.dart
map_view.dart
province_icon.dart
game_ui.dart
assets/
maps/
map.svg
icons/
army.png
battle.png
class GameLoop {
Timer? _timer;
Duration tickDuration;
final VoidCallback onTick;
GameLoop({required this.tickDuration, required this.onTick});
void start() {
_timer = Timer.periodic(tickDuration, (_) => onTick());
}
void stop() {
_timer?.cancel();
}
void changeSpeed(Duration newDuration) {
stop();
tickDuration = newDuration;
start();
}
}class Province {
final String id;
final String name;
final List<String> neighbors;
String? occupyingArmyId;
String? ongoingBattleId;
Province({required this.id, required this.name, required this.neighbors});
}- Use
flutter_svgto load SVG. - Assign IDs to
<path>tags in the SVG file. - Use
GestureDetectoror custom overlay logic for province click detection.
class Army {
final String id;
String currentProvince;
String? destinationProvince;
int daysToArrive;
void tick() {
if (destinationProvince != null) {
daysToArrive--;
if (daysToArrive <= 0) {
currentProvince = destinationProvince!;
destinationProvince = null;
}
}
}
}Handles validation and assignment of movement.
class Battle {
final String id;
final String provinceId;
List<String> armyIds;
int duration;
void tick() {
// apply battle logic each day
}
}Handles engagement creation and damage calculations.
class MapView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Stack(
children: [
SvgPicture.asset('assets/maps/map.svg'),
// Add province overlays if needed
],
);
}
}- Includes game speed controls (e.g., x1, x3, x5)
- Shows current date, army info, province stats
Use Riverpod or Provider to manage global game state:
- Current date
- List of provinces, armies, battles
- Game speed / paused state
- Store
gameStateon every tick or movement - Load on app restart
final box = await Hive.openBox('game_state');
await box.put('state', gameState.toJson());- Add save/load functionality
- Add user profiles and achievements
- Add simple animations using
AnimatedPositioned
- Performance when redrawing the map
- SVG touch detection (requires precision layout)
- Game balance (scaling economy, war, population growth)
Let me know if you want this turned into a GitHub README or project boilerplate.