You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
samples/game_template/.github/copilot-instructions.md

6.3 KiB

Copilot Instructions for Flutter Game Template

Project Overview

This is a mobile game template built with Flutter showcasing a complete starter game with navigation, audio, state management, and optional integrations (ads, in-app purchases, games services, Firebase Crashlytics). The template is intentionally low-level on state management to avoid complexity while remaining extensible.

Architecture & Key Components

Feature-First Organization (lib/src/)

Code is organized by feature, not by layer. Each feature directory is semi-independent:

  • audio/ - Music and sound effects (via audioplayers package)
  • player_progress/ - Game progress tracking with persistence abstraction
  • settings/ - User preferences (muted, music, sound, player name)
  • app_lifecycle/ - Lifecycle event monitoring via WidgetsBindingObserver
  • main_menu/, level_selection/, play_session/, win_game/ - Screen features
  • ads/, games_services/, in_app_purchase/ - Optional integrations (disabled by default)
  • style/ - Palette, responsive layout, custom transitions

State Management Pattern

Uses Provider with a low-level, intentional approach:

  • ChangeNotifier for mutable state (PlayerProgress, SettingsController, AudioController)
  • ValueNotifier for simple reactive properties (settings values, lifecycle state)
  • MultiProvider setup in main.dart with explicit dependency ordering
  • Key insight: AudioController depends on SettingsController via ProxyProvider2 for reactive attachment
  • No code generation; manually attach listeners using attachSettings() and attachLifecycleNotifier() patterns

Persistence Abstraction

All persistent data uses dependency-injected interfaces:

  • PlayerProgressPersistence (injected in PlayerProgress)
  • SettingsPersistence (injected in SettingsController)
  • Default implementation: LocalStoragePlayerProgressPersistence, LocalStorageSettingsPersistence
  • This allows easy testing or swapping implementations (e.g., Firebase, cloud sync)

Navigation

Uses GoRouter (v16.0.0+) with nested route structure in main.dart:

  • Routes are statically defined in MyApp._router
  • Transitions use custom buildMyTransition<void>() helper from src/style/my_transition.dart
  • Parameters passed via state.pathParameters (e.g., level number in /play/session/:level)
  • Extra data passed via state.extra and validated with guards (e.g., win screen redirect)

Audio Integration

AudioController is a facade over audioplayers package:

  • Manages a music player + pool of SFX players (configurable polyphony, default 2)
  • Automatically shuffles playlist and handles lifecycle pauses
  • Pauses audio when app goes to background; resumes on foreground
  • Settings-aware: respects muted, musicOn, soundsOn toggles
  • Use audioController.playSfx(SfxType.buttonTap) to play sound effects

Optional Integrations (Commented By Default)

In main.dart, integrations are commented out and must be explicitly enabled:

  • Firebase Crashlytics: Uncomment imports and initialize block; requires firebase_options.dart
  • Google Mobile Ads: Uncomment AdsController initialization; requires google_mobile_ads package
  • Games Services: Uncomment GamesServicesController initialization
  • In-App Purchase: Uncomment InAppPurchaseController initialization
  • All integrations use platform guards: !kIsWeb && (Platform.isIOS || Platform.isAndroid)

Development Workflows

Running the App

# Default (emulator/simulator/physical device)
flutter run

# Desktop (faster iteration, no emulator needed)
flutter run -d macOS     # or -d linux / -d windows

# Web (useful for demos)
flutter run -d web

Building for Production

# iOS
flutter build ipa && open build/ios/archive/Runner.xcarchive

# Android
flutter build appbundle && open build/app/outputs/bundle/release

# Web (requires 'peanut' package)
flutter pub global run peanut --web-renderer canvaskit --extra-args "--base-href=/repo_name/" && git push origin --set-upstream gh-pages

Analysis & Linting

Uses flutter_lints with minimal overrides (prefer_const_constructors and prefer_single_quotes disabled for early development). Check with:

flutter analyze

Code Patterns & Conventions

Logging

Uses package:logging with dev.log:

static final _log = Logger('ClassName');
_log.info('message');
_log.warning('warning');

Responsive UI

Custom ResponsiveScreen widget in src/style/responsive_screen.dart provides mainAreaProminence and layout areas. Use for adaptive layouts across mobile/tablet/desktop.

Snack Bar Feedback

Custom showSnackBar() in src/style/snack_bar.dart. Use a global scaffoldMessengerKey passed to MaterialApp.router.

Palette & Theme

Centralized Palette provider in src/style/palette.dart. Inject via context.watch<Palette>(). Avoids hardcoding colors.

Game Levels

Game levels defined in src/level_selection/levels.dart as a list. Reference by level number in routing.

Screen State Management

Screens are typically StatelessWidget that watch providers. Mutable interactions go through provider controllers:

final audioController = context.watch<AudioController>();
audioController.playSfx(SfxType.buttonTap);

Dependencies Overview

  • go_router (v16.0.0): Navigation and routing
  • provider (v6.0.2): State management
  • audioplayers (v6.0.0): Audio playback
  • shared_preferences: Local persistence (via abstraction)
  • logging: Structured logging to dart:developer
  • Optional: firebase_core, firebase_crashlytics, google_mobile_ads, games_services, in_app_purchase

Critical Notes for Contributors

  1. Persistence is abstracted: Always use the persistence interface, not SharedPreferences directly
  2. Controllers manage their own initialization: Check initialize() methods and async setup requirements
  3. Lifecycle matters: Audio and ads controllers must respect app lifecycle state
  4. Platform-specific code: Use kIsWeb and platform checks (Platform.isIOS, etc.) for platform-specific logic
  5. No code generation: Template intentionally avoids build_runner for simplicity; can be added if needed
  6. Settings require explicit toggle: Integrations are commented out; uncomment and enable explicitly when needed
  7. Router validation: Use redirect guards on sensitive routes (e.g., win screen requires score extra data)