Core gameplay loop, player management, and game state handling in osu!
The gameplay system orchestrates the entire play session from loading to completion. It manages the ruleset, scoring, health, input handling, and all visual/audio elements during gameplay.
The DrawableRuleset is the game-mode specific component that renders and manages hit objects.Location: osu.Game/Rulesets/UI/DrawableRuleset.cs:43
public abstract partial class DrawableRuleset<TObject> : DrawableRuleset where TObject : HitObject{ // The playfield where hit objects are displayed public override Playfield Playfield { get; } // The converted beatmap public readonly Beatmap<TObject> Beatmap; // Applied mods public sealed override IReadOnlyList<Mod> Mods { get; } // Frame stability for consistent gameplay public override IFrameStableClock FrameStableClock { get; } // Hit object collection public override IEnumerable<HitObject> Objects => Beatmap.HitObjects; // Events for judgements public override event Action<JudgementResult> NewResult; public override event Action<JudgementResult> RevertResult;}
The GameplayState class encapsulates all state information for a gameplay session.Location: osu.Game/Screens/Play/GameplayState.cs:20
public class GameplayState{ // The final beatmap after conversion and mods public readonly IBeatmap Beatmap; // Active ruleset public readonly Ruleset Ruleset; // Applied mods public readonly IReadOnlyList<Mod> Mods; // Score tracking public readonly Score Score; public readonly ScoreProcessor ScoreProcessor; public readonly HealthProcessor HealthProcessor; // Visual elements public readonly Storyboard Storyboard; // Completion state public bool HasPassed { get; set; } public bool HasFailed { get; set; } public bool HasQuit { get; set; } public bool HasCompleted => HasPassed || HasFailed || HasQuit; // Last judgement tracking public IBindable<JudgementResult> LastJudgementResult { get; } // Playing state (playing, paused, watching) public IBindable<LocalUserPlayingState> PlayingState { get; }}
GameplayState Usage
GameplayState is cached in the dependency container, making it accessible to all child components (HUD elements, mods, etc.) without explicit passing.
public class HealthProcessor{ // Current health (0.0 - 1.0) public BindableDouble Health { get; } // Fail state public bool HasFailed { get; } // Apply health change from judgement public void ApplyResult(JudgementResult result);}
Health changes are not synchronized in multiplayer. Each client tracks their own health independently.