From b702c50d30a9d4ef43b7d0330c1e3d3c3a39273e Mon Sep 17 00:00:00 2001 From: Hans Kokx Date: Mon, 16 Mar 2026 16:10:12 +0100 Subject: [PATCH] Unified game screen and abstracted input Signed-off-by: Hans Kokx --- apps/wolf_3d_cli/bin/main.dart | 3 ++- .../lib/screens/difficulty_screen.dart | 6 ------ apps/wolf_3d_gui/lib/screens/game_screen.dart | 15 ++++++--------- .../lib/src/wolf_3d_engine_base.dart | 10 ++++++++-- packages/wolf_3d_engine/pubspec.yaml | 1 + packages/wolf_3d_renderer/lib/base_renderer.dart | 6 +----- .../lib/wolf_3d_ascii_renderer.dart | 8 ++------ .../lib/wolf_3d_flutter_renderer.dart | 8 ++------ packages/wolf_3d_renderer/pubspec.yaml | 1 - 9 files changed, 22 insertions(+), 36 deletions(-) diff --git a/apps/wolf_3d_cli/bin/main.dart b/apps/wolf_3d_cli/bin/main.dart index 657fee5..67dc157 100644 --- a/apps/wolf_3d_cli/bin/main.dart +++ b/apps/wolf_3d_cli/bin/main.dart @@ -53,6 +53,7 @@ void main() async { difficulty: Difficulty.bringEmOn, startingEpisode: 0, audio: cliAudio, + input: input, onGameWon: () { exitCleanly(0); print("YOU WON!"); @@ -108,7 +109,7 @@ void main() async { input.update(); - engine.tick(elapsed, input.currentInput); + engine.tick(elapsed); rasterizer.render(engine, buffer); rasterizer.finalizeFrame(); diff --git a/apps/wolf_3d_gui/lib/screens/difficulty_screen.dart b/apps/wolf_3d_gui/lib/screens/difficulty_screen.dart index df857f8..d31e9d4 100644 --- a/apps/wolf_3d_gui/lib/screens/difficulty_screen.dart +++ b/apps/wolf_3d_gui/lib/screens/difficulty_screen.dart @@ -32,12 +32,6 @@ class _DifficultyScreenState extends State { startingEpisode: Wolf3d.I.activeEpisode, audio: Wolf3d.I.audio, ), - // builder: (_) => WolfFlutterRenderer( - // Wolf3d.I.activeGame, - // difficulty: difficulty, - // startingEpisode: Wolf3d.I.activeEpisode, - // audio: Wolf3d.I.audio, - // ), ), ); } diff --git a/apps/wolf_3d_gui/lib/screens/game_screen.dart b/apps/wolf_3d_gui/lib/screens/game_screen.dart index 22c034a..abb4f6e 100644 --- a/apps/wolf_3d_gui/lib/screens/game_screen.dart +++ b/apps/wolf_3d_gui/lib/screens/game_screen.dart @@ -27,19 +27,22 @@ class GameScreen extends StatefulWidget { class _GameScreenState extends State { late final WolfEngine _engine; - final Wolf3dInput _inputManager = Wolf3dFlutterInput(); + late final Wolf3dInput _input; bool _useAsciiMode = false; @override void initState() { super.initState(); + _input = Wolf3dFlutterInput(); + // The Host Screen owns the engine lifecycle _engine = WolfEngine( data: widget.data, difficulty: widget.difficulty, startingEpisode: widget.startingEpisode, audio: widget.audio, + input: _input, onGameWon: () => Navigator.of(context).pop(), ); @@ -53,14 +56,8 @@ class _GameScreenState extends State { children: [ // Render the active view _useAsciiMode - ? WolfAsciiRenderer( - engine: _engine, - inputManager: _inputManager, - ) - : WolfFlutterRenderer( - engine: _engine, - inputManager: _inputManager, - ), + ? WolfAsciiRenderer(engine: _engine) + : WolfFlutterRenderer(engine: _engine), // Invisible listener to trap the 'Tab' key and swap renderers Focus( diff --git a/packages/wolf_3d_engine/lib/src/wolf_3d_engine_base.dart b/packages/wolf_3d_engine/lib/src/wolf_3d_engine_base.dart index ddd6fc0..0510414 100644 --- a/packages/wolf_3d_engine/lib/src/wolf_3d_engine_base.dart +++ b/packages/wolf_3d_engine/lib/src/wolf_3d_engine_base.dart @@ -3,6 +3,7 @@ import 'dart:math' as math; import 'package:wolf_3d_data_types/wolf_3d_data_types.dart'; import 'package:wolf_3d_engine/wolf_3d_engine.dart'; import 'package:wolf_3d_entities/wolf_3d_entities.dart'; +import 'package:wolf_3d_input/wolf_3d_input.dart'; class WolfEngine { WolfEngine({ @@ -11,6 +12,7 @@ class WolfEngine { required this.startingEpisode, required this.onGameWon, required this.audio, + required this.input, }) : doorManager = DoorManager( onPlaySound: (sfxId) => audio.playSoundEffect(sfxId), ); @@ -28,6 +30,7 @@ class WolfEngine { // Managers final DoorManager doorManager; + final Wolf3dInput input; final PushwallManager pushwallManager = PushwallManager(); @@ -51,12 +54,15 @@ class WolfEngine { } // Expect standard Dart Duration. The host app is responsible for the loop. - void tick(Duration elapsed, EngineInput input) { + void tick(Duration elapsed) { if (!isInitialized) return; _timeAliveMs += elapsed.inMilliseconds; - final inputResult = _processInputs(elapsed, input); + input.update(); + final currentInput = input.currentInput; + + final inputResult = _processInputs(elapsed, currentInput); doorManager.update(elapsed); pushwallManager.update(elapsed, currentLevel); diff --git a/packages/wolf_3d_engine/pubspec.yaml b/packages/wolf_3d_engine/pubspec.yaml index 44a7cb3..d3a2d64 100644 --- a/packages/wolf_3d_engine/pubspec.yaml +++ b/packages/wolf_3d_engine/pubspec.yaml @@ -12,6 +12,7 @@ dependencies: wolf_3d_data_types: any wolf_3d_entities: any wolf_3d_data: any + wolf_3d_input: any dev_dependencies: lints: ^6.0.0 diff --git a/packages/wolf_3d_renderer/lib/base_renderer.dart b/packages/wolf_3d_renderer/lib/base_renderer.dart index 33419cf..fbfbacd 100644 --- a/packages/wolf_3d_renderer/lib/base_renderer.dart +++ b/packages/wolf_3d_renderer/lib/base_renderer.dart @@ -1,16 +1,13 @@ import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:wolf_3d_engine/wolf_3d_engine.dart'; -import 'package:wolf_3d_input/wolf_3d_input.dart'; // 1. The widget now only requires the engine! abstract class BaseWolfRenderer extends StatefulWidget { final WolfEngine engine; - final Wolf3dInput inputManager; const BaseWolfRenderer({ required this.engine, - required this.inputManager, super.key, }); } @@ -37,9 +34,8 @@ abstract class BaseWolfRendererState Duration delta = elapsed - _lastTick; _lastTick = elapsed; - widget.inputManager.update(); // Tick the shared engine - widget.engine.tick(delta, widget.inputManager.currentInput); + widget.engine.tick(delta); performRender(); } diff --git a/packages/wolf_3d_renderer/lib/wolf_3d_ascii_renderer.dart b/packages/wolf_3d_renderer/lib/wolf_3d_ascii_renderer.dart index fa4b02f..2e7cc53 100644 --- a/packages/wolf_3d_renderer/lib/wolf_3d_ascii_renderer.dart +++ b/packages/wolf_3d_renderer/lib/wolf_3d_ascii_renderer.dart @@ -2,14 +2,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:wolf_3d_data_types/wolf_3d_data_types.dart'; import 'package:wolf_3d_engine/wolf_3d_engine.dart'; -import 'package:wolf_3d_flutter/wolf_3d_input_flutter.dart'; -import 'package:wolf_3d_input/wolf_3d_input.dart'; import 'package:wolf_3d_renderer/base_renderer.dart'; class WolfAsciiRenderer extends BaseWolfRenderer { const WolfAsciiRenderer({ required super.engine, - required super.inputManager, super.key, }); @@ -19,7 +16,6 @@ class WolfAsciiRenderer extends BaseWolfRenderer { class _WolfAsciiRendererState extends State with SingleTickerProviderStateMixin { - final Wolf3dInput inputManager = Wolf3dFlutterInput(); late final WolfEngine engine; late Ticker _gameLoop; final FocusNode _focusNode = FocusNode(); @@ -39,6 +35,7 @@ class _WolfAsciiRendererState extends State difficulty: widget.engine.difficulty, startingEpisode: widget.engine.startingEpisode, audio: widget.engine.audio, + input: widget.engine.input, onGameWon: () { Navigator.of(context).pop(); }, @@ -56,8 +53,7 @@ class _WolfAsciiRendererState extends State Duration delta = elapsed - _lastTick; _lastTick = elapsed; - inputManager.update(); - engine.tick(delta, inputManager.currentInput); + engine.tick(delta); // Calculate frame synchronously and trigger UI rebuild setState(() { diff --git a/packages/wolf_3d_renderer/lib/wolf_3d_flutter_renderer.dart b/packages/wolf_3d_renderer/lib/wolf_3d_flutter_renderer.dart index 04a3afe..1f86a4e 100644 --- a/packages/wolf_3d_renderer/lib/wolf_3d_flutter_renderer.dart +++ b/packages/wolf_3d_renderer/lib/wolf_3d_flutter_renderer.dart @@ -4,14 +4,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:wolf_3d_data_types/wolf_3d_data_types.dart'; import 'package:wolf_3d_engine/wolf_3d_engine.dart'; -import 'package:wolf_3d_flutter/wolf_3d_input_flutter.dart'; -import 'package:wolf_3d_input/wolf_3d_input.dart'; import 'package:wolf_3d_renderer/base_renderer.dart'; class WolfFlutterRenderer extends BaseWolfRenderer { const WolfFlutterRenderer({ required super.engine, - required super.inputManager, super.key, }); @@ -21,7 +18,6 @@ class WolfFlutterRenderer extends BaseWolfRenderer { class _WolfFlutterRendererState extends State with SingleTickerProviderStateMixin { - final Wolf3dInput inputManager = Wolf3dFlutterInput(); late final WolfEngine engine; late Ticker _gameLoop; final FocusNode _focusNode = FocusNode(); @@ -45,6 +41,7 @@ class _WolfFlutterRendererState extends State difficulty: widget.engine.difficulty, startingEpisode: widget.engine.startingEpisode, audio: widget.engine.audio, + input: widget.engine.input, onGameWon: () { Navigator.of(context).pop(); }, @@ -62,8 +59,7 @@ class _WolfFlutterRendererState extends State Duration delta = elapsed - _lastTick; _lastTick = elapsed; - inputManager.update(); - engine.tick(delta, inputManager.currentInput); + engine.tick(delta); // Only start rendering a new frame if the previous one is finished. // This prevents memory leaks and stuttering on lower-end hardware! diff --git a/packages/wolf_3d_renderer/pubspec.yaml b/packages/wolf_3d_renderer/pubspec.yaml index e5eed9d..70b229a 100644 --- a/packages/wolf_3d_renderer/pubspec.yaml +++ b/packages/wolf_3d_renderer/pubspec.yaml @@ -15,7 +15,6 @@ dependencies: wolf_3d_data_types: any wolf_3d_engine: any wolf_3d_entities: any - wolf_3d_input: any wolf_3d_flutter: any dev_dependencies: