Graphics Settings System

A graphics service that persists quality level, resolution and fullscreen state through Game Settings and broadcasts every change via the Event Dispatcher.

What the system is for

Every game needs a video options screen. Players expect to lower the quality level on older hardware, pick a resolution that fits their monitor and toggle fullscreen without restarting. In Unity the APIs for quality, resolution and fullscreen are all separate, and wiring them to a settings store, a UI menu and a hardware-aware default is left entirely to the project.

The Game Graphics module in Serenity wraps those three concerns behind a single IGameGraphicsService. It reads persisted preferences on initialization, applies them to the engine, and publishes changes so the UI and any other listener can react without polling.

The Unity problem

A basic Unity project can call QualitySettings.SetQualityLevel and Screen.SetResolution directly. A real project cannot stop there. The chosen quality level must survive between sessions, so it needs to be stored. Hardware that cannot run the default preset needs a lower fallback. The options menu needs to read the current values before the player opens it and write them back when the player confirms. Every piece of that chain is custom work that each project writes from scratch.

Without a service layer, quality and resolution logic ends up scattered across MonoBehaviours, PlayerPrefs calls and menu scripts. Changes to how settings are stored ripple through every screen that touches graphics, and there is no single place to intercept or broadcast a quality change to the rest of the game.

How Serenity approaches it

Serenity exposes graphics through IGameGraphicsService, which covers GetQualityLevelList, GetCurrentQualityLevel, SetCurrentQualityLevel, GetScreenResolution, SetScreenResolution, GetIsFullScreen and SetIsFullScreen. Commands are typed with DTOs such as SetCurrentQualityLevelInput, SetScreenResolutionInput and GameGraphicsSetIsFullScreenInput. The service is created by IGameGraphicsServiceFactory so the Unity implementation can be replaced in tests or on other platforms.

Settings keys and defaults live in IGameGraphicsSettings, implemented as a ScriptableObject asset. On initialization the service reads stored values from IGameSettingsService and falls back to the configured defaults — 1920 × 1080 fullscreen at the configured quality level — when no preference is saved yet. Every mutation is broadcast through IEventDispatcherService so menus, HUD elements and any other subscriber stay in sync automatically.

How it fits into Serenity

Game Graphics lives in the Serenity.GameGraphics namespace and follows the foundation's layered structure. The Domain layer defines IGameGraphicsSettings. The Application layer defines IGameGraphicsService, IGameGraphicsServiceFactory and all command DTOs. Use cases such as GameGraphicsGetCurrentQualityLevel and GameGraphicsSetScreenResolution implement ISyncQueryUseCase and ISyncUseCase respectively, and are aggregated by GameGraphicsUseCases. The Infrastructure layer provides UnityGameGraphicsService and UnityGameGraphicsServiceFactory as the Unity-backed implementations.

Installation is handled by UnityGameGraphicsInstaller, which extends the abstract GameGraphicsInstaller and implements IFoundationInstaller. It wires the service to IEventDispatcherService, ILogService and IGameSettingsService through UnityGameGraphicsInstallerInstallInput. System Configuration provides hardware-aware quality defaults upstream, Game Settings handles persistence, and the menu or UI layer calls the service methods directly to build the video options screen.

Practical workflow

  1. Create a UnityGameGraphicsSettings ScriptableObject asset and configure the persistence keys and default values.
  2. Add UnityGameGraphicsInstaller to your initialization hierarchy and pass it an install input with the Event Dispatcher, Log and Game Settings services.
  3. Call IGameGraphicsService.Initialize during startup; the service reads stored preferences from Game Settings and applies them immediately.
  4. In your video options menu, call GetQualityLevelList to populate the quality dropdown and GetScreenResolution / GetIsFullScreen to reflect the current state.
  5. On player confirmation, call SetCurrentQualityLevel, SetScreenResolution or SetIsFullScreen with the appropriate DTO; the service persists the new value and dispatches the change.
  6. Any other system that needs to react to graphics changes — a texture streaming manager, a dynamic resolution scaler, an overlay renderer — subscribes to the Event Dispatcher rather than polling the service.

What you get

  • Graphics service interface IGameGraphicsService covering quality, resolution and fullscreen in one contract
  • Factory interface IGameGraphicsServiceFactory for swappable Unity or test implementations
  • Settings interface IGameGraphicsSettings backed by UnityGameGraphicsSettings ScriptableObject
  • Typed command DTOs: SetCurrentQualityLevelInput, SetScreenResolutionInput, GameGraphicsSetIsFullScreenInput
  • Use-case layer with GameGraphicsUseCases aggregating all query and command use cases
  • Automatic persistence through IGameSettingsService on every set operation
  • Configurable defaults — quality level key, resolution width/height and fullscreen flag — without code changes
  • Event Dispatcher integration so any subscriber reacts to graphics changes without coupling to the service

When to use this

  • Projects that need a video options screen where players can change quality, resolution and fullscreen mode at runtime.
  • Games that must persist graphics preferences between sessions and restore them on the next launch.
  • Codebases that want graphics state broadcast through the Event Dispatcher so multiple systems can react to changes.
  • Teams that need the graphics service to be replaceable — for tests, for headless builds or for platforms that manage display settings differently.

Related systems

Use Serenity when you want quality, resolution and fullscreen wired to persistence and events from day one, without writing the same settings plumbing in every project.

Back to the home page