From c38595b3937cd4ccc4bba3c9fc8495a2f05dd97f Mon Sep 17 00:00:00 2001 From: Hans Kokx Date: Fri, 13 Mar 2026 19:31:40 +0100 Subject: [PATCH] Guards can spot you Signed-off-by: Hans Kokx --- lib/features/renderer/renderer.dart | 61 +++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/lib/features/renderer/renderer.dart b/lib/features/renderer/renderer.dart index e5633ee..613c8e2 100644 --- a/lib/features/renderer/renderer.dart +++ b/lib/features/renderer/renderer.dart @@ -281,18 +281,26 @@ class _WolfRendererState extends State } _spaceWasPressed = isSpacePressed; - // --- 4. UPDATE ENTITY SPRITES (8-WAY DIRECTIONAL) --- + // --- 4. UPDATE ENTITY LOGIC --- for (Entity entity in entities) { + // 1. Wake up if the player is spotted! if (entity.state == EntityState.idle) { - // Find angle from the guard TO the player + if (_hasLineOfSight(entity)) { + // "Halt!" + entity.state = EntityState.patrolling; + print("A guard spotted you!"); // Just for debugging + } + } + + // 2. Visuals: 8-Way Directional Tracking + if (entity.state == EntityState.idle || + entity.state == EntityState.patrolling) { double dx = player.x - entity.x; double dy = player.y - entity.y; double angleToPlayer = math.atan2(dy, dx); - // Find the difference between where the guard is facing and where the player is double diff = entity.angle - angleToPlayer; - // Wrap the angle to stay within -PI and +PI while (diff <= -math.pi) { diff += 2 * math.pi; } @@ -300,12 +308,10 @@ class _WolfRendererState extends State diff -= 2 * math.pi; } - // Snap that difference to one of 8 octants (45 degrees each) - // Sprite 50 is Front, 51 is Front-Right, 52 is Right, etc. int octant = ((diff + (math.pi / 8)) / (math.pi / 4)).floor() % 8; if (octant < 0) octant += 8; - // Base idle sprite for the Brown Guard is 50 + // Base sprite for the Brown Guard entity.spriteIndex = 50 + octant; } } @@ -349,6 +355,47 @@ class _WolfRendererState extends State } } + bool _hasLineOfSight(Entity guard) { + double dx = player.x - guard.x; + double dy = player.y - guard.y; + double distance = math.sqrt(dx * dx + dy * dy); + + // 1. FOV Check (Are you in front of them?) + double angleToPlayer = math.atan2(dy, dx); + double diff = guard.angle - angleToPlayer; + + while (diff <= -math.pi) { + diff += 2 * math.pi; + } + while (diff > math.pi) { + diff -= 2 * math.pi; + } + + // A standard guard FOV is about 180 degrees (90 degrees left/right) + if (diff.abs() > math.pi / 2) { + return false; // You are behind them! + } + + // 2. Line of Sight Check (Are there walls in the way?) + double dirX = dx / distance; + double dirY = dy / distance; + + // Step along the ray in small increments to check for solid blocks + double stepSize = 0.2; + for (double i = 0; i < distance; i += stepSize) { + int checkX = (guard.x + dirX * i).toInt(); + int checkY = (guard.y + dirY * i).toInt(); + + // If we hit a solid wall or closed door, vision is blocked + if (!_isWalkable(checkX, checkY)) { + return false; + } + } + + // If we made it all the way to the player without hitting a wall... + return true; + } + @override Widget build(BuildContext context) { if (_isLoading) {