import 'dart:math' as math; import 'package:wolf_dart/classes/coordinate_2d.dart'; import 'package:wolf_dart/features/entities/entity.dart'; abstract class Enemy extends Entity { Enemy({ required super.x, required super.y, required super.spriteIndex, super.angle, super.state, super.mapId, super.lastActionTime, }); // Standard guard health int health = 25; bool isDying = false; void takeDamage(int amount, int currentTime) { if (state == EntityState.dead) return; health -= amount; // Mark the start of the death/pain lastActionTime = currentTime; if (health <= 0) { state = EntityState.dead; // This triggers the dying animation isDying = true; } else if (math.Random().nextDouble() < 0.5) { state = EntityState.pain; } else { state = EntityState.patrolling; } } // Decodes the Map ID to figure out which way the enemy is facing static double getInitialAngle(int objId) { int normalizedId = (objId - 108) % 36; // 0=East, 1=North, 2=West, 3=South int direction = normalizedId % 4; switch (direction) { case 0: return 0.0; case 1: return 3 * math.pi / 2; case 2: return math.pi; case 3: return math.pi / 2; default: return 0.0; } } // The enemy can now check its own line of sight! bool hasLineOfSight( Coordinate2D playerPosition, bool Function(int x, int y) isWalkable, ) { double distance = position.distanceTo(playerPosition); // 1. FOV Check double angleToPlayer = position.angleTo(playerPosition); double diff = angle - angleToPlayer; while (diff <= -math.pi) { diff += 2 * math.pi; } while (diff > math.pi) { diff -= 2 * math.pi; } if (diff.abs() > math.pi / 2) return false; // 2. Map Check Coordinate2D dir = (playerPosition - position).normalized; double stepSize = 0.2; for (double i = 0; i < distance; i += stepSize) { Coordinate2D checkPos = position + (dir * i); if (!isWalkable(checkPos.x.toInt(), checkPos.y.toInt())) return false; } return true; } // The weapon asks the enemy if it is unobstructed from the shooter bool hasLineOfSightFrom( Coordinate2D source, double sourceAngle, double distance, bool Function(int x, int y) isWalkable, ) { double dirX = math.cos(sourceAngle); double dirY = math.sin(sourceAngle); for (double i = 0.5; i < distance; i += 0.2) { int checkX = (source.x + dirX * i).toInt(); int checkY = (source.y + dirY * i).toInt(); if (!isWalkable(checkX, checkY)) return false; } return true; } void update({ required int elapsedMs, required Coordinate2D playerPosition, required bool Function(int x, int y) isWalkable, required void Function(int damage) onDamagePlayer, }); }