| | | 1 | | using System.Collections.Generic; |
| | | 2 | | using System.Linq; |
| | | 3 | | using UnityEngine; |
| | | 4 | | |
| | | 5 | | // Base implementation of a mass release strategy. |
| | | 6 | | // |
| | | 7 | | // The mass release strategy checks whether all sub-interceptors should be released simultaneously |
| | | 8 | | // to target the target hierarchical object. The released sub-interceptors are then assigned to the |
| | | 9 | | // sub-hierarchical objects of the target hierarchical object. |
| | | 10 | | public abstract class MassReleaseStrategyBase : ReleaseStrategyBase { |
| | | 11 | | private const float _epsilon = 1e-12f; |
| | | 12 | | private const float _fanOutAngleDegrees = 60f; |
| | | 13 | | |
| | 0 | 14 | | public IAssignment Assignment { get; init; } |
| | | 15 | | |
| | 0 | 16 | | public MassReleaseStrategyBase(IAgent agent, IAssignment assignment) : base(agent) { |
| | 0 | 17 | | Assignment = assignment; |
| | 0 | 18 | | } |
| | | 19 | | |
| | 0 | 20 | | protected override List<IAgent> Release(IEnumerable<IHierarchical> hierarchicals) { |
| | 0 | 21 | | if (Agent is not CarrierBase carrier || carrier.NumSubInterceptorsRemaining <= 0) { |
| | 0 | 22 | | return new List<IAgent>(); |
| | | 23 | | } |
| | | 24 | | |
| | 0 | 25 | | Dictionary<IHierarchical, List<IHierarchical>> targetToHierarchicalMap = |
| | 0 | 26 | | hierarchicals.Where(hierarchical => hierarchical.Target != null) |
| | 0 | 27 | | .GroupBy(hierarchical => hierarchical.Target) |
| | 0 | 28 | | .ToDictionary(group => group.Key, group => group.ToList()); |
| | 0 | 29 | | List<IHierarchical> targets = targetToHierarchicalMap.Keys.ToList(); |
| | 0 | 30 | | if (targets.Count == 0) { |
| | 0 | 31 | | return new List<IAgent>(); |
| | | 32 | | } |
| | 0 | 33 | | LaunchPlan launchPlan = PlanRelease(targets); |
| | 0 | 34 | | if (!launchPlan.ShouldLaunch) { |
| | 0 | 35 | | return new List<IAgent>(); |
| | | 36 | | } |
| | | 37 | | |
| | | 38 | | // Release all sub-interceptors. |
| | 0 | 39 | | Configs.SubAgentConfig subAgentConfig = carrier.AgentConfig.SubAgentConfig; |
| | 0 | 40 | | Vector3 position = carrier.Position; |
| | 0 | 41 | | Simulation.CartesianCoordinates positionCoordinates = Coordinates3.ToProto(position); |
| | | 42 | | |
| | 0 | 43 | | Vector3 velocity = carrier.Velocity; |
| | 0 | 44 | | Vector3 perpendicularDirection = Vector3.Cross(velocity, Vector3.up); |
| | 0 | 45 | | if (perpendicularDirection.sqrMagnitude < _epsilon) { |
| | 0 | 46 | | perpendicularDirection = Vector3.Cross(velocity, Vector3.forward); |
| | 0 | 47 | | } |
| | | 48 | | |
| | 0 | 49 | | var releasedAgents = new List<IAgent>(); |
| | 0 | 50 | | for (int i = 0; i < subAgentConfig.NumSubAgents; ++i) { |
| | | 51 | | // Fan the submunitions radially outwards from the carrier's velocity vector. |
| | 0 | 52 | | Vector3 lateralDirection = |
| | | 53 | | Quaternion.AngleAxis(i * 360 / subAgentConfig.NumSubAgents, velocity) * |
| | | 54 | | perpendicularDirection; |
| | 0 | 55 | | Simulation.CartesianCoordinates velocityCoordinates = |
| | | 56 | | Coordinates3.ToProto(Vector3.RotateTowards( |
| | | 57 | | velocity, lateralDirection, maxRadiansDelta: _fanOutAngleDegrees * Mathf.Deg2Rad, |
| | | 58 | | maxMagnitudeDelta: Mathf.Cos(_fanOutAngleDegrees * Mathf.Deg2Rad))); |
| | 0 | 59 | | Simulation.State initialState = new Simulation.State() { |
| | | 60 | | Position = positionCoordinates, |
| | | 61 | | Velocity = velocityCoordinates, |
| | | 62 | | }; |
| | 0 | 63 | | IAgent subInterceptor = |
| | | 64 | | SimManager.Instance.CreateInterceptor(subAgentConfig.AgentConfig, initialState); |
| | 0 | 65 | | if (subInterceptor is IInterceptor) { |
| | 0 | 66 | | releasedAgents.Add(subInterceptor); |
| | 0 | 67 | | } |
| | 0 | 68 | | } |
| | | 69 | | |
| | | 70 | | // Assign the released sub-interceptors to the targets. |
| | 0 | 71 | | var releasedAgentHierarchicals = |
| | 0 | 72 | | releasedAgents.Select(agent => agent.HierarchicalAgent).ToList(); |
| | 0 | 73 | | List<AssignmentItem> assignments = Assignment.Assign(releasedAgentHierarchicals, targets); |
| | 0 | 74 | | foreach (var assignment in assignments) { |
| | 0 | 75 | | assignment.First.Target = assignment.Second; |
| | 0 | 76 | | foreach (var hierarchical in targetToHierarchicalMap[assignment.Second]) { |
| | 0 | 77 | | hierarchical.AddLaunchedHierarchical(assignment.First); |
| | 0 | 78 | | } |
| | 0 | 79 | | } |
| | | 80 | | |
| | 0 | 81 | | return releasedAgents; |
| | 0 | 82 | | } |
| | | 83 | | |
| | | 84 | | // Plan the release for the given targets. |
| | | 85 | | protected abstract LaunchPlan PlanRelease(IEnumerable<IHierarchical> targets); |
| | | 86 | | } |