feat: Implement patrol path markers and enhance enemy movement logic
Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:test/test.dart';
|
||||
import 'package:wolf_3d_dart/wolf_3d_data_types.dart';
|
||||
import 'package:wolf_3d_dart/wolf_3d_entities.dart';
|
||||
@@ -165,6 +167,80 @@ void main() {
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
test('alerted dog chase does not increase player distance', () {
|
||||
final dog = Dog(x: 10.5, y: 10.5, angle: 0, mapId: MapObject.dogStart);
|
||||
dog
|
||||
..isAlerted = true
|
||||
..state = EntityState.patrolling;
|
||||
|
||||
final playerPosition = const Coordinate2D(8.5, 10.5);
|
||||
final double before = dog.position.distanceTo(playerPosition);
|
||||
|
||||
final intent = dog.update(
|
||||
elapsedMs: 1000,
|
||||
elapsedDeltaMs: 16,
|
||||
playerPosition: playerPosition,
|
||||
playerAngle: 0,
|
||||
isPlayerRunning: false,
|
||||
isWalkable: (x, y) {
|
||||
// Block direct west and diagonals to force fallback selection.
|
||||
if (x == 9 && y == 10) return false;
|
||||
if (x == 9 && y == 9) return false;
|
||||
if (x == 9 && y == 11) return false;
|
||||
return true;
|
||||
},
|
||||
areaAt: (_, _) => 0,
|
||||
isAreaConnectedToPlayer: (_) => true,
|
||||
onDamagePlayer: (_) {},
|
||||
tryOpenDoor: (_, _) {},
|
||||
onPlaySound: (_) {},
|
||||
);
|
||||
|
||||
final after = (dog.position + intent.movement).distanceTo(playerPosition);
|
||||
expect(after, lessThanOrEqualTo(before + 0.001));
|
||||
});
|
||||
|
||||
test('blocked cardinal movement yields exact zero vector', () {
|
||||
final dog = Dog(
|
||||
x: 10.5,
|
||||
y: 10.5,
|
||||
angle: -1.57079632679, // north
|
||||
mapId: MapObject.dogStart,
|
||||
);
|
||||
|
||||
final movement = dog.getValidMovement(
|
||||
intendedMovement: const Coordinate2D(1e-7, -0.6),
|
||||
playerPosition: const Coordinate2D(30, 30),
|
||||
isWalkable: (x, y) {
|
||||
// Block tile directly north of dog.
|
||||
if (x == 10 && y == 9) return false;
|
||||
return true;
|
||||
},
|
||||
tryOpenDoor: (_, _) {},
|
||||
);
|
||||
|
||||
expect(movement.x, 0);
|
||||
expect(movement.y, 0);
|
||||
});
|
||||
|
||||
test('patrol tile-step keeps north heading in map coordinates', () {
|
||||
final guard = Guard(
|
||||
x: 20.5,
|
||||
y: 20.5,
|
||||
angle: -math.pi / 2,
|
||||
mapId: MapObject.guardStart,
|
||||
);
|
||||
|
||||
final movement = guard.getPatrolPathMovement(
|
||||
moveSpeed: 0.1,
|
||||
playerPosition: const Coordinate2D(40, 40),
|
||||
isWalkable: (_, _) => true,
|
||||
tryOpenDoor: (_, _) {},
|
||||
);
|
||||
|
||||
expect(movement.y, lessThan(0));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:test/test.dart';
|
||||
import 'package:wolf_3d_dart/wolf_3d_data_types.dart';
|
||||
|
||||
void main() {
|
||||
group('Map patrol marker angles', () {
|
||||
test('maps marker ids 90-97 to T_Path 8-direction semantics', () {
|
||||
expect(MapObject.patrolAngleForMarker(MapObject.patrolEast), 0.0);
|
||||
|
||||
expect(
|
||||
MapObject.patrolAngleForMarker(MapObject.patrolNorth),
|
||||
closeTo(-math.pi / 4, 1e-9),
|
||||
);
|
||||
expect(
|
||||
MapObject.patrolAngleForMarker(MapObject.patrolWest),
|
||||
closeTo(-math.pi / 2, 1e-9),
|
||||
);
|
||||
expect(
|
||||
MapObject.patrolAngleForMarker(MapObject.patrolSouth),
|
||||
closeTo(-3 * math.pi / 4, 1e-9),
|
||||
);
|
||||
|
||||
expect(
|
||||
MapObject.patrolAngleForMarker(MapObject.patrolEastAlt),
|
||||
closeTo(math.pi, 1e-9),
|
||||
);
|
||||
expect(
|
||||
MapObject.patrolAngleForMarker(MapObject.patrolNorthAlt),
|
||||
closeTo(3 * math.pi / 4, 1e-9),
|
||||
);
|
||||
expect(
|
||||
MapObject.patrolAngleForMarker(MapObject.patrolWestAlt),
|
||||
closeTo(math.pi / 2, 1e-9),
|
||||
);
|
||||
expect(
|
||||
MapObject.patrolAngleForMarker(MapObject.patrolSouthAlt),
|
||||
closeTo(math.pi / 4, 1e-9),
|
||||
);
|
||||
});
|
||||
|
||||
test('returns null for non-marker ids', () {
|
||||
expect(MapObject.patrolAngleForMarker(MapObject.pushwallTrigger), isNull);
|
||||
expect(MapObject.patrolAngleForMarker(MapObject.playerNorth), isNull);
|
||||
expect(MapObject.patrolAngleForMarker(0), isNull);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user