diff --git a/lib/features/renderer/renderer.dart b/lib/features/renderer/renderer.dart index 658aec0..f40e9a4 100644 --- a/lib/features/renderer/renderer.dart +++ b/lib/features/renderer/renderer.dart @@ -13,6 +13,7 @@ import 'package:wolf_dart/features/entities/entity_registry.dart'; import 'package:wolf_dart/features/map/wolf_map.dart'; import 'package:wolf_dart/features/player/player.dart'; import 'package:wolf_dart/features/renderer/raycast_painter.dart'; +import 'package:wolf_dart/features/ui/hud.dart'; import 'package:wolf_dart/sprite_gallery.dart'; class WolfRenderer extends StatefulWidget { @@ -329,33 +330,42 @@ class _WolfRendererState extends State focusNode: _focusNode, autofocus: true, onKeyEvent: (_) {}, - child: LayoutBuilder( - builder: (context, constraints) { - return Stack( - children: [ - CustomPaint( - size: Size(constraints.maxWidth, constraints.maxHeight), - painter: RaycasterPainter( - map: currentLevel, - textures: gameMap.textures, - player: player, - fov: fov, - doorOffsets: doorOffsets, - entities: entities, - sprites: gameMap.sprites, - ), - ), - if (damageFlashOpacity > 0) - Positioned.fill( - child: Container( - color: Colors.red.withValues( - alpha: damageFlashOpacity, + child: Column( + children: [ + // Game view + Expanded( + child: LayoutBuilder( + builder: (context, constraints) { + return Stack( + children: [ + CustomPaint( + size: Size(constraints.maxWidth, constraints.maxHeight), + painter: RaycasterPainter( + map: currentLevel, + textures: gameMap.textures, + player: player, + fov: fov, + doorOffsets: doorOffsets, + entities: entities, + sprites: gameMap.sprites, + ), ), - ), - ), - ], - ); - }, + if (damageFlashOpacity > 0) + Positioned.fill( + child: Container( + color: Colors.red.withValues( + alpha: damageFlashOpacity, + ), + ), + ), + ], + ); + }, + ), + ), + // HUD + Hud(player: player), + ], ), ), ); diff --git a/lib/features/ui/hud.dart b/lib/features/ui/hud.dart new file mode 100644 index 0000000..bc2d515 --- /dev/null +++ b/lib/features/ui/hud.dart @@ -0,0 +1,91 @@ +import 'package:flutter/material.dart'; +import 'package:wolf_dart/features/player/player.dart'; + +class Hud extends StatelessWidget { + final Player player; + + const Hud({super.key, required this.player}); + + @override + Widget build(BuildContext context) { + // We'll give the HUD a fixed height relative to the screen + return Container( + height: 100, + color: const Color(0xFF323232), // Classic dark grey status bar + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _buildStatColumn("FLOOR", "1"), + _buildStatColumn("SCORE", "${player.score}"), + _buildStatColumn("LIVES", "3"), + _buildFace(), + _buildStatColumn( + "HEALTH", + "${player.health}%", + color: _getHealthColor(), + ), + _buildStatColumn("AMMO", "${player.ammo}"), + _buildWeaponIcon(), + ], + ), + ); + } + + Widget _buildStatColumn( + String label, + String value, { + Color color = Colors.white, + }) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + label, + style: const TextStyle( + color: Colors.red, + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + Text( + value, + style: TextStyle(color: color, fontSize: 20, fontFamily: 'monospace'), + ), + ], + ); + } + + Widget _buildFace() { + // For now, we'll use a simple icon. Later we can map VSWAP indices + // for BJ Blazkowicz's face based on health percentage. + return Container( + width: 60, + height: 80, + decoration: BoxDecoration( + color: Colors.blueGrey[800], + border: Border.all(color: Colors.grey, width: 2), + ), + child: const Icon(Icons.face, color: Colors.white, size: 40), + ); + } + + Widget _buildWeaponIcon() { + IconData weaponIcon = Icons.horizontal_rule; // Default Knife/Pistol + if (player.hasChainGun) weaponIcon = Icons.reorder; + if (player.hasMachineGun) weaponIcon = Icons.view_headline; + + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text("WEAPON", style: TextStyle(color: Colors.red, fontSize: 10)), + Icon(weaponIcon, color: Colors.white), + ], + ); + } + + Color _getHealthColor() { + if (player.health > 50) return Colors.white; + if (player.health > 25) return Colors.orange; + return Colors.red; + } +}