From 9be43821ef0d57c84b33003f48df80e97f1ebf30 Mon Sep 17 00:00:00 2001 From: Titan Yuan Date: Fri, 13 Sep 2024 22:45:25 -0700 Subject: [PATCH] Format all files --- .clang-format | 3 + Assets/Scripts/Agent.cs | 346 +++++++------- Assets/Scripts/Assignment/Assignment.cs | 73 ++- .../Assignment/RoundRobinAssignment.cs | 65 ++- Assets/Scripts/Assignment/ThreatAssignment.cs | 145 +++--- Assets/Scripts/Config/SimulationConfig.cs | 182 +++----- Assets/Scripts/Config/StaticConfig.cs | 110 +++-- Assets/Scripts/Constants.cs | 27 +- Assets/Scripts/Editor/GenerateCone.cs | 257 +++++----- Assets/Scripts/IADS/IADS.cs | 41 +- Assets/Scripts/IADS/Vessel.cs | 40 +- Assets/Scripts/Interceptors/Hydra70.cs | 100 ++-- Assets/Scripts/Interceptors/Micromissile.cs | 139 +++--- Assets/Scripts/Missile.cs | 301 ++++++------ Assets/Scripts/Sensors/IdealSensor.cs | 135 +++--- Assets/Scripts/Sensors/Sensor.cs | 119 +++-- Assets/Scripts/SimManager.cs | 442 ++++++++---------- Assets/Scripts/Targets/DroneTarget.cs | 33 +- Assets/Scripts/Targets/MissileTarget.cs | 17 +- Assets/Scripts/Targets/Target.cs | 21 +- Assets/Scripts/Utilities.cs | 16 +- 21 files changed, 1197 insertions(+), 1415 deletions(-) diff --git a/.clang-format b/.clang-format index fc26de0..06caec6 100644 --- a/.clang-format +++ b/.clang-format @@ -2,3 +2,6 @@ BasedOnStyle: Google --- Language: CSharp ColumnLimit: 100 +--- +Language: Json +DisableFormat: true diff --git a/Assets/Scripts/Agent.cs b/Assets/Scripts/Agent.cs index be239fb..4f0b7e0 100644 --- a/Assets/Scripts/Agent.cs +++ b/Assets/Scripts/Agent.cs @@ -5,194 +5,174 @@ using Unity.PlasticSCM.Editor.UI; using Unity.VisualScripting; using UnityEngine; -public abstract class Agent : MonoBehaviour -{ - public enum FlightPhase { - INITIALIZED, - READY, - BOOST, - MIDCOURSE, - TERMINAL, - TERMINATED +public abstract class Agent : MonoBehaviour { + public enum FlightPhase { INITIALIZED, READY, BOOST, MIDCOURSE, TERMINAL, TERMINATED } + + [SerializeField] + private FlightPhase _flightPhase = FlightPhase.INITIALIZED; + + [SerializeField] + protected Agent _target; + protected bool _isHit = false; + protected bool _isMiss = false; + + protected AgentConfig _agentConfig; + + protected double _timeSinceLaunch = 0; + protected double _timeInPhase = 0; + + [SerializeField] + public StaticConfig StaticConfig; + + public void SetFlightPhase(FlightPhase flightPhase) { + Debug.Log( + $"Setting flight phase to {flightPhase} at time {SimManager.Instance.GetElapsedSimulationTime()}"); + _timeInPhase = 0; + _flightPhase = flightPhase; + } + + public FlightPhase GetFlightPhase() { + return _flightPhase; + } + + public bool HasLaunched() { + return (_flightPhase != FlightPhase.INITIALIZED) && (_flightPhase != FlightPhase.READY); + } + + public bool HasTerminated() { + return _flightPhase == FlightPhase.TERMINATED; + } + + public virtual void SetAgentConfig(AgentConfig config) { + _agentConfig = config; + } + + public virtual bool IsAssignable() { + return true; + } + + public virtual void AssignTarget(Agent target) { + _target = target; + } + + public Agent GetAssignedTarget() { + return _target; + } + + public bool HasAssignedTarget() { + return _target != null; + } + + public void CheckTargetHit() { + if (HasAssignedTarget() && _target.IsHit()) { + UnassignTarget(); + } + } + + public virtual void UnassignTarget() { + _target = null; + } + + // Return whether the agent has hit or been hit. + public bool IsHit() { + return _isHit; + } + + public bool IsMiss() { + return _isMiss; + } + + public void TerminateAgent() { + _flightPhase = FlightPhase.TERMINATED; + transform.position = new Vector3(0, 0, 0); + gameObject.SetActive(false); + } + + // Mark the agent as having hit the target or been hit. + public void MarkAsHit() { + _isHit = true; + TerminateAgent(); + } + + public void MarkAsMiss() { + _isMiss = true; + if (_target != null) { + SimManager.Instance.RegisterTargetMiss(_target as Target); + _target = null; + } + TerminateAgent(); + } + + public double GetSpeed() { + return GetComponent().velocity.magnitude; + } + + public Vector3 GetVelocity() { + return GetComponent().velocity; + } + + public double GetDynamicPressure() { + var airDensity = Constants.CalculateAirDensityAtAltitude(transform.position.y); + var flowSpeed = GetSpeed(); + return 0.5 * airDensity * (flowSpeed * flowSpeed); + } + + protected abstract void UpdateReady(double deltaTime); + protected abstract void UpdateBoost(double deltaTime); + protected abstract void UpdateMidCourse(double deltaTime); + + // Start is called before the first frame update + protected virtual void Start() { + _flightPhase = FlightPhase.READY; + } + + // Update is called once per frame + protected virtual void Update() { + _timeSinceLaunch += Time.deltaTime; + _timeInPhase += Time.deltaTime; + + var launch_time = _agentConfig.dynamic_config.launch_config.launch_time; + var boost_time = launch_time + StaticConfig.boostConfig.boostTime; + double elapsedSimulationTime = SimManager.Instance.GetElapsedSimulationTime(); + + if (_flightPhase == FlightPhase.TERMINATED) { + return; } - - [SerializeField] - private FlightPhase _flightPhase = FlightPhase.INITIALIZED; - - [SerializeField] - protected Agent _target; - protected bool _isHit = false; - protected bool _isMiss = false; - - protected AgentConfig _agentConfig; - - protected double _timeSinceLaunch = 0; - protected double _timeInPhase = 0; - - [SerializeField] - public StaticConfig StaticConfig; - - public void SetFlightPhase(FlightPhase flightPhase) { - Debug.Log($"Setting flight phase to {flightPhase} at time {SimManager.Instance.GetElapsedSimulationTime()}"); - _timeInPhase = 0; - _flightPhase = flightPhase; + if (elapsedSimulationTime >= launch_time && _flightPhase == FlightPhase.READY) { + SetFlightPhase(FlightPhase.BOOST); } - - public FlightPhase GetFlightPhase() { - return _flightPhase; + if (_timeSinceLaunch > boost_time && _flightPhase == FlightPhase.BOOST) { + SetFlightPhase(FlightPhase.MIDCOURSE); } - - - public bool HasLaunched() { - return (_flightPhase != FlightPhase.INITIALIZED) && (_flightPhase != FlightPhase.READY); + AlignWithVelocity(); + switch (_flightPhase) { + case FlightPhase.INITIALIZED: + break; + case FlightPhase.READY: + UpdateReady(Time.deltaTime); + break; + case FlightPhase.BOOST: + UpdateBoost(Time.deltaTime); + break; + case FlightPhase.MIDCOURSE: + case FlightPhase.TERMINAL: + UpdateMidCourse(Time.deltaTime); + break; + case FlightPhase.TERMINATED: + break; } - - public bool HasTerminated() { - return _flightPhase == FlightPhase.TERMINATED; - } - - public virtual void SetAgentConfig(AgentConfig config) { - _agentConfig = config; - } - - public virtual bool IsAssignable() { - return true; - } - - public virtual void AssignTarget(Agent target) + } + protected virtual void AlignWithVelocity() { + Vector3 velocity = GetVelocity(); + if (velocity.magnitude > 0.1f) // Only align if we have significant velocity { - _target = target; + // Create a rotation with forward along velocity and up along world up + Quaternion targetRotation = Quaternion.LookRotation(velocity, Vector3.up); + + // Smoothly rotate towards the target rotation + transform.rotation = + Quaternion.RotateTowards(transform.rotation, targetRotation, 1000f * Time.deltaTime); } - - public Agent GetAssignedTarget() { - return _target; - } - - public bool HasAssignedTarget() { - return _target != null; - } - - public void CheckTargetHit() { - if (HasAssignedTarget() && _target.IsHit()) { - UnassignTarget(); - } - } - - public virtual void UnassignTarget() - { - _target = null; - } - - // Return whether the agent has hit or been hit. - public bool IsHit() { - return _isHit; - } - - public bool IsMiss() { - return _isMiss; - } - - public void TerminateAgent() { - _flightPhase = FlightPhase.TERMINATED; - transform.position = new Vector3(0, 0, 0); - gameObject.SetActive(false); - } - - // Mark the agent as having hit the target or been hit. - public void MarkAsHit() { - _isHit = true; - TerminateAgent(); - } - - public void MarkAsMiss() { - _isMiss = true; - if(_target != null) { - SimManager.Instance.RegisterTargetMiss(_target as Target); - _target = null; - } - TerminateAgent(); - } - - - - public double GetSpeed() { - return GetComponent().velocity.magnitude; - } - - public Vector3 GetVelocity() { - return GetComponent().velocity; - } - - public double GetDynamicPressure() { - var airDensity = Constants.CalculateAirDensityAtAltitude(transform.position.y); - var flowSpeed = GetSpeed(); - return 0.5 * airDensity * (flowSpeed * flowSpeed); - } - - protected abstract void UpdateReady(double deltaTime); - protected abstract void UpdateBoost(double deltaTime); - protected abstract void UpdateMidCourse(double deltaTime); - - - - - // Start is called before the first frame update - protected virtual void Start() - { - _flightPhase = FlightPhase.READY; - } - - // Update is called once per frame - protected virtual void Update() - { - _timeSinceLaunch += Time.deltaTime; - _timeInPhase += Time.deltaTime; - - var launch_time = _agentConfig.dynamic_config.launch_config.launch_time; - var boost_time = launch_time + StaticConfig.boostConfig.boostTime; - double elapsedSimulationTime = SimManager.Instance.GetElapsedSimulationTime(); - - if(_flightPhase == FlightPhase.TERMINATED) { - return; - } - - if(elapsedSimulationTime >= launch_time && _flightPhase == FlightPhase.READY) { - SetFlightPhase(FlightPhase.BOOST); - } - if(_timeSinceLaunch > boost_time && _flightPhase == FlightPhase.BOOST) { - SetFlightPhase(FlightPhase.MIDCOURSE); - } - AlignWithVelocity(); - switch (_flightPhase) { - - case FlightPhase.INITIALIZED: - break; - case FlightPhase.READY: - UpdateReady(Time.deltaTime); - break; - case FlightPhase.BOOST: - UpdateBoost(Time.deltaTime); - break; - case FlightPhase.MIDCOURSE: - case FlightPhase.TERMINAL: - UpdateMidCourse(Time.deltaTime); - break; - case FlightPhase.TERMINATED: - break; - } - } - protected virtual void AlignWithVelocity() - { - Vector3 velocity = GetVelocity(); - if (velocity.magnitude > 0.1f) // Only align if we have significant velocity - { - // Create a rotation with forward along velocity and up along world up - Quaternion targetRotation = Quaternion.LookRotation(velocity, Vector3.up); - - // Smoothly rotate towards the target rotation - transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, 1000f * Time.deltaTime); - } - } - + } } diff --git a/Assets/Scripts/Assignment/Assignment.cs b/Assets/Scripts/Assignment/Assignment.cs index 3d98bb4..03b0bb8 100644 --- a/Assets/Scripts/Assignment/Assignment.cs +++ b/Assets/Scripts/Assignment/Assignment.cs @@ -3,53 +3,44 @@ using System.Collections.Generic; using UnityEngine; // The assignment class is an interface for assigning a target to each missile. -public interface IAssignment -{ - // Assignment item type. - // The first element corresponds to the missile index, and the second element - // corresponds to the target index. - public struct AssignmentItem - { - public int MissileIndex; - public int TargetIndex; +public interface IAssignment { + // Assignment item type. + // The first element corresponds to the missile index, and the second element + // corresponds to the target index. + public struct AssignmentItem { + public int MissileIndex; + public int TargetIndex; - public AssignmentItem(int missileIndex, int targetIndex) - { - MissileIndex = missileIndex; - TargetIndex = targetIndex; - } + public AssignmentItem(int missileIndex, int targetIndex) { + MissileIndex = missileIndex; + TargetIndex = targetIndex; } + } - // A list containing the missile-target assignments. + // A list containing the missile-target assignments. - // Assign a target to each missile that has not been assigned a target yet. - public abstract IEnumerable Assign(List missiles, List targets); + // Assign a target to each missile that has not been assigned a target yet. + public abstract IEnumerable Assign(List missiles, List targets); - // Get the list of assignable missile indices. - protected static List GetAssignableMissileIndices(List missiles) - { - List assignableMissileIndices = new List(); - for (int missileIndex = 0; missileIndex < missiles.Count; missileIndex++) - { - if (missiles[missileIndex].IsAssignable()) - { - assignableMissileIndices.Add(missileIndex); - } - } - return assignableMissileIndices; + // Get the list of assignable missile indices. + protected static List GetAssignableMissileIndices(List missiles) { + List assignableMissileIndices = new List(); + for (int missileIndex = 0; missileIndex < missiles.Count; missileIndex++) { + if (missiles[missileIndex].IsAssignable()) { + assignableMissileIndices.Add(missileIndex); + } } + return assignableMissileIndices; + } - // Get the list of active target indices. - protected static List GetActiveTargetIndices(List targets) - { - List activeTargetIndices = new List(); - for (int targetIndex = 0; targetIndex < targets.Count; targetIndex++) - { - if (!targets[targetIndex].IsHit()) - { - activeTargetIndices.Add(targetIndex); - } - } - return activeTargetIndices; + // Get the list of active target indices. + protected static List GetActiveTargetIndices(List targets) { + List activeTargetIndices = new List(); + for (int targetIndex = 0; targetIndex < targets.Count; targetIndex++) { + if (!targets[targetIndex].IsHit()) { + activeTargetIndices.Add(targetIndex); + } } + return activeTargetIndices; + } } diff --git a/Assets/Scripts/Assignment/RoundRobinAssignment.cs b/Assets/Scripts/Assignment/RoundRobinAssignment.cs index 51bc957..d14050a 100644 --- a/Assets/Scripts/Assignment/RoundRobinAssignment.cs +++ b/Assets/Scripts/Assignment/RoundRobinAssignment.cs @@ -5,42 +5,35 @@ using UnityEngine; // The round-robin assignment class assigns missiles to the targets in a // round-robin order. -public class RoundRobinAssignment : IAssignment -{ - // Previous target index that was assigned. - private int prevTargetIndex = -1; +public class RoundRobinAssignment : IAssignment { + // Previous target index that was assigned. + private int prevTargetIndex = -1; - // Assign a target to each missile that has not been assigned a target yet. - public IEnumerable Assign(List missiles, List targets) - { - List assignments = new List(); - List assignableMissileIndices = IAssignment.GetAssignableMissileIndices(missiles); - if (assignableMissileIndices.Count == 0) - { - return assignments; - } - - List activeTargetIndices = IAssignment.GetActiveTargetIndices(targets); - if (activeTargetIndices.Count == 0) - { - return assignments; - } - - foreach (int missileIndex in assignableMissileIndices) - { - int nextActiveTargetIndex = activeTargetIndices - .FindIndex(index => index > prevTargetIndex); - - if (nextActiveTargetIndex == -1) - { - nextActiveTargetIndex = 0; - } - - int nextTargetIndex = activeTargetIndices[nextActiveTargetIndex]; - assignments.Add(new IAssignment.AssignmentItem(missileIndex, nextTargetIndex)); - prevTargetIndex = nextTargetIndex; - } - - return assignments; + // Assign a target to each missile that has not been assigned a target yet. + public IEnumerable Assign(List missiles, List targets) { + List assignments = new List(); + List assignableMissileIndices = IAssignment.GetAssignableMissileIndices(missiles); + if (assignableMissileIndices.Count == 0) { + return assignments; } + + List activeTargetIndices = IAssignment.GetActiveTargetIndices(targets); + if (activeTargetIndices.Count == 0) { + return assignments; + } + + foreach (int missileIndex in assignableMissileIndices) { + int nextActiveTargetIndex = activeTargetIndices.FindIndex(index => index > prevTargetIndex); + + if (nextActiveTargetIndex == -1) { + nextActiveTargetIndex = 0; + } + + int nextTargetIndex = activeTargetIndices[nextActiveTargetIndex]; + assignments.Add(new IAssignment.AssignmentItem(missileIndex, nextTargetIndex)); + prevTargetIndex = nextTargetIndex; + } + + return assignments; + } } \ No newline at end of file diff --git a/Assets/Scripts/Assignment/ThreatAssignment.cs b/Assets/Scripts/Assignment/ThreatAssignment.cs index aa29d2d..f3bf4d4 100644 --- a/Assets/Scripts/Assignment/ThreatAssignment.cs +++ b/Assets/Scripts/Assignment/ThreatAssignment.cs @@ -6,89 +6,80 @@ using UnityEngine; // The threat assignment class assigns missiles to the targets based // on the threat level of the targets. -public class ThreatAssignment : IAssignment -{ - // Assign a target to each missile that has not been assigned a target yet. - public IEnumerable Assign(List missiles, List targets) - { +public class ThreatAssignment : IAssignment { + // Assign a target to each missile that has not been assigned a target yet. + public IEnumerable Assign(List missiles, List targets) { + List assignments = new List(); - List assignments = new List(); - - List assignableMissileIndices = IAssignment.GetAssignableMissileIndices(missiles); - if (assignableMissileIndices.Count == 0) - { - return assignments; - } - - List activeTargetIndices = IAssignment.GetActiveTargetIndices(targets); - if (activeTargetIndices.Count == 0) - { - return assignments; - } - - Vector3 positionToDefend = Vector3.zero; - List threatInfos = CalculateThreatLevels(targets, activeTargetIndices, positionToDefend); - - foreach (int missileIndex in assignableMissileIndices) - { - if (missiles[missileIndex].HasAssignedTarget()) continue; - if (threatInfos.Count == 0) break; - - // Find the optimal target for this missile based on distance and threat - ThreatInfo optimalTarget = null; - float optimalScore = float.MinValue; - - 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 - - if (score > optimalScore) - { - optimalScore = score; - optimalTarget = threat; - } - } - - if (optimalTarget != null) - { - assignments.Add(new IAssignment.AssignmentItem(missileIndex, optimalTarget.TargetIndex)); - threatInfos.Remove(optimalTarget); - } - } - return assignments; + List assignableMissileIndices = IAssignment.GetAssignableMissileIndices(missiles); + if (assignableMissileIndices.Count == 0) { + return assignments; } - - private List CalculateThreatLevels(List targets, List activeTargetIndices, Vector3 missilesMeanPosition) - { - List threatInfos = new List(); - - foreach (int targetIndex in activeTargetIndices) - { - 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(); + List activeTargetIndices = IAssignment.GetActiveTargetIndices(targets); + if (activeTargetIndices.Count == 0) { + return assignments; } - private class ThreatInfo - { - public int TargetIndex { get; } - public float ThreatLevel { get; } + Vector3 positionToDefend = Vector3.zero; + List threatInfos = + CalculateThreatLevels(targets, activeTargetIndices, positionToDefend); - public ThreatInfo(int targetIndex, float threatLevel) - { - TargetIndex = targetIndex; - ThreatLevel = threatLevel; + foreach (int missileIndex in assignableMissileIndices) { + if (missiles[missileIndex].HasAssignedTarget()) + continue; + if (threatInfos.Count == 0) + break; + + // Find the optimal target for this missile based on distance and threat + ThreatInfo optimalTarget = null; + float optimalScore = float.MinValue; + + 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 + + if (score > optimalScore) { + optimalScore = score; + optimalTarget = threat; } + } + + if (optimalTarget != null) { + assignments.Add(new IAssignment.AssignmentItem(missileIndex, optimalTarget.TargetIndex)); + threatInfos.Remove(optimalTarget); + } } + return assignments; + } + + private List CalculateThreatLevels(List targets, List activeTargetIndices, + Vector3 missilesMeanPosition) { + List threatInfos = new List(); + + foreach (int targetIndex in activeTargetIndices) { + 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; + } + } } \ No newline at end of file diff --git a/Assets/Scripts/Config/SimulationConfig.cs b/Assets/Scripts/Config/SimulationConfig.cs index 26b4aa6..94b3b70 100644 --- a/Assets/Scripts/Config/SimulationConfig.cs +++ b/Assets/Scripts/Config/SimulationConfig.cs @@ -3,157 +3,117 @@ using System.Collections.Generic; using UnityEngine; [CreateAssetMenu(fileName = "SimulationConfig", menuName = "Simulation/Config", order = 1)] -public class SimulationConfig : ScriptableObject -{ [Header("Simulation Settings")] - public float timeScale = 0.05f; +public class SimulationConfig : ScriptableObject { + [Header("Simulation Settings")] + public float timeScale = 0.05f; - [Header("Missile Swarm Configurations")] - public List missile_swarm_configs = new List(); + [Header("Missile Swarm Configurations")] + public List missile_swarm_configs = new List(); - [Header("Target Swarm Configurations")] - public List target_swarm_configs = new List(); - - + [Header("Target Swarm Configurations")] + public List target_swarm_configs = new List(); } [System.Serializable] -public class DynamicConfig -{ - public LaunchConfig launch_config; - public SensorConfig sensor_config; +public class DynamicConfig { + public LaunchConfig launch_config; + public SensorConfig sensor_config; } [System.Serializable] -public class SwarmConfig -{ - public int num_agents; - public AgentConfig agent_config; +public class SwarmConfig { + public int num_agents; + public AgentConfig agent_config; } [System.Serializable] -public class AgentConfig -{ - public MissileType missile_type; - public TargetType target_type; - public InitialState initial_state; - public StandardDeviation standard_deviation; - public DynamicConfig dynamic_config; - public PlottingConfig plotting_config; - public SubmunitionsConfig submunitions_config; +public class AgentConfig { + public MissileType missile_type; + public TargetType target_type; + public InitialState initial_state; + public StandardDeviation standard_deviation; + public DynamicConfig dynamic_config; + public PlottingConfig plotting_config; + public SubmunitionsConfig submunitions_config; - public static AgentConfig FromSubmunitionAgentConfig(SubmunitionAgentConfig submunitionConfig) - { - return new AgentConfig - { - missile_type = submunitionConfig.missile_type, - initial_state = submunitionConfig.initial_state, - standard_deviation = submunitionConfig.standard_deviation, - dynamic_config = submunitionConfig.dynamic_config, - plotting_config = submunitionConfig.plotting_config, - - // Set other fields as needed, using default values if not present in SubmunitionAgentConfig - target_type = TargetType.DRONE, // Or another default value - submunitions_config = null // Or a default value if needed - }; - } + public static AgentConfig FromSubmunitionAgentConfig(SubmunitionAgentConfig submunitionConfig) { + return new AgentConfig { + missile_type = submunitionConfig.missile_type, + initial_state = submunitionConfig.initial_state, + standard_deviation = submunitionConfig.standard_deviation, + dynamic_config = submunitionConfig.dynamic_config, + plotting_config = submunitionConfig.plotting_config, + + // Set other fields as needed, using default values if not present in SubmunitionAgentConfig + target_type = TargetType.DRONE, // Or another default value + submunitions_config = null // Or a default value if needed + }; + } } [System.Serializable] -public class InitialState -{ - public Vector3 position; - public Vector3 rotation; - public Vector3 velocity; +public class InitialState { + public Vector3 position; + public Vector3 rotation; + public Vector3 velocity; } [System.Serializable] -public class StandardDeviation -{ - public Vector3 position; - public Vector3 velocity; +public class StandardDeviation { + public Vector3 position; + public Vector3 velocity; } [System.Serializable] -public class LaunchConfig -{ - public float launch_time; +public class LaunchConfig { + public float launch_time; } [System.Serializable] -public class PlottingConfig -{ - public Color color; - public LineStyle linestyle; - public Marker marker; +public class PlottingConfig { + public Color color; + public LineStyle linestyle; + public Marker marker; } [System.Serializable] -public class SubmunitionsConfig -{ - public int num_submunitions; - public LaunchConfig launch_config; - public SubmunitionAgentConfig agent_config; +public class SubmunitionsConfig { + public int num_submunitions; + public LaunchConfig launch_config; + public SubmunitionAgentConfig agent_config; } [System.Serializable] -public class SubmunitionAgentConfig -{ - public MissileType missile_type; - public InitialState initial_state; - public StandardDeviation standard_deviation; - public DynamicConfig dynamic_config; - public PlottingConfig plotting_config; +public class SubmunitionAgentConfig { + public MissileType missile_type; + public InitialState initial_state; + public StandardDeviation standard_deviation; + public DynamicConfig dynamic_config; + public PlottingConfig plotting_config; } [System.Serializable] -public class SensorConfig -{ - public SensorType type; - public float frequency; +public class SensorConfig { + public SensorType type; + public float frequency; } [System.Serializable] -public class TargetConfig -{ - public TargetType target_type; - public InitialState initial_state; - public PlottingConfig plotting_config; - public string prefabName; +public class TargetConfig { + public TargetType target_type; + public InitialState initial_state; + public PlottingConfig plotting_config; + public string prefabName; } -public enum MissileType -{ - HYDRA_70, - MICROMISSILE -} +public enum MissileType { HYDRA_70, MICROMISSILE } -public enum TargetType -{ - DRONE, - MISSILE -} +public enum TargetType { DRONE, MISSILE } -public enum ConfigColor -{ - BLUE, - GREEN, - RED -} +public enum ConfigColor { BLUE, GREEN, RED } -public enum LineStyle -{ - DOTTED, - SOLID -} +public enum LineStyle { DOTTED, SOLID } -public enum Marker -{ - TRIANGLE_UP, - TRIANGLE_DOWN, - SQUARE -} +public enum Marker { TRIANGLE_UP, TRIANGLE_DOWN, SQUARE } -public enum SensorType -{ - IDEAL -} \ No newline at end of file +public enum SensorType { IDEAL } \ No newline at end of file diff --git a/Assets/Scripts/Config/StaticConfig.cs b/Assets/Scripts/Config/StaticConfig.cs index a582347..b118ee4 100644 --- a/Assets/Scripts/Config/StaticConfig.cs +++ b/Assets/Scripts/Config/StaticConfig.cs @@ -3,71 +3,65 @@ using System.Collections.Generic; using UnityEngine; [System.Serializable] -public class StaticConfig -{ - [System.Serializable] - public class AccelerationConfig - { - [Tooltip("Maximum reference acceleration")] - public float maxReferenceAcceleration = 300f; - [Tooltip("Reference speed")] - public float referenceSpeed = 1000f; - } +public class StaticConfig { + [System.Serializable] + public class AccelerationConfig { + [Tooltip("Maximum reference acceleration")] + public float maxReferenceAcceleration = 300f; + [Tooltip("Reference speed")] + public float referenceSpeed = 1000f; + } - [System.Serializable] - public class BoostConfig - { - [Tooltip("Boost time in seconds")] - public float boostTime = 0.3f; - [Tooltip("Boost acceleration")] - public float boostAcceleration = 350f; - } + [System.Serializable] + public class BoostConfig { + [Tooltip("Boost time in seconds")] + public float boostTime = 0.3f; + [Tooltip("Boost acceleration")] + public float boostAcceleration = 350f; + } - [System.Serializable] - public class LiftDragConfig - { - [Tooltip("Lift coefficient")] - public float liftCoefficient = 0.2f; - [Tooltip("Drag coefficient")] - public float dragCoefficient = 0.7f; - [Tooltip("Lift to drag ratio")] - public float liftDragRatio = 5f; - } + [System.Serializable] + public class LiftDragConfig { + [Tooltip("Lift coefficient")] + public float liftCoefficient = 0.2f; + [Tooltip("Drag coefficient")] + public float dragCoefficient = 0.7f; + [Tooltip("Lift to drag ratio")] + public float liftDragRatio = 5f; + } - [System.Serializable] - public class BodyConfig - { - [Tooltip("Mass in kg")] - public float mass = 0.37f; - [Tooltip("Cross-sectional area in m²")] - public float crossSectionalArea = 3e-4f; - [Tooltip("Fin area in m²")] - public float finArea = 6e-4f; - [Tooltip("Body area in m²")] - public float bodyArea = 1e-2f; - } + [System.Serializable] + public class BodyConfig { + [Tooltip("Mass in kg")] + public float mass = 0.37f; + [Tooltip("Cross-sectional area in m²")] + public float crossSectionalArea = 3e-4f; + [Tooltip("Fin area in m²")] + public float finArea = 6e-4f; + [Tooltip("Body area in m²")] + public float bodyArea = 1e-2f; + } - [System.Serializable] - public class HitConfig - { - [Tooltip("Hit radius")] - public float hitRadius = 1f; - [Tooltip("Kill probability")] - public float killProbability = 0.9f; - } + [System.Serializable] + public class HitConfig { + [Tooltip("Hit radius")] + public float hitRadius = 1f; + [Tooltip("Kill probability")] + public float killProbability = 0.9f; + } - [Header("Acceleration Configuration")] - public AccelerationConfig accelerationConfig; + [Header("Acceleration Configuration")] + public AccelerationConfig accelerationConfig; - [Header("Boost Configuration")] - public BoostConfig boostConfig; + [Header("Boost Configuration")] + public BoostConfig boostConfig; - [Header("Lift and Drag Configuration")] - public LiftDragConfig liftDragConfig; + [Header("Lift and Drag Configuration")] + public LiftDragConfig liftDragConfig; - [Header("Body Configuration")] - public BodyConfig bodyConfig; + [Header("Body Configuration")] + public BodyConfig bodyConfig; - [Header("Hit Configuration")] - public HitConfig hitConfig; + [Header("Hit Configuration")] + public HitConfig hitConfig; } \ No newline at end of file diff --git a/Assets/Scripts/Constants.cs b/Assets/Scripts/Constants.cs index 4256044..0613edb 100644 --- a/Assets/Scripts/Constants.cs +++ b/Assets/Scripts/Constants.cs @@ -1,20 +1,17 @@ using System; -public static class Constants -{ - // Constants (these should be defined with appropriate values) - public const double kAirDensity = 1.204; // Sea level air density in kg/m^3 - public const double kAirDensityScaleHeight = 10.4; // Scale height in km - public const double kGravity = 9.80665; // Standard gravity in m/s^2 - public const double kEarthMeanRadius = 6378137; // Earth's mean radius in meters +public static class Constants { + // Constants (these should be defined with appropriate values) + public const double kAirDensity = 1.204; // Sea level air density in kg/m^3 + public const double kAirDensityScaleHeight = 10.4; // Scale height in km + public const double kGravity = 9.80665; // Standard gravity in m/s^2 + public const double kEarthMeanRadius = 6378137; // Earth's mean radius in meters - public static double CalculateAirDensityAtAltitude(double altitude) - { - return kAirDensity * Math.Exp(-altitude / (kAirDensityScaleHeight * 1000)); - } + public static double CalculateAirDensityAtAltitude(double altitude) { + return kAirDensity * Math.Exp(-altitude / (kAirDensityScaleHeight * 1000)); + } - public static double CalculateGravityAtAltitude(double altitude) - { - return kGravity * Math.Pow(kEarthMeanRadius / (kEarthMeanRadius + altitude), 2); - } + public static double CalculateGravityAtAltitude(double altitude) { + return kGravity * Math.Pow(kEarthMeanRadius / (kEarthMeanRadius + altitude), 2); + } } \ No newline at end of file diff --git a/Assets/Scripts/Editor/GenerateCone.cs b/Assets/Scripts/Editor/GenerateCone.cs index 9c35711..9245ac2 100644 --- a/Assets/Scripts/Editor/GenerateCone.cs +++ b/Assets/Scripts/Editor/GenerateCone.cs @@ -3,155 +3,140 @@ using UnityEditor; using System; using System.Collections.Generic; -public class GenerateCone : EditorWindow -{ - private int sides = 16; - private float baseRadius = 1f; - private float height = 2f; +public class GenerateCone : EditorWindow { + private int sides = 16; + private float baseRadius = 1f; + private float height = 2f; - [MenuItem("GameObject/3D Object/Cone", false, 10)] - static void CreateCone() - { - GameObject cone; - GameObject selectedObject = Selection.activeGameObject; + [MenuItem("GameObject/3D Object/Cone", false, 10)] + static void CreateCone() { + GameObject cone; + GameObject selectedObject = Selection.activeGameObject; - if (selectedObject != null) - { - // Create as child of selected object - cone = new GameObject("Cone"); - cone.transform.SetParent(selectedObject.transform, false); - } - else - { - // Create as new root object - cone = new GameObject("Cone"); - } - - cone.AddComponent(); - cone.AddComponent(); - Undo.RegisterCreatedObjectUndo(cone, "Create Cone"); - - var window = ScriptableObject.CreateInstance(); - window.GenerateConeObject(cone); - - Selection.activeGameObject = cone; + if (selectedObject != null) { + // Create as child of selected object + cone = new GameObject("Cone"); + cone.transform.SetParent(selectedObject.transform, false); + } else { + // Create as new root object + cone = new GameObject("Cone"); } - void GenerateConeObject(GameObject cone) - { - Mesh mesh = CreateConeMesh("ConeMesh", sides, Vector3.zero, Quaternion.identity, baseRadius, height); - - // Save the mesh as an asset - string path = "Assets/Meshes"; - if (!AssetDatabase.IsValidFolder(path)) - { - AssetDatabase.CreateFolder("Assets", "Meshes"); - } - string assetPath = AssetDatabase.GenerateUniqueAssetPath(path + "/ConeMesh.asset"); - AssetDatabase.CreateAsset(mesh, assetPath); - AssetDatabase.SaveAssets(); + cone.AddComponent(); + cone.AddComponent(); + Undo.RegisterCreatedObjectUndo(cone, "Create Cone"); - // Assign the mesh to the MeshFilter - cone.GetComponent().sharedMesh = mesh; - cone.GetComponent().material = new Material(Shader.Find("Standard")); + var window = ScriptableObject.CreateInstance(); + window.GenerateConeObject(cone); + + Selection.activeGameObject = cone; + } + + void GenerateConeObject(GameObject cone) { + Mesh mesh = + CreateConeMesh("ConeMesh", sides, Vector3.zero, Quaternion.identity, baseRadius, height); + + // Save the mesh as an asset + string path = "Assets/Meshes"; + if (!AssetDatabase.IsValidFolder(path)) { + AssetDatabase.CreateFolder("Assets", "Meshes"); + } + string assetPath = AssetDatabase.GenerateUniqueAssetPath(path + "/ConeMesh.asset"); + AssetDatabase.CreateAsset(mesh, assetPath); + AssetDatabase.SaveAssets(); + + // Assign the mesh to the MeshFilter + cone.GetComponent().sharedMesh = mesh; + cone.GetComponent().material = new Material(Shader.Find("Standard")); + } + + Vector2[] GetBasePoints(int vertices, float radius) { + const float TAU = 2f * Mathf.PI; + var pts = new Vector2[vertices]; + var step = TAU / vertices; // angular step between two vertices + for (int i = 0; i < vertices; i++) { + pts[i] = radius * Trig(i * step); // convert polar coordinate to cartesian space + } + return pts; + } + + static Vector2 Trig(float rad) => new Vector2(Mathf.Cos(rad), Mathf.Sin(rad)); + + Vector3[] BuildConeVertices(Vector2[] baseVerts, float coneHeight) { + if (baseVerts == null || baseVerts.Length < 3) + throw new InvalidOperationException("Requires at least 3 base vertices."); + var verts = new Vector3[baseVerts.Length + 1]; + verts[0] = new Vector3(0f, coneHeight, 0f); + for (int i = 0; i < baseVerts.Length; i++) { + verts[i + 1] = new Vector3(baseVerts[i].x, 0f, baseVerts[i].y); + } + return verts; + } + + void ConstructCone(Vector3[] coneVerts, List finalVerts, List triangles) { + if (coneVerts == null || coneVerts.Length < 4) + throw new InvalidOperationException("Requires at least 4 vertices."); + if (finalVerts == null || triangles == null) + throw new ArgumentNullException(); + + finalVerts.Clear(); + triangles.Clear(); + + var rimVertices = coneVerts.Length - 1; + + // Side faces + for (int i = 1; i <= rimVertices; i++) { + int a = i, b = i < rimVertices ? i + 1 : 1; + AddTriangle(coneVerts[0], coneVerts[b], coneVerts[a]); } - Vector2[] GetBasePoints(int vertices, float radius) - { - const float TAU = 2f * Mathf.PI; - var pts = new Vector2[vertices]; - var step = TAU / vertices; // angular step between two vertices - for (int i = 0; i < vertices; i++) - { - pts[i] = radius * Trig(i * step); // convert polar coordinate to cartesian space - } - return pts; + // Base face + for (int i = 1; i < rimVertices - 1; i++) { + AddTriangle(coneVerts[1], coneVerts[i + 1], coneVerts[i + 2]); } - static Vector2 Trig(float rad) => new Vector2(Mathf.Cos(rad), Mathf.Sin(rad)); + void AddTriangle(Vector3 t1, Vector3 t2, Vector3 t3) { + finalVerts.Add(t1); + finalVerts.Add(t2); + finalVerts.Add(t3); + triangles.Add(finalVerts.Count - 3); + triangles.Add(finalVerts.Count - 2); + triangles.Add(finalVerts.Count - 1); + } + } + Mesh CreateConeMesh(string name, int sides, Vector3 apex, Quaternion rotation, float baseRadius, + float height) { + var baseVerts = GetBasePoints(sides, baseRadius); + var coneVerts = BuildConeVertices(baseVerts, height); - Vector3[] BuildConeVertices(Vector2[] baseVerts, float coneHeight) - { - if (baseVerts == null || baseVerts.Length < 3) throw new InvalidOperationException("Requires at least 3 base vertices."); - var verts = new Vector3[baseVerts.Length + 1]; - verts[0] = new Vector3(0f, coneHeight, 0f); - for (int i = 0; i < baseVerts.Length; i++) - { - verts[i + 1] = new Vector3(baseVerts[i].x, 0f, baseVerts[i].y); - } - return verts; + var verts = new List(); + var tris = new List(); + ConstructCone(coneVerts, verts, tris); + + for (int i = 0; i < verts.Count; i++) { + verts[i] = rotation * (verts[i] - coneVerts[0]); } - void ConstructCone(Vector3[] coneVerts, List finalVerts, List triangles) - { - if (coneVerts == null || coneVerts.Length < 4) throw new InvalidOperationException("Requires at least 4 vertices."); - if (finalVerts == null || triangles == null) throw new ArgumentNullException(); - - finalVerts.Clear(); - triangles.Clear(); - - var rimVertices = coneVerts.Length - 1; - - // Side faces - for (int i = 1; i <= rimVertices; i++) - { - int a = i, b = i < rimVertices ? i + 1 : 1; - AddTriangle(coneVerts[0], coneVerts[b], coneVerts[a]); - } - - // Base face - for (int i = 1; i < rimVertices - 1; i++) - { - AddTriangle(coneVerts[1], coneVerts[i + 1], coneVerts[i + 2]); - } - - void AddTriangle(Vector3 t1, Vector3 t2, Vector3 t3) - { - finalVerts.Add(t1); - finalVerts.Add(t2); - finalVerts.Add(t3); - triangles.Add(finalVerts.Count - 3); - triangles.Add(finalVerts.Count - 2); - triangles.Add(finalVerts.Count - 1); - } - } - Mesh CreateConeMesh(string name, int sides, Vector3 apex, Quaternion rotation, float baseRadius, float height) - { - var baseVerts = GetBasePoints(sides, baseRadius); - var coneVerts = BuildConeVertices(baseVerts, height); - - var verts = new List(); - var tris = new List(); - ConstructCone(coneVerts, verts, tris); - - for (int i = 0; i < verts.Count; i++) - { - verts[i] = rotation * (verts[i] - coneVerts[0]); - } - - // Recenter the cone - Vector3 center = CalculateCenter(verts); - for (int i = 0; i < verts.Count; i++) - { - verts[i] = verts[i] - center + apex; - } - - Mesh mesh = new Mesh(); - mesh.name = name; - mesh.SetVertices(verts); - mesh.SetTriangles(tris.ToArray(), 0); - mesh.RecalculateNormals(); - - return mesh; + // Recenter the cone + Vector3 center = CalculateCenter(verts); + for (int i = 0; i < verts.Count; i++) { + verts[i] = verts[i] - center + apex; } - Vector3 CalculateCenter(List vertices) - { - Vector3 sum = Vector3.zero; - foreach (Vector3 vert in vertices) - { - sum += vert; - } - return sum / vertices.Count; + Mesh mesh = new Mesh(); + mesh.name = name; + mesh.SetVertices(verts); + mesh.SetTriangles(tris.ToArray(), 0); + mesh.RecalculateNormals(); + + return mesh; + } + + Vector3 CalculateCenter(List vertices) { + Vector3 sum = Vector3.zero; + foreach (Vector3 vert in vertices) { + sum += vert; } + return sum / vertices.Count; + } } \ No newline at end of file diff --git a/Assets/Scripts/IADS/IADS.cs b/Assets/Scripts/IADS/IADS.cs index 8678420..362163f 100644 --- a/Assets/Scripts/IADS/IADS.cs +++ b/Assets/Scripts/IADS/IADS.cs @@ -4,36 +4,27 @@ using System.Collections; using System; // Integrated Air Defense System -public class IADS : MonoBehaviour -{ +public class IADS : MonoBehaviour { + public enum TargetStatus { UNASSIGNED, ASSIGNED, HIT, DEGRADED, DESTROYED } - public enum TargetStatus { - UNASSIGNED, - ASSIGNED, - HIT, - DEGRADED, - DESTROYED - } + // Look up target status by unique target ID + public Dictionary _targetStatusDictionary; - // Look up target status by unique target ID - public Dictionary _targetStatusDictionary; - - private List _targets; + private List _targets; - private List _missiles; + private List _missiles; - private List _vessels; + private List _vessels; - public delegate void RegisterNewTargetDelegate(Target target); - public event RegisterNewTargetDelegate OnRegisterNewTarget; + public delegate void RegisterNewTargetDelegate(Target target); + public event RegisterNewTargetDelegate OnRegisterNewTarget; - void Start() - { - _targets = new List(); - } + void Start() { + _targets = new List(); + } - public void RegisterNewTarget(Target target) { - _targets.Add(target); - OnRegisterNewTarget?.Invoke(target); - } + public void RegisterNewTarget(Target target) { + _targets.Add(target); + OnRegisterNewTarget?.Invoke(target); + } } \ No newline at end of file diff --git a/Assets/Scripts/IADS/Vessel.cs b/Assets/Scripts/IADS/Vessel.cs index c243548..84afd78 100644 --- a/Assets/Scripts/IADS/Vessel.cs +++ b/Assets/Scripts/IADS/Vessel.cs @@ -1,33 +1,27 @@ using UnityEngine; using System.Collections.Generic; -public class Vessel : MonoBehaviour -{ - [SerializeField] - private List missileInventory = new List(); +public class Vessel : MonoBehaviour { + [SerializeField] + private List missileInventory = new List(); - public void AddMissile(Missile missile) - { - if (missile != null) - { - missileInventory.Add(missile); - } + public void AddMissile(Missile missile) { + if (missile != null) { + missileInventory.Add(missile); } + } - public void RemoveMissile(Missile missile) - { - missileInventory.Remove(missile); - } + public void RemoveMissile(Missile missile) { + missileInventory.Remove(missile); + } - public List GetMissileInventory() - { - return new List(missileInventory); - } + public List GetMissileInventory() { + return new List(missileInventory); + } - public int GetMissileCount() - { - return missileInventory.Count; - } + public int GetMissileCount() { + return missileInventory.Count; + } - // Additional methods can be added here as needed + // Additional methods can be added here as needed } diff --git a/Assets/Scripts/Interceptors/Hydra70.cs b/Assets/Scripts/Interceptors/Hydra70.cs index be8030c..dfd0b9d 100644 --- a/Assets/Scripts/Interceptors/Hydra70.cs +++ b/Assets/Scripts/Interceptors/Hydra70.cs @@ -3,63 +3,57 @@ using System.Collections.Generic; using JetBrains.Annotations; using UnityEngine; -public class Hydra70 : Missile -{ +public class Hydra70 : Missile { + private Vector3 _acceleration; + private bool _submunitionsLaunched = false; - private Vector3 _acceleration; - private bool _submunitionsLaunched = false; + protected override void Update() { + base.Update(); - protected override void Update() { + // Check if it's time to launch submunitions + if (!_submunitionsLaunched && + (GetFlightPhase() == FlightPhase.MIDCOURSE || GetFlightPhase() == FlightPhase.BOOST) && + SimManager.Instance.GetElapsedSimulationTime() >= + _agentConfig.submunitions_config.launch_config.launch_time) { + SpawnSubmunitions(); + _submunitionsLaunched = true; + } + } - base.Update(); + protected override void UpdateMidCourse(double deltaTime) { + Vector3 accelerationInput = Vector3.zero; + // Calculate and set the total acceleration + Vector3 acceleration = CalculateAcceleration(accelerationInput); + GetComponent().AddForce(acceleration, ForceMode.Acceleration); + _acceleration = acceleration; + } - // Check if it's time to launch submunitions - if (!_submunitionsLaunched && (GetFlightPhase() == FlightPhase.MIDCOURSE || GetFlightPhase() == FlightPhase.BOOST) && - SimManager.Instance.GetElapsedSimulationTime() >= _agentConfig.submunitions_config.launch_config.launch_time) - { - SpawnSubmunitions(); - _submunitionsLaunched = true; + protected override void DrawDebugVectors() { + base.DrawDebugVectors(); + if (_acceleration != null) { + Debug.DrawRay(transform.position, _acceleration * 1f, Color.green); + } + } + + public void SpawnSubmunitions() { + Debug.Log("Spawning submunitions"); + // print the callstack + Debug.Log(new System.Diagnostics.StackTrace().ToString()); + List submunitions = new List(); + switch (_agentConfig.submunitions_config.agent_config.missile_type) { + case MissileType.MICROMISSILE: + for (int i = 0; i < _agentConfig.submunitions_config.num_submunitions; i++) { + AgentConfig convertedConfig = + AgentConfig.FromSubmunitionAgentConfig(_agentConfig.submunitions_config.agent_config); + + convertedConfig.initial_state.position = transform.position; + convertedConfig.initial_state.velocity = GetComponent().velocity; + Missile submunition = SimManager.Instance.CreateMissile(convertedConfig); + submunitions.Add(submunition); + Debug.Log("Created submunition"); } + break; } - - protected override void UpdateMidCourse(double deltaTime) - { - Vector3 accelerationInput = Vector3.zero; - // Calculate and set the total acceleration - Vector3 acceleration = CalculateAcceleration(accelerationInput); - GetComponent().AddForce(acceleration, ForceMode.Acceleration); - _acceleration = acceleration; - } - - protected override void DrawDebugVectors() - { - base.DrawDebugVectors(); - if (_acceleration != null) - { - Debug.DrawRay(transform.position, _acceleration * 1f, Color.green); - } - } - - public void SpawnSubmunitions() { - Debug.Log("Spawning submunitions"); - // print the callstack - Debug.Log(new System.Diagnostics.StackTrace().ToString()); - List submunitions = new List(); - switch(_agentConfig.submunitions_config.agent_config.missile_type) { - case MissileType.MICROMISSILE: - for (int i = 0; i < _agentConfig.submunitions_config.num_submunitions; i++) { - AgentConfig convertedConfig = AgentConfig.FromSubmunitionAgentConfig(_agentConfig.submunitions_config.agent_config); - - convertedConfig.initial_state.position = transform.position; - convertedConfig.initial_state.velocity = GetComponent().velocity; - Missile submunition = SimManager.Instance.CreateMissile(convertedConfig); - submunitions.Add(submunition); - Debug.Log("Created submunition"); - } - break; - } - SimManager.Instance.AssignMissilesToTargets(submunitions); - - } - + SimManager.Instance.AssignMissilesToTargets(submunitions); + } } diff --git a/Assets/Scripts/Interceptors/Micromissile.cs b/Assets/Scripts/Interceptors/Micromissile.cs index 347f567..6b6f839 100644 --- a/Assets/Scripts/Interceptors/Micromissile.cs +++ b/Assets/Scripts/Interceptors/Micromissile.cs @@ -2,84 +2,77 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; -public class Micromissile : Missile -{ - [SerializeField] private float _navigationGain = 5f; // Typically 3-5 +public class Micromissile : Missile { + [SerializeField] + private float _navigationGain = 5f; // Typically 3-5 - private SensorOutput _sensorOutput; - private Vector3 _accelerationCommand; - private double _elapsedTime = 0; - protected override void UpdateMidCourse(double deltaTime) - { - _elapsedTime += deltaTime; - Vector3 accelerationInput = Vector3.zero; - if (HasAssignedTarget()) - { - // Update the target model (assuming we have a target model) - // TODO: Implement target model update logic + private SensorOutput _sensorOutput; + private Vector3 _accelerationCommand; + private double _elapsedTime = 0; + protected override void UpdateMidCourse(double deltaTime) { + _elapsedTime += deltaTime; + Vector3 accelerationInput = Vector3.zero; + if (HasAssignedTarget()) { + // Update the target model (assuming we have a target model) + // TODO: Implement target model update logic - // Correct the state of the target model at the sensor frequency - float sensorUpdatePeriod = 1f / _agentConfig.dynamic_config.sensor_config.frequency; - if (_elapsedTime >= sensorUpdatePeriod) - { - // TODO: Implement guidance filter to estimate state from sensor output - // For now, we'll use the target's actual state - _sensorOutput = GetComponent().Sense(_target); - _elapsedTime = 0; - } + // Correct the state of the target model at the sensor frequency + float sensorUpdatePeriod = 1f / _agentConfig.dynamic_config.sensor_config.frequency; + if (_elapsedTime >= sensorUpdatePeriod) { + // TODO: Implement guidance filter to estimate state from sensor output + // For now, we'll use the target's actual state + _sensorOutput = GetComponent().Sense(_target); + _elapsedTime = 0; + } - // Check whether the target should be considered a miss - SensorOutput sensorOutput = GetComponent().Sense(_target); - if(sensorOutput.velocity.range > 1000f) { - this.MarkAsMiss(); - } + // Check whether the target should be considered a miss + SensorOutput sensorOutput = GetComponent().Sense(_target); + if (sensorOutput.velocity.range > 1000f) { + this.MarkAsMiss(); + } - // Calculate the acceleration input - accelerationInput = CalculateAccelerationCommand(_sensorOutput); - } - - // Calculate and set the total acceleration - Vector3 acceleration = CalculateAcceleration(accelerationInput, compensateForGravity: true); - GetComponent().AddForce(acceleration, ForceMode.Acceleration); - - - } - private Vector3 CalculateAccelerationCommand(SensorOutput sensorOutput) - { - // Implement Proportional Navigation guidance law - Vector3 accelerationCommand = Vector3.zero; - - // Extract relevant information from sensor output - float los_rate_az = sensorOutput.velocity.azimuth; - float los_rate_el = sensorOutput.velocity.elevation; - float closing_velocity = -sensorOutput.velocity.range; // Negative because closing velocity is opposite to range rate - - // Navigation gain (adjust as needed) - float N = _navigationGain; - - // Calculate acceleration commands in azimuth and elevation planes - float acc_az = N * closing_velocity * los_rate_az; - float acc_el = N * closing_velocity * los_rate_el; - - // Convert acceleration commands to missile body frame - accelerationCommand = transform.right * acc_az + transform.up * acc_el; - - // Clamp the acceleration command to the maximum acceleration - float maxAcceleration = CalculateMaxAcceleration(); - accelerationCommand = Vector3.ClampMagnitude(accelerationCommand, maxAcceleration); - - // Update the stored acceleration command for debugging - _accelerationCommand = accelerationCommand; - return accelerationCommand; + // Calculate the acceleration input + accelerationInput = CalculateAccelerationCommand(_sensorOutput); } - protected override void DrawDebugVectors() - { - base.DrawDebugVectors(); - if (_accelerationCommand != null) - { - Debug.DrawRay(transform.position, _accelerationCommand * 1f, Color.green); - } - } + // Calculate and set the total acceleration + Vector3 acceleration = CalculateAcceleration(accelerationInput, compensateForGravity: true); + GetComponent().AddForce(acceleration, ForceMode.Acceleration); + } + private Vector3 CalculateAccelerationCommand(SensorOutput sensorOutput) { + // Implement Proportional Navigation guidance law + Vector3 accelerationCommand = Vector3.zero; + // Extract relevant information from sensor output + float los_rate_az = sensorOutput.velocity.azimuth; + float los_rate_el = sensorOutput.velocity.elevation; + float closing_velocity = + -sensorOutput.velocity + .range; // Negative because closing velocity is opposite to range rate + + // Navigation gain (adjust as needed) + float N = _navigationGain; + + // Calculate acceleration commands in azimuth and elevation planes + float acc_az = N * closing_velocity * los_rate_az; + float acc_el = N * closing_velocity * los_rate_el; + + // Convert acceleration commands to missile body frame + accelerationCommand = transform.right * acc_az + transform.up * acc_el; + + // Clamp the acceleration command to the maximum acceleration + float maxAcceleration = CalculateMaxAcceleration(); + accelerationCommand = Vector3.ClampMagnitude(accelerationCommand, maxAcceleration); + + // Update the stored acceleration command for debugging + _accelerationCommand = accelerationCommand; + return accelerationCommand; + } + + protected override void DrawDebugVectors() { + base.DrawDebugVectors(); + if (_accelerationCommand != null) { + Debug.DrawRay(transform.position, _accelerationCommand * 1f, Color.green); + } + } } diff --git a/Assets/Scripts/Missile.cs b/Assets/Scripts/Missile.cs index 388b28a..e42794f 100644 --- a/Assets/Scripts/Missile.cs +++ b/Assets/Scripts/Missile.cs @@ -2,171 +2,156 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; -public class Missile : Agent -{ +public class Missile : Agent { + [SerializeField] + protected bool _showDebugVectors = true; - [SerializeField] protected bool _showDebugVectors = true; + [SerializeField] + private Vector3 _boostAcceleration; + // Return whether a target can be assigned to the missile. + public override bool IsAssignable() { + bool assignable = !HasLaunched() && !HasAssignedTarget(); + return assignable; + } - [SerializeField] - private Vector3 _boostAcceleration; - // Return whether a target can be assigned to the missile. - public override bool IsAssignable() { - bool assignable = !HasLaunched() && !HasAssignedTarget(); - return assignable; + // Assign the given target to the missile. + public override void AssignTarget(Agent target) { + base.AssignTarget(target); + } + + // Unassign the target from the missile. + public override void UnassignTarget() { + base.UnassignTarget(); + } + + protected override void UpdateReady(double deltaTime) { + Vector3 accelerationInput = Vector3.zero; + Vector3 acceleration = CalculateAcceleration(accelerationInput); + // GetComponent().AddForce(acceleration, ForceMode.Acceleration); + } + + protected override void Update() { + base.Update(); + if (_showDebugVectors) { + DrawDebugVectors(); + } + } + + protected override void UpdateBoost(double deltaTime) { + // The missile only accelerates along its roll axis (forward in Unity) + Vector3 rollAxis = transform.forward; + + // Calculate boost acceleration + float boostAcceleration = + (float)(StaticConfig.boostConfig.boostAcceleration * Constants.kGravity); + Vector3 accelerationInput = boostAcceleration * rollAxis; + + // Calculate the total acceleration + Vector3 acceleration = CalculateAcceleration(accelerationInput); + + // Apply the acceleration force + GetComponent().AddForce(acceleration, ForceMode.Acceleration); + _boostAcceleration = acceleration; + } + protected override void UpdateMidCourse(double deltaTime) {} + + protected Vector3 CalculateAcceleration(Vector3 accelerationInput, + bool compensateForGravity = false) { + Vector3 gravity = Physics.gravity; + if (compensateForGravity) { + Vector3 gravityProjection = CalculateGravityProjectionOnPitchAndYaw(); + accelerationInput -= gravityProjection; } - // Assign the given target to the missile. - public override void AssignTarget(Agent target) { - base.AssignTarget(target); + float airDrag = CalculateDrag(); + float liftInducedDrag = CalculateLiftInducedDrag(accelerationInput); + float dragAcceleration = -(airDrag + liftInducedDrag); + + // Project the drag acceleration onto the forward direction + Vector3 dragAccelerationAlongRoll = dragAcceleration * transform.forward; + + return accelerationInput + gravity + dragAccelerationAlongRoll; + } + + private void OnTriggerEnter(Collider other) { + if (other.gameObject.name == "Floor") { + this.MarkAsMiss(); } + // Check if the collision is with another Agent + Agent otherAgent = other.gameObject.GetComponentInParent(); + if (otherAgent != null && otherAgent.GetComponent() != null) { + // Check kill probability before marking as hit + float killProbability = StaticConfig.hitConfig.killProbability; + GameObject markerObject = Instantiate(Resources.Load("Prefabs/HitMarkerPrefab"), + transform.position, Quaternion.identity); + if (Random.value <= killProbability) { + // Set green for hit + markerObject.GetComponent().material.color = new Color(0, 1, 0, 0.15f); + // Mark both this agent and the other agent as hit + this.MarkAsHit(); + otherAgent.MarkAsHit(); - - // Unassign the target from the missile. - public override void UnassignTarget() { - base.UnassignTarget(); + } else { + // Set red for miss + markerObject.GetComponent().material.color = new Color(1, 0, 0, 0.15f); + this.MarkAsMiss(); + // otherAgent.MarkAsMiss(); + } } + } - protected override void UpdateReady(double deltaTime) { - Vector3 accelerationInput = Vector3.zero; - Vector3 acceleration = CalculateAcceleration(accelerationInput); - //GetComponent().AddForce(acceleration, ForceMode.Acceleration); - } - - protected override void Update() { - base.Update(); - if(_showDebugVectors) { - DrawDebugVectors(); - } - } - - protected override void UpdateBoost(double deltaTime) - { - // The missile only accelerates along its roll axis (forward in Unity) - Vector3 rollAxis = transform.forward; - - // Calculate boost acceleration - float boostAcceleration = (float)(StaticConfig.boostConfig.boostAcceleration * Constants.kGravity); - Vector3 accelerationInput = boostAcceleration * rollAxis; - - // Calculate the total acceleration - Vector3 acceleration = CalculateAcceleration(accelerationInput); - - // Apply the acceleration force - GetComponent().AddForce(acceleration, ForceMode.Acceleration); - _boostAcceleration = acceleration; - } - protected override void UpdateMidCourse(double deltaTime) { - - } - - protected Vector3 CalculateAcceleration(Vector3 accelerationInput, bool compensateForGravity = false) - { - Vector3 gravity = Physics.gravity; - if (compensateForGravity) - { - Vector3 gravityProjection = CalculateGravityProjectionOnPitchAndYaw(); - accelerationInput -= gravityProjection; - } - - float airDrag = CalculateDrag(); - float liftInducedDrag = CalculateLiftInducedDrag(accelerationInput); - float dragAcceleration = -(airDrag + liftInducedDrag); - - // Project the drag acceleration onto the forward direction - Vector3 dragAccelerationAlongRoll = dragAcceleration * transform.forward; - - return accelerationInput + gravity + dragAccelerationAlongRoll; - } - - private void OnTriggerEnter(Collider other) - { - - if(other.gameObject.name == "Floor") { - this.MarkAsMiss(); - } - // Check if the collision is with another Agent - Agent otherAgent = other.gameObject.GetComponentInParent(); - if (otherAgent != null && otherAgent.GetComponent() != null) - { - // Check kill probability before marking as hit - float killProbability = StaticConfig.hitConfig.killProbability; - GameObject markerObject = Instantiate(Resources.Load("Prefabs/HitMarkerPrefab"), transform.position, Quaternion.identity); - if (Random.value <= killProbability) - { - // Set green for hit - markerObject.GetComponent().material.color = new Color(0, 1, 0, 0.15f); - // Mark both this agent and the other agent as hit - this.MarkAsHit(); - otherAgent.MarkAsHit(); - - } - else { - // Set red for miss - markerObject.GetComponent().material.color = new Color(1, 0, 0, 0.15f); - this.MarkAsMiss(); - //otherAgent.MarkAsMiss(); - - } - } - } - - protected float CalculateMaxAcceleration() - { - float maxReferenceAcceleration = (float)(StaticConfig.accelerationConfig.maxReferenceAcceleration * Constants.kGravity); - float referenceSpeed = StaticConfig.accelerationConfig.referenceSpeed; - return Mathf.Pow(GetComponent().velocity.magnitude / referenceSpeed, 2) * maxReferenceAcceleration; - } - protected Vector3 CalculateGravityProjectionOnPitchAndYaw() - { - Vector3 gravity = Physics.gravity; - Vector3 pitchAxis = transform.right; - Vector3 yawAxis = transform.up; - - // Project the gravity onto the pitch and yaw axes - float gravityProjectionPitchCoefficient = Vector3.Dot(gravity, pitchAxis); - float gravityProjectionYawCoefficient = Vector3.Dot(gravity, yawAxis); - - // Return the sum of the projections - return gravityProjectionPitchCoefficient * pitchAxis + - gravityProjectionYawCoefficient * yawAxis; - } - - private float CalculateDrag() - { - float dragCoefficient = StaticConfig.liftDragConfig.dragCoefficient; - float crossSectionalArea = StaticConfig.bodyConfig.crossSectionalArea; - float mass = StaticConfig.bodyConfig.mass; - float dynamicPressure = (float)GetDynamicPressure(); - float dragForce = dragCoefficient * dynamicPressure * crossSectionalArea; - return dragForce / mass; - } - - private float CalculateLiftInducedDrag(Vector3 accelerationInput) - { - float liftAcceleration = Vector3.Dot(accelerationInput, transform.forward); - float liftDragRatio = StaticConfig.liftDragConfig.liftDragRatio; - return Mathf.Abs(liftAcceleration / liftDragRatio); - } - - - protected virtual void DrawDebugVectors() - { - if (_target != null) - { - // Line of sight - Debug.DrawLine(transform.position, _target.transform.position, new Color(1, 1, 1, 0.15f)); - - // Velocity vector - Debug.DrawRay(transform.position, GetVelocity()*0.01f, new Color(0, 0, 1, 0.15f)); - - // Current forward direction - Debug.DrawRay(transform.position, transform.forward * 5f, Color.yellow); - - // Pitch axis (right) - Debug.DrawRay(transform.position, transform.right * 5f, Color.red); - - // Yaw axis (up) - Debug.DrawRay(transform.position, transform.up * 5f, Color.magenta); - } + protected float CalculateMaxAcceleration() { + float maxReferenceAcceleration = + (float)(StaticConfig.accelerationConfig.maxReferenceAcceleration * Constants.kGravity); + float referenceSpeed = StaticConfig.accelerationConfig.referenceSpeed; + return Mathf.Pow(GetComponent().velocity.magnitude / referenceSpeed, 2) * + maxReferenceAcceleration; + } + protected Vector3 CalculateGravityProjectionOnPitchAndYaw() { + Vector3 gravity = Physics.gravity; + Vector3 pitchAxis = transform.right; + Vector3 yawAxis = transform.up; + + // Project the gravity onto the pitch and yaw axes + float gravityProjectionPitchCoefficient = Vector3.Dot(gravity, pitchAxis); + float gravityProjectionYawCoefficient = Vector3.Dot(gravity, yawAxis); + + // Return the sum of the projections + return gravityProjectionPitchCoefficient * pitchAxis + + gravityProjectionYawCoefficient * yawAxis; + } + + private float CalculateDrag() { + float dragCoefficient = StaticConfig.liftDragConfig.dragCoefficient; + float crossSectionalArea = StaticConfig.bodyConfig.crossSectionalArea; + float mass = StaticConfig.bodyConfig.mass; + float dynamicPressure = (float)GetDynamicPressure(); + float dragForce = dragCoefficient * dynamicPressure * crossSectionalArea; + return dragForce / mass; + } + + private float CalculateLiftInducedDrag(Vector3 accelerationInput) { + float liftAcceleration = Vector3.Dot(accelerationInput, transform.forward); + float liftDragRatio = StaticConfig.liftDragConfig.liftDragRatio; + return Mathf.Abs(liftAcceleration / liftDragRatio); + } + + protected virtual void DrawDebugVectors() { + if (_target != null) { + // Line of sight + Debug.DrawLine(transform.position, _target.transform.position, new Color(1, 1, 1, 0.15f)); + + // Velocity vector + Debug.DrawRay(transform.position, GetVelocity() * 0.01f, new Color(0, 0, 1, 0.15f)); + + // Current forward direction + Debug.DrawRay(transform.position, transform.forward * 5f, Color.yellow); + + // Pitch axis (right) + Debug.DrawRay(transform.position, transform.right * 5f, Color.red); + + // Yaw axis (up) + Debug.DrawRay(transform.position, transform.up * 5f, Color.magenta); } + } } diff --git a/Assets/Scripts/Sensors/IdealSensor.cs b/Assets/Scripts/Sensors/IdealSensor.cs index 29bd94d..9ea6876 100644 --- a/Assets/Scripts/Sensors/IdealSensor.cs +++ b/Assets/Scripts/Sensors/IdealSensor.cs @@ -1,74 +1,71 @@ using UnityEngine; -public class IdealSensor : Sensor -{ - protected override void Start() - { - base.Start(); +public class IdealSensor : Sensor { + protected override void Start() { + base.Start(); + } + + public override SensorOutput Sense(Agent target) { + SensorOutput targetSensorOutput = new SensorOutput(); + + // Sense the target's position + PositionOutput targetPositionSensorOutput = SensePosition(target); + targetSensorOutput.position = targetPositionSensorOutput; + + // Sense the target's velocity + VelocityOutput targetVelocitySensorOutput = SenseVelocity(target); + targetSensorOutput.velocity = targetVelocitySensorOutput; + + return targetSensorOutput; + } + + protected override PositionOutput SensePosition(Agent target) { + PositionOutput positionSensorOutput = new PositionOutput(); + + // Calculate the relative position of the target + Vector3 relativePosition = target.transform.position - transform.position; + + // Calculate the distance (range) to the target + positionSensorOutput.range = relativePosition.magnitude; + + // Calculate azimuth (horizontal angle relative to forward) + positionSensorOutput.azimuth = + Vector3.SignedAngle(transform.forward, relativePosition, transform.up); + + // Calculate elevation (vertical angle relative to forward) + Vector3 flatRelativePosition = Vector3.ProjectOnPlane(relativePosition, transform.up); + positionSensorOutput.elevation = + Vector3.SignedAngle(flatRelativePosition, relativePosition, transform.right); + + return positionSensorOutput; + } + + protected override VelocityOutput SenseVelocity(Agent target) { + VelocityOutput velocitySensorOutput = new VelocityOutput(); + + // Calculate relative position and velocity + Vector3 relativePosition = target.transform.position - transform.position; + Vector3 relativeVelocity = target.GetVelocity() - GetComponent().velocity; + + // Calculate range rate (radial velocity) + velocitySensorOutput.range = Vector3.Dot(relativeVelocity, relativePosition.normalized); + + // Project relative velocity onto a plane perpendicular to relative position + Vector3 tangentialVelocity = + Vector3.ProjectOnPlane(relativeVelocity, relativePosition.normalized); + + // Calculate azimuth rate + Vector3 horizontalVelocity = Vector3.ProjectOnPlane(tangentialVelocity, transform.up); + velocitySensorOutput.azimuth = + Vector3.Dot(horizontalVelocity, transform.right) / relativePosition.magnitude; + + // Calculate elevation rate + Vector3 verticalVelocity = Vector3.Project(tangentialVelocity, transform.up); + velocitySensorOutput.elevation = verticalVelocity.magnitude / relativePosition.magnitude; + if (Vector3.Dot(verticalVelocity, transform.up) < 0) { + velocitySensorOutput.elevation *= -1; } - public override SensorOutput Sense(Agent target) - { - SensorOutput targetSensorOutput = new SensorOutput(); - - // Sense the target's position - PositionOutput targetPositionSensorOutput = SensePosition(target); - targetSensorOutput.position = targetPositionSensorOutput; - - // Sense the target's velocity - VelocityOutput targetVelocitySensorOutput = SenseVelocity(target); - targetSensorOutput.velocity = targetVelocitySensorOutput; - - return targetSensorOutput; - } - - protected override PositionOutput SensePosition(Agent target) - { - PositionOutput positionSensorOutput = new PositionOutput(); - - // Calculate the relative position of the target - Vector3 relativePosition = target.transform.position - transform.position; - - // Calculate the distance (range) to the target - positionSensorOutput.range = relativePosition.magnitude; - - // Calculate azimuth (horizontal angle relative to forward) - positionSensorOutput.azimuth = Vector3.SignedAngle(transform.forward, relativePosition, transform.up); - - // Calculate elevation (vertical angle relative to forward) - Vector3 flatRelativePosition = Vector3.ProjectOnPlane(relativePosition, transform.up); - positionSensorOutput.elevation = Vector3.SignedAngle(flatRelativePosition, relativePosition, transform.right); - - return positionSensorOutput; - } - - protected override VelocityOutput SenseVelocity(Agent target) - { - VelocityOutput velocitySensorOutput = new VelocityOutput(); - - // Calculate relative position and velocity - Vector3 relativePosition = target.transform.position - transform.position; - Vector3 relativeVelocity = target.GetVelocity() - GetComponent().velocity; - - // Calculate range rate (radial velocity) - velocitySensorOutput.range = Vector3.Dot(relativeVelocity, relativePosition.normalized); - - // Project relative velocity onto a plane perpendicular to relative position - Vector3 tangentialVelocity = Vector3.ProjectOnPlane(relativeVelocity, relativePosition.normalized); - - // Calculate azimuth rate - Vector3 horizontalVelocity = Vector3.ProjectOnPlane(tangentialVelocity, transform.up); - velocitySensorOutput.azimuth = Vector3.Dot(horizontalVelocity, transform.right) / relativePosition.magnitude; - - // Calculate elevation rate - Vector3 verticalVelocity = Vector3.Project(tangentialVelocity, transform.up); - velocitySensorOutput.elevation = verticalVelocity.magnitude / relativePosition.magnitude; - if (Vector3.Dot(verticalVelocity, transform.up) < 0) - { - velocitySensorOutput.elevation *= -1; - } - - return velocitySensorOutput; - } + return velocitySensorOutput; + } } - diff --git a/Assets/Scripts/Sensors/Sensor.cs b/Assets/Scripts/Sensors/Sensor.cs index 4be17e5..9fa06c9 100644 --- a/Assets/Scripts/Sensors/Sensor.cs +++ b/Assets/Scripts/Sensors/Sensor.cs @@ -1,75 +1,70 @@ using UnityEngine; -public abstract class Sensor : MonoBehaviour -{ - protected Agent _agent; +public abstract class Sensor : MonoBehaviour { + protected Agent _agent; - protected virtual void Start() - { - _agent = GetComponent(); - } + protected virtual void Start() { + _agent = GetComponent(); + } - /// - /// Main sensing method to gather information about a target agent. - /// - /// The agent to sense. - /// SensorOutput containing position and velocity data. - /// - /// Implementers should: - /// 1. Call SensePosition to get position data. - /// 2. Call SenseVelocity to get velocity data. - /// 3. Combine results into a SensorOutput struct. - /// - public abstract SensorOutput Sense(Agent target); + /// + /// Main sensing method to gather information about a target agent. + /// + /// The agent to sense. + /// SensorOutput containing position and velocity data. + /// + /// Implementers should: + /// 1. Call SensePosition to get position data. + /// 2. Call SenseVelocity to get velocity data. + /// 3. Combine results into a SensorOutput struct. + /// + public abstract SensorOutput Sense(Agent target); - /// - /// Calculates the relative position of the target agent. - /// - /// The agent to sense. - /// PositionOutput containing range, azimuth, and elevation. - /// - /// Implementers should calculate: - /// - range: Distance to the target (in unity units). - /// - azimuth: Horizontal angle to the target (in degrees). - /// Positive is clockwise from the forward direction. - /// - elevation: Vertical angle to the target (in degrees). - /// Positive is above the horizontal plane. - /// - protected abstract PositionOutput SensePosition(Agent target); + /// + /// Calculates the relative position of the target agent. + /// + /// The agent to sense. + /// PositionOutput containing range, azimuth, and elevation. + /// + /// Implementers should calculate: + /// - range: Distance to the target (in unity units). + /// - azimuth: Horizontal angle to the target (in degrees). + /// Positive is clockwise from the forward direction. + /// - elevation: Vertical angle to the target (in degrees). + /// Positive is above the horizontal plane. + /// + protected abstract PositionOutput SensePosition(Agent target); - /// - /// Calculates the relative velocity of the target agent. - /// - /// The agent to sense. - /// VelocityOutput containing range rate, azimuth rate, and elevation rate. - /// - /// Implementers should calculate: - /// - range: Radial velocity (closing speed) in units/second. - /// Positive means the target is moving away. - /// - azimuth: Rate of change of azimuth in degrees/second. - /// Positive means the target is moving clockwise. - /// - elevation: Rate of change of elevation in degrees/second. - /// Positive means the target is moving upwards. - /// - protected abstract VelocityOutput SenseVelocity(Agent target); + /// + /// Calculates the relative velocity of the target agent. + /// + /// The agent to sense. + /// VelocityOutput containing range rate, azimuth rate, and elevation rate. + /// + /// Implementers should calculate: + /// - range: Radial velocity (closing speed) in units/second. + /// Positive means the target is moving away. + /// - azimuth: Rate of change of azimuth in degrees/second. + /// Positive means the target is moving clockwise. + /// - elevation: Rate of change of elevation in degrees/second. + /// Positive means the target is moving upwards. + /// + protected abstract VelocityOutput SenseVelocity(Agent target); } -public struct SensorOutput -{ - public PositionOutput position; - public VelocityOutput velocity; +public struct SensorOutput { + public PositionOutput position; + public VelocityOutput velocity; } -public struct PositionOutput -{ - public float range; - public float azimuth; - public float elevation; +public struct PositionOutput { + public float range; + public float azimuth; + public float elevation; } -public struct VelocityOutput -{ - public float range; - public float azimuth; - public float elevation; +public struct VelocityOutput { + public float range; + public float azimuth; + public float elevation; } \ No newline at end of file diff --git a/Assets/Scripts/SimManager.cs b/Assets/Scripts/SimManager.cs index f7caf28..710308d 100644 --- a/Assets/Scripts/SimManager.cs +++ b/Assets/Scripts/SimManager.cs @@ -3,266 +3,226 @@ using System.Collections.Generic; using System.Linq; using UnityEngine; -public class SimManager : MonoBehaviour -{ +public class SimManager : MonoBehaviour { + // Singleton instance + public static SimManager Instance { get; private set; } - // Singleton instance - public static SimManager Instance { get; private set; } + [SerializeField] + public SimulationConfig simulationConfig; + private List _missiles = new List(); + private List _unassignedTargets = new List(); + private List _targets = new List(); + private float _elapsedSimulationTime = 0f; + private float endTime = 100f; // Set an appropriate end time + private bool simulationRunning = false; - [SerializeField] - public SimulationConfig simulationConfig; + private IAssignment _assignmentScheme; - - private List _missiles = new List(); - private List _unassignedTargets = new List(); - private List _targets = new List(); - private float _elapsedSimulationTime = 0f; - private float endTime = 100f; // Set an appropriate end time - private bool simulationRunning = false; + public double GetElapsedSimulationTime() { + return _elapsedSimulationTime; + } - private IAssignment _assignmentScheme; + void Awake() { + // Ensure only one instance of SimManager exists + if (Instance == null) { + Instance = this; + DontDestroyOnLoad(gameObject); + } else { + Destroy(gameObject); + } + } - public double GetElapsedSimulationTime() - { - return _elapsedSimulationTime; + void Start() { + // Slow down time by simulationConfig.timeScale + if (Instance == this) { + Time.timeScale = simulationConfig.timeScale; + Time.fixedDeltaTime = Time.timeScale * 0.02f; + Time.maximumDeltaTime = Time.timeScale * 0.15f; + InitializeSimulation(); + simulationRunning = true; + } + } + + private void InitializeSimulation() { + List missiles = new List(); + // Create missiles based on config + foreach (var swarmConfig in simulationConfig.missile_swarm_configs) { + for (int i = 0; i < swarmConfig.num_agents; i++) { + var missile = CreateMissile(swarmConfig.agent_config); + } } - void Awake() - { - // Ensure only one instance of SimManager exists - if (Instance == null) - { - Instance = this; - DontDestroyOnLoad(gameObject); - } - else - { - Destroy(gameObject); - } + List targets = new List(); + // Create targets based on config + foreach (var swarmConfig in simulationConfig.target_swarm_configs) { + for (int i = 0; i < swarmConfig.num_agents; i++) { + var target = CreateTarget(swarmConfig.agent_config); + } } - void Start() { - // Slow down time by simulationConfig.timeScale - if(Instance == this) { - Time.timeScale = simulationConfig.timeScale; - Time.fixedDeltaTime = Time.timeScale * 0.02f; - Time.maximumDeltaTime = Time.timeScale * 0.15f; - InitializeSimulation(); - simulationRunning = true; - } + _assignmentScheme = new ThreatAssignment(); + // Perform initial assignment + } + + public void AssignMissilesToTargets() { + AssignMissilesToTargets(_missiles); + } + + public void RegisterTargetMiss(Target target) { + _unassignedTargets.Add(target); + } + + public void AssignMissilesToTargets(List missilesToAssign) { + // Convert Missile and Target lists to Agent lists + List missileAgents = new List(missilesToAssign.ConvertAll(m => m as Agent)); + // Convert Target list to Agent list, excluding already assigned targets + List targetAgents = _unassignedTargets.ToList(); + + // Perform the assignment + IEnumerable assignments = + _assignmentScheme.Assign(missileAgents, targetAgents); + + // Apply the assignments to the missiles + foreach (var assignment in assignments) { + if (assignment.MissileIndex < missilesToAssign.Count) { + Missile missile = missilesToAssign[assignment.MissileIndex]; + Target target = _unassignedTargets[assignment.TargetIndex]; + missile.AssignTarget(target); + Debug.Log($"Missile {missile.name} assigned to target {target.name}"); + } } - - private void InitializeSimulation() - { - List missiles = new List(); - // Create missiles based on config - foreach (var swarmConfig in simulationConfig.missile_swarm_configs) - { - for (int i = 0; i < swarmConfig.num_agents; i++) { - var missile = CreateMissile(swarmConfig.agent_config); - } - } + // TODO this whole function should be optimized + _unassignedTargets.RemoveAll( + target => missilesToAssign.Any(missile => missile.GetAssignedTarget() == target)); + } - List targets = new List(); - // Create targets based on config - foreach (var swarmConfig in simulationConfig.target_swarm_configs) - { - for (int i = 0; i < swarmConfig.num_agents; i++) { - var target = CreateTarget(swarmConfig.agent_config); + public Missile CreateMissile(AgentConfig config) { + string prefabName = config.missile_type switch { MissileType.HYDRA_70 => "Hydra70", + MissileType.MICROMISSILE => "Micromissile", + _ => "Hydra70" }; - } - } + GameObject missileObject = CreateAgent(config, prefabName); + if (missileObject == null) + return null; - _assignmentScheme = new ThreatAssignment(); - // Perform initial assignment + // Missile-specific logic + switch (config.dynamic_config.sensor_config.type) { + case SensorType.IDEAL: + missileObject.AddComponent(); + break; + default: + Debug.LogError($"Sensor type '{config.dynamic_config.sensor_config.type}' not found."); + break; } - public void AssignMissilesToTargets() - { - AssignMissilesToTargets(_missiles); + // Missile missile = missileObject.GetComponent(); + // if (missile == null) + // { + // Debug.LogError($"Missile component not found on prefab '{prefabName}'."); + // Destroy(missileObject); + // return null; + // } + + // missile.SetAgentConfig(config); + _missiles.Add(missileObject.GetComponent()); + // Assign a unique and simple target ID + int missileId = _missiles.Count; + missileObject.name = $"{config.missile_type}_Missile_{missileId}"; + return missileObject.GetComponent(); + } + + private Target CreateTarget(AgentConfig config) { + string prefabName = config.target_type switch { + TargetType.DRONE => "DroneTarget", TargetType.MISSILE => "MissileTarget", + _ => throw new System.ArgumentException($"Unsupported target type: {config.target_type}") + }; + GameObject targetObject = CreateAgent(config, prefabName); + if (targetObject == null) + return null; + + // Target target = targetObject.GetComponent(); + // if (target == null) + // { + // Debug.LogError($"Target component not found on prefab '{config.prefabName}'."); + // Destroy(targetObject); + // return null; + // } + + // target.SetAgentConfig(config); + _targets.Add(targetObject.GetComponent()); + _unassignedTargets.Add(targetObject.GetComponent()); + // Assign a unique and simple target ID + int targetId = _targets.Count; + targetObject.name = $"{config.target_type}_Target_{targetId}"; + return targetObject.GetComponent(); + } + + public GameObject CreateAgent(AgentConfig config, string prefabName) { + GameObject prefab = Resources.Load($"Prefabs/{prefabName}"); + if (prefab == null) { + Debug.LogError($"Prefab '{prefabName}' not found in Resources/Prefabs folder."); + return null; } - public void RegisterTargetMiss(Target target) { - _unassignedTargets.Add(target); + Vector3 noiseOffset = Utilities.GenerateRandomNoise(config.standard_deviation.position); + Vector3 noisyPosition = config.initial_state.position + noiseOffset; + + GameObject agentObject = + Instantiate(prefab, noisyPosition, Quaternion.Euler(config.initial_state.rotation)); + + Rigidbody agentRigidbody = agentObject.GetComponent(); + Vector3 velocityNoise = Utilities.GenerateRandomNoise(config.standard_deviation.velocity); + Vector3 noisyVelocity = config.initial_state.velocity + velocityNoise; + agentRigidbody.velocity = noisyVelocity; + + agentObject.GetComponent().SetAgentConfig(config); + + return agentObject; + } + + private void RestartSimulation() { + // Reset simulation time + _elapsedSimulationTime = 0f; + simulationRunning = true; + + // Clear existing missiles and targets + foreach (var missile in _missiles) { + if (missile != null) { + Destroy(missile.gameObject); + } + } + _missiles.Clear(); + + foreach (var target in _targets) { + if (target != null) { + Destroy(target.gameObject); + } + } + _targets.Clear(); + + InitializeSimulation(); + } + + void Update() { + // Check if all missiles have terminated + bool allMissilesTerminated = true; + foreach (var missile in _missiles) { + if (missile != null && !missile.IsHit() && !missile.IsMiss()) { + allMissilesTerminated = false; + break; + } + } + // If all missiles have terminated, restart the simulation + if (allMissilesTerminated) { + RestartSimulation(); } - public void AssignMissilesToTargets(List missilesToAssign) - { - - // Convert Missile and Target lists to Agent lists - List missileAgents = new List(missilesToAssign.ConvertAll(m => m as Agent)); - // Convert Target list to Agent list, excluding already assigned targets - List targetAgents = _unassignedTargets.ToList(); - - // Perform the assignment - IEnumerable assignments = _assignmentScheme.Assign(missileAgents, targetAgents); - - // Apply the assignments to the missiles - foreach (var assignment in assignments) - { - if (assignment.MissileIndex < missilesToAssign.Count) - { - Missile missile = missilesToAssign[assignment.MissileIndex]; - Target target = _unassignedTargets[assignment.TargetIndex]; - missile.AssignTarget(target); - Debug.Log($"Missile {missile.name} assigned to target {target.name}"); - - } - } - // TODO this whole function should be optimized - _unassignedTargets.RemoveAll(target => missilesToAssign.Any(missile => missile.GetAssignedTarget() == target)); + if (simulationRunning && _elapsedSimulationTime < endTime) { + _elapsedSimulationTime += Time.deltaTime; + } else if (_elapsedSimulationTime >= endTime) { + simulationRunning = false; + Debug.Log("Simulation completed."); } - - public Missile CreateMissile(AgentConfig config) - { - string prefabName = config.missile_type switch - { - MissileType.HYDRA_70 => "Hydra70", - MissileType.MICROMISSILE => "Micromissile", - _ => "Hydra70" - }; - - GameObject missileObject = CreateAgent(config, prefabName); - if (missileObject == null) return null; - - // Missile-specific logic - switch(config.dynamic_config.sensor_config.type) { - case SensorType.IDEAL: - missileObject.AddComponent(); - break; - default: - Debug.LogError($"Sensor type '{config.dynamic_config.sensor_config.type}' not found."); - break; - } - - // Missile missile = missileObject.GetComponent(); - // if (missile == null) - // { - // Debug.LogError($"Missile component not found on prefab '{prefabName}'."); - // Destroy(missileObject); - // return null; - // } - - // missile.SetAgentConfig(config); - _missiles.Add(missileObject.GetComponent()); - // Assign a unique and simple target ID - int missileId = _missiles.Count; - missileObject.name = $"{config.missile_type}_Missile_{missileId}"; - return missileObject.GetComponent(); - } - - private Target CreateTarget(AgentConfig config) - { - string prefabName = config.target_type switch - { - TargetType.DRONE => "DroneTarget", - TargetType.MISSILE => "MissileTarget", - _ => throw new System.ArgumentException($"Unsupported target type: {config.target_type}") - }; - GameObject targetObject = CreateAgent(config, prefabName); - if (targetObject == null) return null; - - // Target target = targetObject.GetComponent(); - // if (target == null) - // { - // Debug.LogError($"Target component not found on prefab '{config.prefabName}'."); - // Destroy(targetObject); - // return null; - // } - - // target.SetAgentConfig(config); - _targets.Add(targetObject.GetComponent()); - _unassignedTargets.Add(targetObject.GetComponent()); - // Assign a unique and simple target ID - int targetId = _targets.Count; - targetObject.name = $"{config.target_type}_Target_{targetId}"; - return targetObject.GetComponent(); - } - - public GameObject CreateAgent(AgentConfig config, string prefabName) - { - GameObject prefab = Resources.Load($"Prefabs/{prefabName}"); - if (prefab == null) - { - Debug.LogError($"Prefab '{prefabName}' not found in Resources/Prefabs folder."); - return null; - } - - Vector3 noiseOffset = Utilities.GenerateRandomNoise(config.standard_deviation.position); - Vector3 noisyPosition = config.initial_state.position + noiseOffset; - - GameObject agentObject = Instantiate(prefab, noisyPosition, Quaternion.Euler(config.initial_state.rotation)); - - Rigidbody agentRigidbody = agentObject.GetComponent(); - Vector3 velocityNoise = Utilities.GenerateRandomNoise(config.standard_deviation.velocity); - Vector3 noisyVelocity = config.initial_state.velocity + velocityNoise; - agentRigidbody.velocity = noisyVelocity; - - agentObject.GetComponent().SetAgentConfig(config); - - return agentObject; - } - - - - private void RestartSimulation() - { - // Reset simulation time - _elapsedSimulationTime = 0f; - simulationRunning = true; - - // Clear existing missiles and targets - foreach (var missile in _missiles) - { - if (missile != null) - { - Destroy(missile.gameObject); - } - } - _missiles.Clear(); - - foreach (var target in _targets) - { - if (target != null) - { - Destroy(target.gameObject); - } - } - _targets.Clear(); - - InitializeSimulation(); - } - - void Update() - { - // Check if all missiles have terminated - bool allMissilesTerminated = true; - foreach (var missile in _missiles) - { - if (missile != null && !missile.IsHit() && !missile.IsMiss()) - { - allMissilesTerminated = false; - break; - } - } - // If all missiles have terminated, restart the simulation - if (allMissilesTerminated) - { - RestartSimulation(); - } - - if (simulationRunning && _elapsedSimulationTime < endTime) - { - _elapsedSimulationTime += Time.deltaTime; - } - else if (_elapsedSimulationTime >= endTime) - { - simulationRunning = false; - Debug.Log("Simulation completed."); - } - - - } - + } } diff --git a/Assets/Scripts/Targets/DroneTarget.cs b/Assets/Scripts/Targets/DroneTarget.cs index 8f569b4..d155d2e 100644 --- a/Assets/Scripts/Targets/DroneTarget.cs +++ b/Assets/Scripts/Targets/DroneTarget.cs @@ -2,29 +2,20 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; -public class DroneTarget : Target -{ - // Start is called before the first frame update - protected override void Start() - { - base.Start(); - } +public class DroneTarget : Target { + // Start is called before the first frame update + protected override void Start() { + base.Start(); + } - // Update is called once per frame - protected override void Update() - { - base.Update(); - } + // Update is called once per frame + protected override void Update() { + base.Update(); + } - protected override void UpdateReady(double deltaTime) { + protected override void UpdateReady(double deltaTime) {} - } + protected override void UpdateBoost(double deltaTime) {} - protected override void UpdateBoost(double deltaTime) { - - } - - protected override void UpdateMidCourse(double deltaTime) { - - } + protected override void UpdateMidCourse(double deltaTime) {} } diff --git a/Assets/Scripts/Targets/MissileTarget.cs b/Assets/Scripts/Targets/MissileTarget.cs index 0b520bb..a756c31 100644 --- a/Assets/Scripts/Targets/MissileTarget.cs +++ b/Assets/Scripts/Targets/MissileTarget.cs @@ -2,17 +2,10 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; -public class MissileTarget : MonoBehaviour -{ - // Start is called before the first frame update - void Start() - { - - } +public class MissileTarget : MonoBehaviour { + // Start is called before the first frame update + void Start() {} - // Update is called once per frame - void Update() - { - - } + // Update is called once per frame + void Update() {} } diff --git a/Assets/Scripts/Targets/Target.cs b/Assets/Scripts/Targets/Target.cs index 0a4e225..a929619 100644 --- a/Assets/Scripts/Targets/Target.cs +++ b/Assets/Scripts/Targets/Target.cs @@ -2,17 +2,16 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; -public abstract class Target : Agent -{ - public override bool IsAssignable() { - return false; - } +public abstract class Target : Agent { + public override bool IsAssignable() { + return false; + } - protected override void Start() { - base.Start(); - } + protected override void Start() { + base.Start(); + } - protected override void Update() { - base.Update(); - } + protected override void Update() { + base.Update(); + } } \ No newline at end of file diff --git a/Assets/Scripts/Utilities.cs b/Assets/Scripts/Utilities.cs index 9d3b400..893c1e4 100644 --- a/Assets/Scripts/Utilities.cs +++ b/Assets/Scripts/Utilities.cs @@ -1,13 +1,9 @@ using UnityEngine; -public static class Utilities -{ - public static Vector3 GenerateRandomNoise(Vector3 standardDeviation) - { - return new Vector3( - Random.Range(-standardDeviation.x, standardDeviation.x), - Random.Range(-standardDeviation.y, standardDeviation.y), - Random.Range(-standardDeviation.z, standardDeviation.z) - ); - } +public static class Utilities { + public static Vector3 GenerateRandomNoise(Vector3 standardDeviation) { + return new Vector3(Random.Range(-standardDeviation.x, standardDeviation.x), + Random.Range(-standardDeviation.y, standardDeviation.y), + Random.Range(-standardDeviation.z, standardDeviation.z)); + } } \ No newline at end of file