Update enemy AI

Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
2026-03-15 18:16:46 +01:00
parent 347528c9f4
commit 6c55136d5b
5 changed files with 66 additions and 22 deletions

View File

@@ -69,8 +69,11 @@ class HansGrosse extends Enemy {
}) { }) {
Coordinate2D movement = const Coordinate2D(0, 0); Coordinate2D movement = const Coordinate2D(0, 0);
// Bosses lack directional sprites, they always look straight at the player double newAngle = angle;
double newAngle = position.angleTo(playerPosition);
if (isAlerted && state != EntityState.dead) {
newAngle = position.angleTo(playerPosition);
}
checkWakeUp( checkWakeUp(
elapsedMs: elapsedMs, elapsedMs: elapsedMs,
@@ -87,9 +90,10 @@ class HansGrosse extends Enemy {
break; break;
case EntityState.patrolling: case EntityState.patrolling:
if (distance > 1.5) { if (!isAlerted || distance > 1.5) {
double moveX = math.cos(newAngle) * speed; double currentMoveAngle = isAlerted ? newAngle : angle;
double moveY = math.sin(newAngle) * speed; double moveX = math.cos(currentMoveAngle) * speed;
double moveY = math.sin(currentMoveAngle) * speed;
movement = getValidMovement( movement = getValidMovement(
Coordinate2D(moveX, moveY), Coordinate2D(moveX, moveY),
isWalkable, isWalkable,
@@ -100,7 +104,7 @@ class HansGrosse extends Enemy {
int walkFrame = (elapsedMs ~/ 150) % 4; int walkFrame = (elapsedMs ~/ 150) % 4;
spriteIndex = (_baseSprite + 1) + walkFrame; spriteIndex = (_baseSprite + 1) + walkFrame;
if (distance < 8.0 && elapsedMs - lastActionTime > 1000) { if (isAlerted && distance < 8.0 && elapsedMs - lastActionTime > 1000) {
if (hasLineOfSight(playerPosition, isWalkable)) { if (hasLineOfSight(playerPosition, isWalkable)) {
state = EntityState.attacking; state = EntityState.attacking;
lastActionTime = elapsedMs; lastActionTime = elapsedMs;

View File

@@ -66,11 +66,29 @@ class Dog extends Enemy {
angleDiff: diff, angleDiff: diff,
); );
if (state == EntityState.patrolling && distance < 1.0) { if (isAlerted && state != EntityState.dead) {
newAngle = angleToPlayer;
}
// Dogs attack based on distance, so wrap the movement and attack in alert checks
if (state == EntityState.patrolling) {
if (!isAlerted || distance > 1.0) {
double currentMoveAngle = isAlerted ? angleToPlayer : angle;
double moveX = math.cos(currentMoveAngle) * speed;
double moveY = math.sin(currentMoveAngle) * speed;
movement = getValidMovement(
Coordinate2D(moveX, moveY),
isWalkable,
tryOpenDoor,
);
}
if (isAlerted && distance < 1.0) {
state = EntityState.attacking; state = EntityState.attacking;
lastActionTime = elapsedMs; lastActionTime = elapsedMs;
_hasBittenThisCycle = false; _hasBittenThisCycle = false;
} }
}
if (state == EntityState.attacking) { if (state == EntityState.attacking) {
int time = elapsedMs - lastActionTime; int time = elapsedMs - lastActionTime;

View File

@@ -69,10 +69,16 @@ class Mutant extends Enemy {
angleDiff: diff, angleDiff: diff,
); );
if (isAlerted && state != EntityState.dead) {
newAngle = angleToPlayer;
}
if (state == EntityState.patrolling) { if (state == EntityState.patrolling) {
if (distance > 0.8) { // FIX 2: Move along patrol angle if unalerted, chase if alerted
double moveX = math.cos(angleToPlayer) * speed; if (!isAlerted || distance > 0.8) {
double moveY = math.sin(angleToPlayer) * speed; double currentMoveAngle = isAlerted ? angleToPlayer : angle;
double moveX = math.cos(currentMoveAngle) * speed;
double moveY = math.sin(currentMoveAngle) * speed;
movement = getValidMovement( movement = getValidMovement(
Coordinate2D(moveX, moveY), Coordinate2D(moveX, moveY),
isWalkable, isWalkable,
@@ -80,7 +86,8 @@ class Mutant extends Enemy {
); );
} }
if (distance < 6.0 && elapsedMs - lastActionTime > 1500) { // FIX 3: Only attack if alerted (Adjust the distance/timing per enemy class!)
if (isAlerted && distance < 6.0 && elapsedMs - lastActionTime > 1500) {
if (hasLineOfSight(playerPosition, isWalkable)) { if (hasLineOfSight(playerPosition, isWalkable)) {
state = EntityState.attacking; state = EntityState.attacking;
lastActionTime = elapsedMs; lastActionTime = elapsedMs;

View File

@@ -69,17 +69,25 @@ class Officer extends Enemy {
angleDiff: diff, angleDiff: diff,
); );
if (isAlerted && state != EntityState.dead) {
newAngle = angleToPlayer;
}
if (state == EntityState.patrolling) { if (state == EntityState.patrolling) {
if (distance > 0.8) { // FIX 2: Move along patrol angle if unalerted, chase if alerted
double moveX = math.cos(angleToPlayer) * speed; if (!isAlerted || distance > 0.8) {
double moveY = math.sin(angleToPlayer) * speed; double currentMoveAngle = isAlerted ? angleToPlayer : angle;
double moveX = math.cos(currentMoveAngle) * speed;
double moveY = math.sin(currentMoveAngle) * speed;
movement = getValidMovement( movement = getValidMovement(
Coordinate2D(moveX, moveY), Coordinate2D(moveX, moveY),
isWalkable, isWalkable,
tryOpenDoor, tryOpenDoor,
); );
} }
if (distance < 6.0 && elapsedMs - lastActionTime > 1000) {
// FIX 3: Only attack if alerted (Adjust the distance/timing per enemy class!)
if (isAlerted && distance < 6.0 && elapsedMs - lastActionTime > 1500) {
if (hasLineOfSight(playerPosition, isWalkable)) { if (hasLineOfSight(playerPosition, isWalkable)) {
state = EntityState.attacking; state = EntityState.attacking;
lastActionTime = elapsedMs; lastActionTime = elapsedMs;

View File

@@ -69,10 +69,16 @@ class SS extends Enemy {
angleDiff: diff, angleDiff: diff,
); );
if (isAlerted && state != EntityState.dead) {
newAngle = angleToPlayer;
}
if (state == EntityState.patrolling) { if (state == EntityState.patrolling) {
if (distance > 0.8) { // FIX 2: Move along patrol angle if unalerted, chase if alerted
double moveX = math.cos(angleToPlayer) * speed; if (!isAlerted || distance > 0.8) {
double moveY = math.sin(angleToPlayer) * speed; double currentMoveAngle = isAlerted ? angleToPlayer : angle;
double moveX = math.cos(currentMoveAngle) * speed;
double moveY = math.sin(currentMoveAngle) * speed;
movement = getValidMovement( movement = getValidMovement(
Coordinate2D(moveX, moveY), Coordinate2D(moveX, moveY),
isWalkable, isWalkable,
@@ -80,7 +86,8 @@ class SS extends Enemy {
); );
} }
if (distance < 6.0 && elapsedMs - lastActionTime > 1500) { // FIX 3: Only attack if alerted (Adjust the distance/timing per enemy class!)
if (isAlerted && distance < 6.0 && elapsedMs - lastActionTime > 1500) {
if (hasLineOfSight(playerPosition, isWalkable)) { if (hasLineOfSight(playerPosition, isWalkable)) {
state = EntityState.attacking; state = EntityState.attacking;
lastActionTime = elapsedMs; lastActionTime = elapsedMs;