micromissiles-unity/Assets/Scripts/Assignment/ThreatAssignment.cs

85 lines
3.0 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.Linq;
2024-09-12 15:44:55 -07:00
using Unity.VisualScripting;
using UnityEngine;
// The threat assignment class assigns missiles to the targets based
// on the threat level of the targets.
2024-09-13 22:45:25 -07:00
public class ThreatAssignment : IAssignment {
2024-09-24 19:59:25 -07:00
// Assign a target to each interceptor that has not been assigned a target yet.
2024-09-13 22:45:25 -07:00
public IEnumerable<IAssignment.AssignmentItem> Assign(List<Agent> missiles, List<Agent> targets) {
List<IAssignment.AssignmentItem> assignments = new List<IAssignment.AssignmentItem>();
2024-09-24 19:59:25 -07:00
List<int> assignableInterceptorIndices = IAssignment.GetAssignableInterceptorIndices(missiles);
if (assignableInterceptorIndices.Count == 0) {
2024-09-13 22:45:25 -07:00
return assignments;
}
2024-09-24 19:24:50 -07:00
List<int> activeThreatIndices = IAssignment.GetActiveThreatIndices(targets);
if (activeThreatIndices.Count == 0) {
2024-09-13 22:45:25 -07:00
return assignments;
}
2024-09-13 22:45:25 -07:00
Vector3 positionToDefend = Vector3.zero;
List<ThreatInfo> threatInfos =
2024-09-24 19:24:50 -07:00
CalculateThreatLevels(targets, activeThreatIndices, positionToDefend);
2024-09-24 19:59:25 -07:00
foreach (int missileIndex in assignableInterceptorIndices) {
2024-09-13 22:45:25 -07:00
if (missiles[missileIndex].HasAssignedTarget())
continue;
if (threatInfos.Count == 0)
break;
2024-09-24 19:59:25 -07:00
// Find the optimal target for this interceptor based on distance and threat
2024-09-13 22:45:25 -07:00
ThreatInfo optimalTarget = null;
float optimalScore = float.MinValue;
2024-09-13 22:45:25 -07:00
foreach (ThreatInfo threat in threatInfos) {
float distance = Vector3.Distance(missiles[missileIndex].transform.position,
targets[threat.TargetIndex].transform.position);
float score = threat.ThreatLevel / distance; // Balance threat level with proximity
2024-09-13 22:45:25 -07:00
if (score > optimalScore) {
optimalScore = score;
optimalTarget = threat;
}
2024-09-13 22:45:25 -07:00
}
2024-09-13 22:45:25 -07:00
if (optimalTarget != null) {
assignments.Add(new IAssignment.AssignmentItem(missileIndex, optimalTarget.TargetIndex));
threatInfos.Remove(optimalTarget);
}
}
2024-09-13 22:45:25 -07:00
return assignments;
}
2024-09-24 19:24:50 -07:00
private List<ThreatInfo> CalculateThreatLevels(List<Agent> targets, List<int> activeThreatIndices,
2024-09-13 22:45:25 -07:00
Vector3 missilesMeanPosition) {
List<ThreatInfo> threatInfos = new List<ThreatInfo>();
2024-09-24 19:24:50 -07:00
foreach (int targetIndex in activeThreatIndices) {
2024-09-13 22:45:25 -07:00
Agent target = targets[targetIndex];
float distanceToMean = Vector3.Distance(target.transform.position, missilesMeanPosition);
float velocityMagnitude = target.GetVelocity().magnitude;
// Calculate threat level based on proximity and velocity
float threatLevel = (1 / distanceToMean) * velocityMagnitude;
threatInfos.Add(new ThreatInfo(targetIndex, threatLevel));
}
// Sort threats in descending order
return threatInfos.OrderByDescending(t => t.ThreatLevel).ToList();
}
private class ThreatInfo {
public int TargetIndex { get; }
public float ThreatLevel { get; }
public ThreatInfo(int targetIndex, float threatLevel) {
TargetIndex = targetIndex;
ThreatLevel = threatLevel;
}
2024-09-13 22:45:25 -07:00
}
}