import 'dart:math' as math; import 'package:wolf_dart/classes/linear_coordinates.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( LinearCoordinates player, bool Function(int x, int y) isWalkable, ) { double dx = player.x - x; double dy = player.y - y; double distance = math.sqrt(dx * dx + dy * dy); // 1. FOV Check double angleToPlayer = math.atan2(dy, dx); 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 double dirX = dx / distance; double dirY = dy / distance; double stepSize = 0.2; for (double i = 0; i < distance; i += stepSize) { int checkX = (x + dirX * i).toInt(); int checkY = (y + dirY * i).toInt(); if (!isWalkable(checkX, checkY)) return false; } return true; } // The weapon asks the enemy if it is unobstructed from the shooter bool hasLineOfSightFrom( LinearCoordinates 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 LinearCoordinates player, required bool Function(int x, int y) isWalkable, required void Function(int damage) onDamagePlayer, }); }