Added basic HUD

Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
2026-03-13 20:30:11 +01:00
parent 026db920b3
commit fb2b297900
2 changed files with 127 additions and 26 deletions

View File

@@ -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<WolfRenderer>
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),
],
),
),
);

91
lib/features/ui/hud.dart Normal file
View File

@@ -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;
}
}