/// Active gameplay screen for the Flutter host. library; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:wolf_3d_dart/wolf_3d_data_types.dart'; import 'package:wolf_3d_dart/wolf_3d_engine.dart'; import 'package:wolf_3d_flutter/wolf_3d_input_flutter.dart'; import 'package:wolf_3d_renderer/wolf_3d_ascii_renderer.dart'; import 'package:wolf_3d_renderer/wolf_3d_flutter_renderer.dart'; /// Owns a [WolfEngine] instance and exposes renderer/input integrations to Flutter. class GameScreen extends StatefulWidget { /// Fully parsed game data for the selected version. final WolfensteinData data; /// Difficulty applied when creating the engine session. final Difficulty difficulty; /// Episode index used as the starting world. final int startingEpisode; /// Shared audio backend reused across menu and gameplay screens. final EngineAudio audio; /// Flutter input adapter that translates widget events into engine input. final Wolf3dFlutterInput input; /// Creates a gameplay screen with the supplied game session configuration. const GameScreen({ required this.data, required this.difficulty, required this.startingEpisode, required this.audio, required this.input, super.key, }); @override State createState() => _GameScreenState(); } class _GameScreenState extends State { late final WolfEngine _engine; bool _useAsciiMode = false; @override void initState() { super.initState(); _engine = WolfEngine( data: widget.data, difficulty: widget.difficulty, startingEpisode: widget.startingEpisode, frameBuffer: FrameBuffer(320, 200), audio: widget.audio, input: widget.input, onGameWon: () => Navigator.of(context).pop(), ); _engine.init(); } @override Widget build(BuildContext context) { return Scaffold( body: Listener( onPointerDown: widget.input.onPointerDown, onPointerUp: widget.input.onPointerUp, onPointerMove: widget.input.onPointerMove, onPointerHover: widget.input.onPointerMove, child: Stack( children: [ // Keep both renderers behind the same engine so mode switching does // not reset level state or audio playback. _useAsciiMode ? WolfAsciiRenderer(engine: _engine) : WolfFlutterRenderer(engine: _engine), if (!_engine.isInitialized) Container( color: Colors.black, child: const Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ CircularProgressIndicator(color: Colors.teal), SizedBox(height: 20), Text( "GET PSYCHED!", style: TextStyle( color: Colors.teal, fontFamily: 'monospace', ), ), ], ), ), ), // Tab toggles the renderer implementation for quick visual debugging. Focus( autofocus: true, onKeyEvent: (node, event) { if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.tab) { setState(() => _useAsciiMode = !_useAsciiMode); return KeyEventResult.handled; } return KeyEventResult.ignored; }, child: const SizedBox.shrink(), ), // A second full-screen overlay keeps the presentation simple while // the engine is still warming up or decoding the first frame. if (!_engine.isInitialized) Container( color: Colors.black, child: const Center( child: CircularProgressIndicator(color: Colors.teal), ), ), Positioned( top: 16, right: 16, child: Text( 'TAB: Swap Renderer', style: TextStyle(color: Colors.white.withValues(alpha: 0.5)), ), ), ], ), ), ); } }