Refactor menu rendering and improve projection sampling
- Updated AsciiRasterizer to support game and episode selection menus with improved layout and cursor handling. - Enhanced SixelRasterizer and SoftwareRasterizer to modularize menu drawing logic for game and episode selection. - Introduced new methods for drawing menus and applying fade effects across rasterizers. - Adjusted wall texture sampling in Rasterizer to anchor to projection height center for consistent rendering. - Added tests for wall texture sampling behavior to ensure legacy compatibility and new functionality. - Modified Flutter audio adapter to use nullable access for active game and adjusted game selection logic in the main class. - Cleaned up input handling in Wolf3dFlutterInput by removing unused menu tap variables. Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -40,12 +40,15 @@ class Wolf3d {
|
||||
return _activeGame!;
|
||||
}
|
||||
|
||||
/// Nullable access to the selected game, useful during menu bootstrap.
|
||||
WolfensteinData? get maybeActiveGame => _activeGame;
|
||||
|
||||
// Episode selection lives on the facade so menus can configure gameplay
|
||||
// before constructing a new engine instance.
|
||||
int _activeEpisode = 0;
|
||||
int? _activeEpisode;
|
||||
|
||||
/// Index of the episode currently selected in the UI flow.
|
||||
int get activeEpisode => _activeEpisode;
|
||||
int? get activeEpisode => _activeEpisode;
|
||||
|
||||
Difficulty? _activeDifficulty;
|
||||
|
||||
@@ -80,16 +83,30 @@ class Wolf3d {
|
||||
/// engine so it can be retrieved via [engine]. [onGameWon] is invoked when
|
||||
/// the player completes the final level of the episode.
|
||||
WolfEngine launchEngine({required void Function() onGameWon}) {
|
||||
if (availableGames.isEmpty) {
|
||||
throw StateError(
|
||||
'No game data was discovered. Add game files before launching the engine.',
|
||||
);
|
||||
}
|
||||
|
||||
_engine = WolfEngine(
|
||||
data: activeGame,
|
||||
availableGames: availableGames,
|
||||
difficulty: _activeDifficulty,
|
||||
startingEpisode: _activeEpisode,
|
||||
frameBuffer: FrameBuffer(320, 200),
|
||||
menuBackgroundRgb: menuBackgroundRgb,
|
||||
menuPanelRgb: menuPanelRgb,
|
||||
audio: audio,
|
||||
engineAudio: audio,
|
||||
input: input,
|
||||
onGameWon: onGameWon,
|
||||
onMenuExit: onGameWon,
|
||||
onGameSelected: (game) {
|
||||
_activeGame = game;
|
||||
audio.activeGame = game;
|
||||
},
|
||||
onEpisodeSelected: (episodeIndex) {
|
||||
_activeEpisode = episodeIndex;
|
||||
},
|
||||
);
|
||||
_engine!.init();
|
||||
return _engine!;
|
||||
@@ -107,8 +124,18 @@ class Wolf3d {
|
||||
_activeEpisode = episodeIndex;
|
||||
}
|
||||
|
||||
/// Clears any selected episode so menu flow starts fresh.
|
||||
void clearActiveEpisode() {
|
||||
_activeEpisode = null;
|
||||
}
|
||||
|
||||
/// Convenience access to the active episode's level list.
|
||||
List<WolfLevel> get levels => activeGame.episodes[activeEpisode].levels;
|
||||
List<WolfLevel> get levels {
|
||||
if (_activeEpisode == null) {
|
||||
throw StateError('No active episode selected.');
|
||||
}
|
||||
return activeGame.episodes[_activeEpisode!].levels;
|
||||
}
|
||||
|
||||
/// Convenience access to the active game's wall textures.
|
||||
List<Sprite> get walls => activeGame.walls;
|
||||
@@ -141,6 +168,7 @@ class Wolf3d {
|
||||
}
|
||||
|
||||
_activeGame = game;
|
||||
_activeEpisode = null;
|
||||
audio.activeGame = game;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user