-
Notifications
You must be signed in to change notification settings - Fork 6
song_select
The song select screen is where the player browses songs and folders, selects a difficulty, and transitions into gameplay. It manages a state machine that routes input and drawing across several sub-systems: the global navigator, the song_select_player, and a song_select_script that drives the footer and overlay animations.
The screen is constructed with the name "song_select", which the base Screen class uses to load the correct textures and sounds from the active skin.
An enum tracking which phase the screen is currently in.
| Value | Description |
|---|---|
BROWSING |
The player is scrolling through the song/folder list |
SONG_SELECTED |
A song has been opened and the difficulty selector is visible |
DIFF_SORTING |
The diff_sort UI is open for filtering songs by difficulty |
SEARCHING |
The search_box is open for text-based song searching |
DAN_SELECTED |
A Dan challenge folder has been selected |
Inherits from Screen. Constructed with the screen name "song_select".
| Member | Type | Description |
|---|---|---|
state |
SongSelectState |
Current screen state |
player |
unique_ptr<SongSelectPlayer> |
The player's UI controller |
script |
unique_ptr<SongSelectScript> |
Lua script interface for skin customisation |
diff_fade_out |
FadeAnimation* |
Fade used when transitioning out of difficulty select |
game_transition |
optional<Transition> |
Fade-to-black transition when starting a song |
dan_transition |
optional<DanTransition> |
Slide transition when entering Dan mode |
diff_sort_selector |
optional<DiffSortSelect> |
The difficulty sort overlay, created on demand |
search_box |
optional<SearchBox> |
The song search overlay, created on demand |
select_timer |
unique_ptr<Timer> |
Countdown timer shown while a song is selected |
diff_select_timer |
unique_ptr<Timer> |
Countdown timer shown during difficulty selection |
indicator |
unique_ptr<Indicator> |
Play-count indicator displayed on screen |
coin_overlay |
CoinOverlay |
Global coin display |
allnet_indicator |
AllNetIcon |
Online connectivity indicator |
stats_future |
future<Statistics> |
Async task computing difficulty statistics for diff sort |
cached_stats |
Statistics |
Statistics stored once the future resolves |
song_num |
unique_ptr<SongNum> |
Total song count display |
shader |
ray::Shader |
Colour-transform shader applied during rendering |
last_diff_sort |
pair<int,int> |
The most recently applied difficulty sort filter |
void on_screen_start() override;Calls Screen::on_screen_start() to load skin textures and sounds, then starts background music and the entry voice clip. Loads the color shader, creates the SongSelectScript, initializes the global navigator with the configured song paths, launches the async stats_future task, creates the SongSelectPlayer, and sets up the timer, indicator, and song-count display objects.
Screens on_screen_end(Screens next_screen) override;Joins the navigator's loader thread, then delegates to Screen::on_screen_end which unloads all sounds, music, and textures.
std::optional<Screens> update() override;The main loop. Each frame it:
- Calls
Screen::update()for first-frame initialisation. - Advances the
diff_fade_outandscriptanimations. - Checks whether
stats_futurehas resolved; if so, cachesStatisticsand passes them to a newly createdDiffSortSelect. - Calls the appropriate
handle_input_*method for the current state. - Updates the
player,navigator, timers, and overlays. - Handles state transitions — if the player is ready and the voice has finished playing, a
game_transitionfade is started; once it completes the screen returnsScreens::GAME. - If the Back box is selected during
SONG_SELECTED, returns toBROWSING. - If the back key is pressed from
BROWSING, returnsScreens::ENTRY.
Returns std::nullopt while the screen is still active.
void handle_input(double current_ms); // private dispatcherRoutes input to the correct handler based on state.
void handle_input_browsing(double current_ms);Delegates to player->handle_input_browsing(). If the result signals SONG_SELECTED, SEARCHING, or DAN_SELECTED, the state is updated accordingly and the appropriate overlay is created. If the result signals entering a Difficulty Sort folder, awaiting_diff_sort is set and the stats_future task is launched.
void handle_input_selecting();Delegates to player->handle_input_selecting(). A return of BROWSING exits the difficulty selector and resets to browsing; a confirmed selection marks the player ready.
void handle_input_diff_sorting();Forwards left/right/select inputs to the DiffSortSelect overlay. On confirmation, calls navigator.apply_diff_sort() and returns to BROWSING. On cancel, calls navigator.cancel_diff_sort().
void handle_input_search();Feeds character input into the SearchBox. On confirmation, passes the search string to navigator and transitions to BROWSING.
void draw() override;Renders in the following order:
-
navigator.draw_background()— genre-based scrolling background. -
player->draw_background_diffs()— faded difficulty decorations behind the list. -
navigator.draw()— all visible boxes. -
script->draw_footer()— Lua-driven footer strip. -
navigator.draw_score_history()— score history panel for the open song. -
player->draw_selector()andplayer->draw()— difficulty selector and player character/nameplate. -
diff_sort_selector->draw()orsearch_box->draw()when those overlays are active. -
draw_overlays()— timers, indicators, coin overlay, allnet icon, and script overlays. -
game_transition->draw()ordan_transition->draw()when transitioning out.
void draw_overlays(); // protected, virtualDraws the select_timer, diff_select_timer, indicator, song_num, coin_overlay, allnet_indicator, and calls script->draw_overlays(state).
virtual void select_song(SongBox* song);Records the selected song path, hash, and genre in SessionData, adds the song to the recent list, and starts the game_transition fade. Overridden in the practice and 2P variants to set different session targets.
SongSelectScreen is subclassed by SongSelect2PScreen (two-player mode) and SongSelectPracticeScreen (practice mode). Both variants override select_song, handle_input, draw, get_game_screen_target, and several other methods to support their respective modes.
SongSelect2PScreen inherits from SongSelectScreen and adds a second SongSelectPlayer for P2. It uses the same "song_select" skin assets and routes to Screens::GAME_2P on confirmation.
| Member | Type | Description |
|---|---|---|
player_2 |
unique_ptr<SongSelectPlayer> |
P2's UI controller (difficulty selector, nameplate, character) |
void on_screen_start() override;Calls SongSelectScreen::on_screen_start(), then constructs player_2 for PlayerNum::P2.
std::optional<Screens> update() override;Mirrors the base update loop but advances both player and player_2 each frame. The transition to GAME_2P fires only when both player->is_ready and player_2->is_ready are true and both have selected a playable difficulty. If either player confirms the Back option, both players' ready and selected-song state are reset and the screen returns to BROWSING.
void handle_input_browsing(double current_ms) override;Runs P1's browsing input first. If P1 selects a song, P2's difficulty list is immediately populated with that song's difficulties (and vice versa), and the state advances to SONG_SELECTED. Non-song-select state changes (folder navigation, search, etc.) are propagated from whichever player triggered them.
void handle_input_selecting() override;Runs each player's difficulty-select input independently, skipping a player once is_ready is set.
void select_song(SongBox* song) override;Writes SessionData for both PlayerNum::P1 and PlayerNum::P2 — each with their own selected difficulty and hash — then starts the game_transition fade. A Loading.png from the song directory is added to the transition if present.
void draw() override;Draws background diffs for both players, then the navigator, footer script, and both players' difficulty selectors side-by-side. The is_half flag passed to each player's draw() is true when both players have selected the same difficulty, shrinking each selector to half-width to avoid overlap.
Building
libs
- animation
- audio
- config
- filesystem
- global_data
- input
- logging
- ray
- scores
- screen
- script
- song_parser
- text
- texture
- video
- webcam
libs/parsers
objects
objects/game
- player
- background
- gauge
- judgment
- combo
- branch_indicator
- ending_animations
- gogo_time
- fireworks
- song_info
- transition
- result_transition
- judge_counter
- score_counter
- score_counter_animation
- balloon_counter
- drumroll_counter
- kusudama_counter
- drum_hit_effect
- lane_hit_effect
- gauge_hit_effect
- combo_announce
- note_arc
objects/global
objects/title
objects/entry
objects/settings
objects/result
objects/song_select
- player
- navigator
- box_base
- box_song
- box_folder
- neiro
- modifier
- ura_switch
- diff_sort
- search_box
- dan_transition
- genre_bg
- score_history
- song_select_script
scenes