using GameCore.ECS; using GameCore.ECS.Interfaces; using GameCore.Input; using GameCore.Math; using GameCore.Physics; using GameCore.Player; namespace GameCore.AI; public class AIPathfindingSystem : ISystem { private const float WaypointReachThreshold = 0.5f; public void Update(World world, float deltaTime) { var entities = world.GetEntitiesWith(); foreach (var entity in entities) { if (world.GetComponent(entity) != null) continue; var ai = world.GetComponent(entity); var input = world.GetComponent(entity); var pos = world.GetComponent(entity); if (ai == null || input == null || pos == null) continue; input.MoveDirection = Vector3.Zero; Vector3? targetPosition = null; switch (ai.CurrentState) { case AIState.Chase: targetPosition = ai.LastKnownTargetPosition; world.Logger.Debug($"AI Entity {entity.Id} chasing target at {targetPosition}"); break; case AIState.Patrol: var patrol = world.GetComponent(entity); if (patrol == null || patrol.PatrolPoints.Count == 0) { ai.CurrentState = AIState.Idle; world.Logger.Debug($"AI Entity {entity.Id} has no patrol points, switching to Idle state."); continue; } targetPosition = patrol.PatrolPoints[patrol.CurrentPatrolIndex]; var horizontalDiff = new Vector3(targetPosition.Value.X - pos.Position.X, 0f, targetPosition.Value.Z - pos.Position.Z); var distanceToPatrolPoint = horizontalDiff.Length(); if (distanceToPatrolPoint < WaypointReachThreshold) { patrol.CurrentPatrolIndex++; if (patrol.CurrentPatrolIndex >= patrol.PatrolPoints.Count) patrol.CurrentPatrolIndex = patrol.IsLooping ? 0 : patrol.PatrolPoints.Count - 1; targetPosition = patrol.PatrolPoints[patrol.CurrentPatrolIndex]; world.Logger.Debug( $"AI Entity {entity.Id} reached patrol point, moving to next point at {targetPosition}"); } break; case AIState.Idle: case AIState.Attack: world.Logger.Debug($"AI Entity {entity.Id} is in state {ai.CurrentState}, not moving."); continue; } if (targetPosition == null) { world.Logger.Debug($"AI Entity {entity.Id} has no target position."); continue; } var path = world.WorldQuery.GetPath(pos.Position, targetPosition.Value); world.Logger.Debug($"Path for AI Entity {entity.Id}: {string.Join(" -> ", path)}"); if (path.Count > 0) { var nextWaypoint = path[0]; var horizontalDiffToWaypoint = new Vector3(nextWaypoint.X - pos.Position.X, 0f, nextWaypoint.Z - pos.Position.Z); if (horizontalDiffToWaypoint.Length() < 0.1f && path.Count > 1) { nextWaypoint = path[1]; world.Logger.Debug($"AI Entity {entity.Id} skipping first waypoint, moving to {nextWaypoint}"); } var directionVector = nextWaypoint - pos.Position; input.MoveDirection = new Vector3(directionVector.X, 0f, directionVector.Z).Normalize(); world.Logger.Debug( $"AI Entity {entity.Id} moving towards waypoint at {nextWaypoint} with direction {input.MoveDirection}"); } else { world.Logger.Debug($"AI Entity {entity.Id} has no path."); } } } }