From ede2c3fa31cd4c30ecb208eb9c21ed9184476966 Mon Sep 17 00:00:00 2001 From: Hans Kokx Date: Mon, 16 Mar 2026 14:47:10 +0100 Subject: [PATCH] Fixed ASCII rasterizer, abstracted out input and audio, and created CLI client (untested) Signed-off-by: Hans Kokx --- bin/cli_main.dart | 96 ++++++++++++++ lib/screens/difficulty_screen.dart | 4 +- .../lib/src}/ascii_rasterizer.dart | 118 +++++++++++------- .../wolf_3d_engine/lib/src/rasterizer.dart | 19 +++ .../lib/src/software_rasterizer.dart | 10 +- .../wolf_3d_engine/lib/wolf_3d_engine.dart | 1 + .../lib/wolf_3d_input_flutter.dart | 38 ++++++ packages/wolf_3d_flutter/pubspec.yaml | 2 + packages/wolf_3d_input/lib/src/cli_input.dart | 47 +++++++ .../wolf_3d_input/lib/src/wolf_3d_input.dart | 27 ++++ packages/wolf_3d_input/lib/wolf_3d_input.dart | 60 +-------- packages/wolf_3d_input/pubspec.yaml | 45 ------- .../wolf_3d_renderer/analysis_options.yaml | 3 + .../lib/wolf_3d_ascii_renderer.dart | 10 +- .../lib/wolf_3d_renderer.dart | 3 +- packages/wolf_3d_renderer/pubspec.yaml | 1 + .../lib/src/silent_renderer.dart | 34 +++++ packages/wolf_3d_synth/lib/wolf_3d_synth.dart | 1 + 18 files changed, 353 insertions(+), 166 deletions(-) create mode 100644 bin/cli_main.dart rename packages/{wolf_3d_renderer/lib => wolf_3d_engine/lib/src}/ascii_rasterizer.dart (76%) create mode 100644 packages/wolf_3d_flutter/lib/wolf_3d_input_flutter.dart create mode 100644 packages/wolf_3d_input/lib/src/cli_input.dart create mode 100644 packages/wolf_3d_input/lib/src/wolf_3d_input.dart create mode 100644 packages/wolf_3d_synth/lib/src/silent_renderer.dart diff --git a/bin/cli_main.dart b/bin/cli_main.dart new file mode 100644 index 0000000..5138312 --- /dev/null +++ b/bin/cli_main.dart @@ -0,0 +1,96 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:wolf_3d_data/wolf_3d_data.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_input/wolf_3d_input.dart'; +import 'package:wolf_3d_synth/wolf_3d_synth.dart'; + +// Helper to gracefully exit and restore the terminal +void exitCleanly(int code) { + stdout.write('\x1b[0m'); // Reset color + stdout.write('\x1b[2J\x1b[H'); // Clear screen + stdout.write('\x1b[?25h'); // SHOW the cursor again + exit(code); +} + +void main() async { + stdin.echoMode = false; + stdin.lineMode = false; + + // HIDE the blinking cursor and clear the screen to prep the canvas + stdout.write('\x1b[?25l\x1b[2J'); + + // ... (Keep your game discovery and instantiation exactly the same) ... + final availableGames = await WolfensteinLoader.discover( + directoryPath: 'assets/shareware', + recursive: true, + ); + final data = availableGames.values.first; + + final input = CliInput(); + final cliAudio = CliSilentAudio(); + + final engine = WolfEngine( + data: data, + difficulty: Difficulty.bringEmOn, + startingEpisode: 0, + audio: cliAudio, + onGameWon: () { + exitCleanly(0); + print("YOU WON!"); + }, + ); + + final rasterizer = AsciiRasterizer(); + final buffer = FrameBuffer(120, 40); + + engine.init(); + + stdin.listen((List bytes) { + if (bytes.contains(113) || bytes.contains(27)) { + exitCleanly(0); + } + input.handleKey(bytes); + }); + + Stopwatch stopwatch = Stopwatch()..start(); + Duration lastTick = Duration.zero; + + Timer.periodic(const Duration(milliseconds: 33), (timer) { + // 1. Terminal Size Safety Check + if (stdout.hasTerminal) { + if (stdout.terminalColumns < 120 || stdout.terminalLines < 40) { + // Clear the screen and print the warning at the top left + stdout.write('\x1b[2J\x1b[H'); + stdout.write('\x1b[31m[ ERROR ] TERMINAL TOO SMALL\x1b[0m\n\n'); + stdout.write( + 'Wolfenstein 3D requires a minimum resolution of 120x40.\n', + ); + stdout.write( + 'Current size: \x1b[33m${stdout.terminalColumns}x${stdout.terminalLines}\x1b[0m\n\n', + ); + stdout.write('Please resize your window to resume the game...'); + + // Prevent the engine from simulating a massive time jump when resumed + lastTick = stopwatch.elapsed; + return; + } + } + + // 2. Normal Game Loop + Duration currentTick = stopwatch.elapsed; + Duration elapsed = currentTick - lastTick; + lastTick = currentTick; + + // Move cursor to top-left (0,0) before drawing the frame + stdout.write('\x1b[H'); + + engine.tick(elapsed, input.currentInput); + rasterizer.render(engine, buffer); + rasterizer.finalizeFrame(); + + stdout.write(rasterizer.toAnsiString()); + }); +} diff --git a/lib/screens/difficulty_screen.dart b/lib/screens/difficulty_screen.dart index fd895f6..0113d8e 100644 --- a/lib/screens/difficulty_screen.dart +++ b/lib/screens/difficulty_screen.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:wolf_3d_data_types/wolf_3d_data_types.dart'; import 'package:wolf_3d_flutter/wolf_3d.dart'; -import 'package:wolf_3d_renderer/wolf_3d_renderer.dart'; +import 'package:wolf_3d_renderer/wolf_3d_ascii_renderer.dart'; class DifficultyScreen extends StatefulWidget { const DifficultyScreen({ @@ -26,7 +26,7 @@ class _DifficultyScreenState extends State { Navigator.of(context).pushReplacement( MaterialPageRoute( - builder: (_) => WolfRenderer( + builder: (_) => WolfAsciiRenderer( Wolf3d.I.activeGame, difficulty: difficulty, startingEpisode: Wolf3d.I.activeEpisode, diff --git a/packages/wolf_3d_renderer/lib/ascii_rasterizer.dart b/packages/wolf_3d_engine/lib/src/ascii_rasterizer.dart similarity index 76% rename from packages/wolf_3d_renderer/lib/ascii_rasterizer.dart rename to packages/wolf_3d_engine/lib/src/ascii_rasterizer.dart index bb51770..76199f4 100644 --- a/packages/wolf_3d_renderer/lib/ascii_rasterizer.dart +++ b/packages/wolf_3d_engine/lib/src/ascii_rasterizer.dart @@ -1,6 +1,5 @@ import 'dart:math' as math; -import 'package:flutter/material.dart'; import 'package:wolf_3d_data_types/wolf_3d_data_types.dart'; import 'package:wolf_3d_engine/wolf_3d_engine.dart'; @@ -34,8 +33,17 @@ abstract class AsciiThemes { class ColoredChar { final String char; - final Color color; - ColoredChar(this.char, this.color); + final int rawColor; // Stores the AABBGGRR integer from the palette + + ColoredChar(this.char, this.rawColor); + + // Safely extract the exact RGB channels regardless of framework + int get r => rawColor & 0xFF; + int get g => (rawColor >> 8) & 0xFF; + int get b => (rawColor >> 16) & 0xFF; + + // Outputs standard AARRGGBB for Flutter's Color(int) constructor + int get argb => (0xFF000000) | (r << 16) | (g << 8) | b; } class AsciiRasterizer extends Rasterizer { @@ -49,38 +57,29 @@ class AsciiRasterizer extends Rasterizer { @override double get aspectMultiplier => 0.6; - // --- HELPER: Color Conversion --- - Color _vgaToColor(int vgaColor) { - int r = vgaColor & 0xFF; - int g = (vgaColor >> 8) & 0xFF; - int b = (vgaColor >> 16) & 0xFF; - - return Color.fromARGB(255, r, g, b); - } - // Intercept the base render call to initialize our text grid @override dynamic render(WolfEngine engine, FrameBuffer buffer) { _engine = engine; _screen = List.generate( buffer.height, - (_) => List.filled(buffer.width, ColoredChar(' ', Colors.black)), + (_) => + List.filled(buffer.width, ColoredChar(' ', ColorPalette.vga32Bit[0])), ); return super.render(engine, buffer); } @override void prepareFrame(WolfEngine engine) { - final Color ceilingColor = _vgaToColor(ColorPalette.vga32Bit[25]); - final Color floorColor = _vgaToColor(ColorPalette.vga32Bit[29]); + // Just grab the raw ints! + final int ceilingColor = ColorPalette.vga32Bit[25]; + final int floorColor = ColorPalette.vga32Bit[29]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (y < viewHeight / 2) { - // Fetch the solid character from the theme _screen[y][x] = ColoredChar(activeTheme.solid, ceilingColor); } else if (y < viewHeight) { - // Fetch the solid character from the theme _screen[y][x] = ColoredChar(activeTheme.solid, floorColor); } } @@ -98,7 +97,7 @@ class AsciiRasterizer extends Rasterizer { double perpWallDist, int side, ) { - double brightness = (4.0 / (perpWallDist + 1.0)); + double brightness = calculateDepthBrightness(perpWallDist); String wallChar = activeTheme.getByBrightness(brightness); for (int y = drawStart; y < drawEnd; y++) { @@ -107,16 +106,11 @@ class AsciiRasterizer extends Rasterizer { int texY = (relativeY * 64).toInt().clamp(0, 63); int colorByte = texture.pixels[texX * 64 + texY]; - Color pixelColor = _vgaToColor(ColorPalette.vga32Bit[colorByte]); + int pixelColor = ColorPalette.vga32Bit[colorByte]; // Raw int - // Faux directional lighting + // Faux directional lighting using your new base class method if (side == 1) { - pixelColor = Color.fromARGB( - 255, - (pixelColor.r * 0.9).toInt().clamp(0, 255), - (pixelColor.g * 0.9).toInt().clamp(0, 255), - (pixelColor.b * 0.9).toInt().clamp(0, 255), - ); + pixelColor = shadeColor(pixelColor); } _screen[y][x] = ColoredChar(wallChar, pixelColor); @@ -133,7 +127,8 @@ class AsciiRasterizer extends Rasterizer { int texX, double transformY, ) { - double brightness = (4.0 / (transformY + 1.0)).clamp(0.0, 1.0); + // Ask the base class for the depth brightness + double brightness = calculateDepthBrightness(transformY); String spriteChar = activeTheme.getByBrightness(brightness); for ( @@ -148,7 +143,7 @@ class AsciiRasterizer extends Rasterizer { if (colorByte != 255) { _screen[y][stripeX] = ColoredChar( spriteChar, - _vgaToColor(ColorPalette.vga32Bit[colorByte]), + ColorPalette.vga32Bit[colorByte], ); } } @@ -180,7 +175,7 @@ class AsciiRasterizer extends Rasterizer { if (drawX >= 0 && drawX < width && drawY >= 0 && drawY < viewHeight) { _screen[drawY][drawX] = ColoredChar( activeTheme.solid, - _vgaToColor(ColorPalette.vga32Bit[colorByte]), + ColorPalette.vga32Bit[colorByte], ); } } @@ -310,10 +305,9 @@ class AsciiRasterizer extends Rasterizer { int colorByte = image.pixels[index]; if (colorByte != 255) { - // Using '█' for UI to make it look solid _screen[drawY][drawX] = ColoredChar( activeTheme.solid, - _vgaToColor(ColorPalette.vga32Bit[colorByte]), + ColorPalette.vga32Bit[colorByte], ); } } @@ -322,7 +316,6 @@ class AsciiRasterizer extends Rasterizer { } // --- DAMAGE FLASH --- - void _applyDamageFlash() { double intensity = _engine.player.damageFlash; int redBoost = (150 * intensity).toInt(); @@ -330,24 +323,55 @@ class AsciiRasterizer extends Rasterizer { for (int y = 0; y < viewHeight; y++) { for (int x = 0; x < width; x++) { - Color c = _screen[y][x].color; + ColoredChar cell = _screen[y][x]; - int r = ((c.r * 255).round().clamp(0, 255) + redBoost).clamp(0, 255); - int g = ((c.g * 255).round().clamp(0, 255) * colorDrop).toInt().clamp( - 0, - 255, - ); - int b = ((c.b * 255).round().clamp(0, 255) * colorDrop).toInt().clamp( - 0, - 255, - ); + // Use our safe getters! + int r = cell.r; + int g = cell.g; + int b = cell.b; - // Replace the existing character with a red-tinted version - _screen[y][x] = ColoredChar( - _screen[y][x].char, - Color.fromARGB(255, r, g, b), - ); + r = (r + redBoost).clamp(0, 255); + g = (g * colorDrop).toInt().clamp(0, 255); + b = (b * colorDrop).toInt().clamp(0, 255); + + // Pack back into the native AABBGGRR format that ColoredChar expects + int newRawColor = (0xFF000000) | (b << 16) | (g << 8) | r; + + _screen[y][x] = ColoredChar(cell.char, newRawColor); } } } + + /// Converts the current frame to a single printable ANSI string + String toAnsiString() { + StringBuffer buffer = StringBuffer(); + + int lastR = -1; + int lastG = -1; + int lastB = -1; + + for (int y = 0; y < _screen.length; y++) { + List row = _screen[y]; + for (ColoredChar cell in row) { + if (cell.r != lastR || cell.g != lastG || cell.b != lastB) { + buffer.write('\x1b[38;2;${cell.r};${cell.g};${cell.b}m'); + lastR = cell.r; + lastG = cell.g; + lastB = cell.b; + } + buffer.write(cell.char); + } + + // Only print a newline if we are NOT on the very last row. + // This stops the terminal from scrolling down! + if (y < _screen.length - 1) { + buffer.write('\n'); + } + } + + // Reset the terminal color at the very end + buffer.write('\x1b[0m'); + + return buffer.toString(); + } } diff --git a/packages/wolf_3d_engine/lib/src/rasterizer.dart b/packages/wolf_3d_engine/lib/src/rasterizer.dart index edf129a..2ee4522 100644 --- a/packages/wolf_3d_engine/lib/src/rasterizer.dart +++ b/packages/wolf_3d_engine/lib/src/rasterizer.dart @@ -80,6 +80,17 @@ abstract class Rasterizer { /// Return the finished frame (e.g., the FrameBuffer itself, or an ASCII list). dynamic finalizeFrame(); + // =========================================================================== + // SHARED LIGHTING MATH + // =========================================================================== + + /// Calculates depth-based lighting falloff (0.0 to 1.0). + /// While the original Wolf3D didn't use depth fog, this provides a great + /// atmospheric effect for custom renderers (like ASCII dithering). + double calculateDepthBrightness(double distance) { + return (10.0 / (distance + 2.0)).clamp(0.0, 1.0); + } + // =========================================================================== // CORE ENGINE MATH (Shared across all renderers) // =========================================================================== @@ -359,4 +370,12 @@ abstract class Rasterizer { } } } + + /// Darkens a 32-bit 0xAABBGGRR color by roughly 30% without touching Alpha + int shadeColor(int color) { + int r = (color & 0xFF) * 7 ~/ 10; + int g = ((color >> 8) & 0xFF) * 7 ~/ 10; + int b = ((color >> 16) & 0xFF) * 7 ~/ 10; + return (0xFF000000) | (b << 16) | (g << 8) | r; + } } diff --git a/packages/wolf_3d_engine/lib/src/software_rasterizer.dart b/packages/wolf_3d_engine/lib/src/software_rasterizer.dart index 99450f3..2739a8f 100644 --- a/packages/wolf_3d_engine/lib/src/software_rasterizer.dart +++ b/packages/wolf_3d_engine/lib/src/software_rasterizer.dart @@ -51,7 +51,7 @@ class SoftwareRasterizer extends Rasterizer { // Darken Y-side walls for faux directional lighting if (side == 1) { - pixelColor = _shadeColor(pixelColor); + pixelColor = shadeColor(pixelColor); } _buffer.pixels[y * width + x] = pixelColor; @@ -235,14 +235,6 @@ class SoftwareRasterizer extends Rasterizer { } } - /// Darkens a 32-bit 0xAABBGGRR color by roughly 30% without touching Alpha - int _shadeColor(int color) { - int r = (color & 0xFF) * 7 ~/ 10; - int g = ((color >> 8) & 0xFF) * 7 ~/ 10; - int b = ((color >> 16) & 0xFF) * 7 ~/ 10; - return (0xFF000000) | (b << 16) | (g << 8) | r; - } - /// Tints the top 80% of the screen red based on player.damageFlash intensity void _applyDamageFlash() { // Grab the intensity (0.0 to 1.0) diff --git a/packages/wolf_3d_engine/lib/wolf_3d_engine.dart b/packages/wolf_3d_engine/lib/wolf_3d_engine.dart index 58ebdfd..ec9c694 100644 --- a/packages/wolf_3d_engine/lib/wolf_3d_engine.dart +++ b/packages/wolf_3d_engine/lib/wolf_3d_engine.dart @@ -3,6 +3,7 @@ /// More dartdocs go here. library; +export 'src/ascii_rasterizer.dart'; export 'src/engine_audio.dart'; export 'src/engine_input.dart'; export 'src/managers/door_manager.dart'; diff --git a/packages/wolf_3d_flutter/lib/wolf_3d_input_flutter.dart b/packages/wolf_3d_flutter/lib/wolf_3d_input_flutter.dart new file mode 100644 index 0000000..fedfaa6 --- /dev/null +++ b/packages/wolf_3d_flutter/lib/wolf_3d_input_flutter.dart @@ -0,0 +1,38 @@ +import 'package:flutter/services.dart'; +import 'package:wolf_3d_entities/wolf_3d_entities.dart'; +import 'package:wolf_3d_input/wolf_3d_input.dart'; + +class Wolf3dFlutterInput extends Wolf3dInput { + Set _previousKeys = {}; + + @override + void update() { + final pressedKeys = HardwareKeyboard.instance.logicalKeysPressed; + final newlyPressedKeys = pressedKeys.difference(_previousKeys); + + isMovingForward = pressedKeys.contains(LogicalKeyboardKey.keyW); + isMovingBackward = pressedKeys.contains(LogicalKeyboardKey.keyS); + isTurningLeft = pressedKeys.contains(LogicalKeyboardKey.keyA); + isTurningRight = pressedKeys.contains(LogicalKeyboardKey.keyD); + + isInteracting = newlyPressedKeys.contains(LogicalKeyboardKey.space); + + isFiring = + pressedKeys.contains(LogicalKeyboardKey.controlLeft) && + !pressedKeys.contains(LogicalKeyboardKey.space); + + requestedWeapon = null; + for (final LogicalKeyboardKey key in newlyPressedKeys) { + if (key == LogicalKeyboardKey.digit1) requestedWeapon = WeaponType.knife; + if (key == LogicalKeyboardKey.digit2) requestedWeapon = WeaponType.pistol; + if (key == LogicalKeyboardKey.digit3) { + requestedWeapon = WeaponType.machineGun; + } + if (key == LogicalKeyboardKey.digit4) { + requestedWeapon = WeaponType.chainGun; + } + } + + _previousKeys = Set.from(pressedKeys); + } +} diff --git a/packages/wolf_3d_flutter/pubspec.yaml b/packages/wolf_3d_flutter/pubspec.yaml index 885f362..358f421 100644 --- a/packages/wolf_3d_flutter/pubspec.yaml +++ b/packages/wolf_3d_flutter/pubspec.yaml @@ -16,6 +16,8 @@ dependencies: wolf_3d_data_types: any wolf_3d_synth: any wolf_3d_engine: any + wolf_3d_entities: any + wolf_3d_input: any dev_dependencies: flutter_test: diff --git a/packages/wolf_3d_input/lib/src/cli_input.dart b/packages/wolf_3d_input/lib/src/cli_input.dart new file mode 100644 index 0000000..afbf997 --- /dev/null +++ b/packages/wolf_3d_input/lib/src/cli_input.dart @@ -0,0 +1,47 @@ +import 'package:wolf_3d_entities/wolf_3d_entities.dart'; +import 'package:wolf_3d_input/src/wolf_3d_input.dart'; + +class CliInput extends Wolf3dInput { + // Pending buffer for asynchronous stdin events + bool _pForward = false; + bool _pBackward = false; + bool _pLeft = false; + bool _pRight = false; + bool _pFire = false; + bool _pInteract = false; + WeaponType? _pWeapon; + + /// Call this directly from the stdin listener to queue inputs for the next frame + void handleKey(List bytes) { + String char = String.fromCharCodes(bytes).toLowerCase(); + + if (char == 'w') _pForward = true; + if (char == 's') _pBackward = true; + if (char == 'a') _pLeft = true; + if (char == 'd') _pRight = true; + + if (char == 'f' || char == ' ') _pFire = true; + if (char == 'e') _pInteract = true; + + if (char == '1') _pWeapon = WeaponType.knife; + if (char == '2') _pWeapon = WeaponType.pistol; + if (char == '3') _pWeapon = WeaponType.machineGun; + if (char == '4') _pWeapon = WeaponType.chainGun; + } + + @override + void update() { + // 1. Move pending inputs to the active state + isMovingForward = _pForward; + isMovingBackward = _pBackward; + isTurningLeft = _pLeft; + isTurningRight = _pRight; + isFiring = _pFire; + isInteracting = _pInteract; + requestedWeapon = _pWeapon; + + // 2. Wipe the pending slate clean for the next frame + _pForward = _pBackward = _pLeft = _pRight = _pFire = _pInteract = false; + _pWeapon = null; + } +} diff --git a/packages/wolf_3d_input/lib/src/wolf_3d_input.dart b/packages/wolf_3d_input/lib/src/wolf_3d_input.dart new file mode 100644 index 0000000..d555e73 --- /dev/null +++ b/packages/wolf_3d_input/lib/src/wolf_3d_input.dart @@ -0,0 +1,27 @@ +import 'package:wolf_3d_engine/wolf_3d_engine.dart'; +import 'package:wolf_3d_entities/wolf_3d_entities.dart'; + +abstract class Wolf3dInput { + bool isMovingForward = false; + bool isMovingBackward = false; + bool isTurningLeft = false; + bool isTurningRight = false; + bool isInteracting = false; + bool isFiring = false; + WeaponType? requestedWeapon; + + /// Called once per frame by the game loop to refresh the state. + void update(); + + /// Exports the current state as a clean DTO for the engine. + /// Subclasses do not need to override this. + EngineInput get currentInput => EngineInput( + isMovingForward: isMovingForward, + isMovingBackward: isMovingBackward, + isTurningLeft: isTurningLeft, + isTurningRight: isTurningRight, + isFiring: isFiring, + isInteracting: isInteracting, + requestedWeapon: requestedWeapon, + ); +} diff --git a/packages/wolf_3d_input/lib/wolf_3d_input.dart b/packages/wolf_3d_input/lib/wolf_3d_input.dart index 6a2cd00..251e399 100644 --- a/packages/wolf_3d_input/lib/wolf_3d_input.dart +++ b/packages/wolf_3d_input/lib/wolf_3d_input.dart @@ -1,58 +1,4 @@ -import 'package:flutter/services.dart'; -import 'package:wolf_3d_engine/wolf_3d_engine.dart'; -import 'package:wolf_3d_entities/wolf_3d_entities.dart'; +library; -class WolfInput { - Set _previousKeys = {}; - - bool isMovingForward = false; - bool isMovingBackward = false; - bool isTurningLeft = false; - bool isTurningRight = false; - bool isInteracting = false; - bool isFiring = false; - WeaponType? requestedWeapon; - - void update() { - final pressedKeys = HardwareKeyboard.instance.logicalKeysPressed; - final newlyPressedKeys = pressedKeys.difference(_previousKeys); - - isMovingForward = pressedKeys.contains(LogicalKeyboardKey.keyW); - isMovingBackward = pressedKeys.contains(LogicalKeyboardKey.keyS); - isTurningLeft = pressedKeys.contains(LogicalKeyboardKey.keyA); - isTurningRight = pressedKeys.contains(LogicalKeyboardKey.keyD); - - isInteracting = newlyPressedKeys.contains(LogicalKeyboardKey.space); - - isFiring = - pressedKeys.contains(LogicalKeyboardKey.controlLeft) && - !pressedKeys.contains(LogicalKeyboardKey.space); - - requestedWeapon = null; - for (final LogicalKeyboardKey key in newlyPressedKeys) { - switch (key) { - case LogicalKeyboardKey.digit1: - requestedWeapon = WeaponType.knife; - case LogicalKeyboardKey.digit2: - requestedWeapon = WeaponType.pistol; - case LogicalKeyboardKey.digit3: - requestedWeapon = WeaponType.machineGun; - case LogicalKeyboardKey.digit4: - requestedWeapon = WeaponType.chainGun; - } - } - - _previousKeys = Set.from(pressedKeys); - } - - /// Exports the current state as a clean DTO for the engine - EngineInput get currentInput => EngineInput( - isMovingForward: isMovingForward, - isMovingBackward: isMovingBackward, - isTurningLeft: isTurningLeft, - isTurningRight: isTurningRight, - isFiring: isFiring, - isInteracting: isInteracting, - requestedWeapon: requestedWeapon, - ); -} +export 'src/cli_input.dart'; +export 'src/wolf_3d_input.dart'; diff --git a/packages/wolf_3d_input/pubspec.yaml b/packages/wolf_3d_input/pubspec.yaml index 13454e6..3df1026 100644 --- a/packages/wolf_3d_input/pubspec.yaml +++ b/packages/wolf_3d_input/pubspec.yaml @@ -5,54 +5,9 @@ homepage: environment: sdk: ^3.11.1 - flutter: ">=1.17.0" resolution: workspace dependencies: - flutter: - sdk: flutter wolf_3d_entities: any wolf_3d_engine: any - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_lints: ^6.0.0 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - - # To add assets to your package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.dev/to/asset-from-package - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/to/resolution-aware-images - - # To add custom fonts to your package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.dev/to/font-from-package diff --git a/packages/wolf_3d_renderer/analysis_options.yaml b/packages/wolf_3d_renderer/analysis_options.yaml index a5744c1..5e91e85 100644 --- a/packages/wolf_3d_renderer/analysis_options.yaml +++ b/packages/wolf_3d_renderer/analysis_options.yaml @@ -2,3 +2,6 @@ include: package:flutter_lints/flutter.yaml # Additional information about this file can be found at # https://dart.dev/guides/language/analysis-options + +formatter: + trailing_commas: preserve 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 3a3b21b..1c285fd 100644 --- a/packages/wolf_3d_renderer/lib/wolf_3d_ascii_renderer.dart +++ b/packages/wolf_3d_renderer/lib/wolf_3d_ascii_renderer.dart @@ -2,8 +2,8 @@ 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/ascii_rasterizer.dart'; class WolfAsciiRenderer extends StatefulWidget { const WolfAsciiRenderer( @@ -25,7 +25,7 @@ class WolfAsciiRenderer extends StatefulWidget { class _WolfAsciiRendererState extends State with SingleTickerProviderStateMixin { - final WolfInput inputManager = WolfInput(); + final Wolf3dInput inputManager = Wolf3dFlutterInput(); late final WolfEngine engine; late Ticker _gameLoop; final FocusNode _focusNode = FocusNode(); @@ -116,11 +116,11 @@ class AsciiFrameWidget extends StatelessWidget { children: frameData.map((row) { List optimizedSpans = []; if (row.isNotEmpty) { - Color currentColor = row[0].color; + Color currentColor = Color(row[0].argb); StringBuffer currentSegment = StringBuffer(row[0].char); for (int i = 1; i < row.length; i++) { - if (row[i].color == currentColor) { + if (Color(row[i].argb) == currentColor) { currentSegment.write(row[i].char); } else { optimizedSpans.add( @@ -129,7 +129,7 @@ class AsciiFrameWidget extends StatelessWidget { style: TextStyle(color: currentColor), ), ); - currentColor = row[i].color; + currentColor = Color(row[i].argb); currentSegment = StringBuffer(row[i].char); } } diff --git a/packages/wolf_3d_renderer/lib/wolf_3d_renderer.dart b/packages/wolf_3d_renderer/lib/wolf_3d_renderer.dart index bd3c7d3..412b09a 100644 --- a/packages/wolf_3d_renderer/lib/wolf_3d_renderer.dart +++ b/packages/wolf_3d_renderer/lib/wolf_3d_renderer.dart @@ -4,6 +4,7 @@ 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'; class WolfRenderer extends StatefulWidget { @@ -26,7 +27,7 @@ class WolfRenderer extends StatefulWidget { class _WolfRendererState extends State with SingleTickerProviderStateMixin { - final WolfInput inputManager = WolfInput(); + final Wolf3dInput inputManager = Wolf3dFlutterInput(); late final WolfEngine engine; late Ticker _gameLoop; final FocusNode _focusNode = FocusNode(); diff --git a/packages/wolf_3d_renderer/pubspec.yaml b/packages/wolf_3d_renderer/pubspec.yaml index ae93d5d..e5eed9d 100644 --- a/packages/wolf_3d_renderer/pubspec.yaml +++ b/packages/wolf_3d_renderer/pubspec.yaml @@ -16,6 +16,7 @@ dependencies: wolf_3d_engine: any wolf_3d_entities: any wolf_3d_input: any + wolf_3d_flutter: any dev_dependencies: flutter_test: diff --git a/packages/wolf_3d_synth/lib/src/silent_renderer.dart b/packages/wolf_3d_synth/lib/src/silent_renderer.dart new file mode 100644 index 0000000..ce67ca9 --- /dev/null +++ b/packages/wolf_3d_synth/lib/src/silent_renderer.dart @@ -0,0 +1,34 @@ +import 'package:wolf_3d_data_types/wolf_3d_data_types.dart'; +import 'package:wolf_3d_engine/wolf_3d_engine.dart'; + +class CliSilentAudio implements EngineAudio { + @override + WolfensteinData? activeGame; + + @override + Future init() async { + // No-op for CLI + } + + @override + void playMenuMusic() {} + + @override + void playLevelMusic(WolfLevel level) { + // Optional: Print a log so you know it's working! + // print("🎵 Playing music for: ${level.name} 🎵"); + } + + @override + void stopMusic() {} + + @override + void playSoundEffect(int sfxId) { + // Optional: You could use the terminal 'bell' character here + // to actually make a system beep when a sound plays! + // stdout.write('\x07'); + } + + @override + void dispose() {} +} diff --git a/packages/wolf_3d_synth/lib/wolf_3d_synth.dart b/packages/wolf_3d_synth/lib/wolf_3d_synth.dart index 10d38a6..ccd3f87 100644 --- a/packages/wolf_3d_synth/lib/wolf_3d_synth.dart +++ b/packages/wolf_3d_synth/lib/wolf_3d_synth.dart @@ -3,4 +3,5 @@ /// More dartdocs go here. library; +export 'src/silent_renderer.dart' show CliSilentAudio; export 'src/wolf_3d_audio.dart' show WolfAudio;