Format all files

more-targets
Titan Yuan 2024-09-13 22:45:25 -07:00
parent df4c8dfbfe
commit 9be43821ef
21 changed files with 1197 additions and 1415 deletions

View File

@ -2,3 +2,6 @@ BasedOnStyle: Google
--- ---
Language: CSharp Language: CSharp
ColumnLimit: 100 ColumnLimit: 100
---
Language: Json
DisableFormat: true

View File

@ -5,17 +5,8 @@ using Unity.PlasticSCM.Editor.UI;
using Unity.VisualScripting; using Unity.VisualScripting;
using UnityEngine; using UnityEngine;
public abstract class Agent : MonoBehaviour public abstract class Agent : MonoBehaviour {
{ public enum FlightPhase { INITIALIZED, READY, BOOST, MIDCOURSE, TERMINAL, TERMINATED }
public enum FlightPhase {
INITIALIZED,
READY,
BOOST,
MIDCOURSE,
TERMINAL,
TERMINATED
}
[SerializeField] [SerializeField]
private FlightPhase _flightPhase = FlightPhase.INITIALIZED; private FlightPhase _flightPhase = FlightPhase.INITIALIZED;
@ -34,7 +25,8 @@ public abstract class Agent : MonoBehaviour
public StaticConfig StaticConfig; public StaticConfig StaticConfig;
public void SetFlightPhase(FlightPhase flightPhase) { public void SetFlightPhase(FlightPhase flightPhase) {
Debug.Log($"Setting flight phase to {flightPhase} at time {SimManager.Instance.GetElapsedSimulationTime()}"); Debug.Log(
$"Setting flight phase to {flightPhase} at time {SimManager.Instance.GetElapsedSimulationTime()}");
_timeInPhase = 0; _timeInPhase = 0;
_flightPhase = flightPhase; _flightPhase = flightPhase;
} }
@ -43,7 +35,6 @@ public abstract class Agent : MonoBehaviour
return _flightPhase; return _flightPhase;
} }
public bool HasLaunched() { public bool HasLaunched() {
return (_flightPhase != FlightPhase.INITIALIZED) && (_flightPhase != FlightPhase.READY); return (_flightPhase != FlightPhase.INITIALIZED) && (_flightPhase != FlightPhase.READY);
} }
@ -60,8 +51,7 @@ public abstract class Agent : MonoBehaviour
return true; return true;
} }
public virtual void AssignTarget(Agent target) public virtual void AssignTarget(Agent target) {
{
_target = target; _target = target;
} }
@ -79,8 +69,7 @@ public abstract class Agent : MonoBehaviour
} }
} }
public virtual void UnassignTarget() public virtual void UnassignTarget() {
{
_target = null; _target = null;
} }
@ -107,15 +96,13 @@ public abstract class Agent : MonoBehaviour
public void MarkAsMiss() { public void MarkAsMiss() {
_isMiss = true; _isMiss = true;
if(_target != null) { if (_target != null) {
SimManager.Instance.RegisterTargetMiss(_target as Target); SimManager.Instance.RegisterTargetMiss(_target as Target);
_target = null; _target = null;
} }
TerminateAgent(); TerminateAgent();
} }
public double GetSpeed() { public double GetSpeed() {
return GetComponent<Rigidbody>().velocity.magnitude; return GetComponent<Rigidbody>().velocity.magnitude;
} }
@ -134,18 +121,13 @@ public abstract class Agent : MonoBehaviour
protected abstract void UpdateBoost(double deltaTime); protected abstract void UpdateBoost(double deltaTime);
protected abstract void UpdateMidCourse(double deltaTime); protected abstract void UpdateMidCourse(double deltaTime);
// Start is called before the first frame update // Start is called before the first frame update
protected virtual void Start() protected virtual void Start() {
{
_flightPhase = FlightPhase.READY; _flightPhase = FlightPhase.READY;
} }
// Update is called once per frame // Update is called once per frame
protected virtual void Update() protected virtual void Update() {
{
_timeSinceLaunch += Time.deltaTime; _timeSinceLaunch += Time.deltaTime;
_timeInPhase += Time.deltaTime; _timeInPhase += Time.deltaTime;
@ -153,19 +135,18 @@ public abstract class Agent : MonoBehaviour
var boost_time = launch_time + StaticConfig.boostConfig.boostTime; var boost_time = launch_time + StaticConfig.boostConfig.boostTime;
double elapsedSimulationTime = SimManager.Instance.GetElapsedSimulationTime(); double elapsedSimulationTime = SimManager.Instance.GetElapsedSimulationTime();
if(_flightPhase == FlightPhase.TERMINATED) { if (_flightPhase == FlightPhase.TERMINATED) {
return; return;
} }
if(elapsedSimulationTime >= launch_time && _flightPhase == FlightPhase.READY) { if (elapsedSimulationTime >= launch_time && _flightPhase == FlightPhase.READY) {
SetFlightPhase(FlightPhase.BOOST); SetFlightPhase(FlightPhase.BOOST);
} }
if(_timeSinceLaunch > boost_time && _flightPhase == FlightPhase.BOOST) { if (_timeSinceLaunch > boost_time && _flightPhase == FlightPhase.BOOST) {
SetFlightPhase(FlightPhase.MIDCOURSE); SetFlightPhase(FlightPhase.MIDCOURSE);
} }
AlignWithVelocity(); AlignWithVelocity();
switch (_flightPhase) { switch (_flightPhase) {
case FlightPhase.INITIALIZED: case FlightPhase.INITIALIZED:
break; break;
case FlightPhase.READY: case FlightPhase.READY:
@ -182,8 +163,7 @@ public abstract class Agent : MonoBehaviour
break; break;
} }
} }
protected virtual void AlignWithVelocity() protected virtual void AlignWithVelocity() {
{
Vector3 velocity = GetVelocity(); Vector3 velocity = GetVelocity();
if (velocity.magnitude > 0.1f) // Only align if we have significant velocity if (velocity.magnitude > 0.1f) // Only align if we have significant velocity
{ {
@ -191,8 +171,8 @@ public abstract class Agent : MonoBehaviour
Quaternion targetRotation = Quaternion.LookRotation(velocity, Vector3.up); Quaternion targetRotation = Quaternion.LookRotation(velocity, Vector3.up);
// Smoothly rotate towards the target rotation // Smoothly rotate towards the target rotation
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, 1000f * Time.deltaTime); transform.rotation =
Quaternion.RotateTowards(transform.rotation, targetRotation, 1000f * Time.deltaTime);
} }
} }
} }

View File

@ -3,18 +3,15 @@ using System.Collections.Generic;
using UnityEngine; using UnityEngine;
// The assignment class is an interface for assigning a target to each missile. // The assignment class is an interface for assigning a target to each missile.
public interface IAssignment public interface IAssignment {
{
// Assignment item type. // Assignment item type.
// The first element corresponds to the missile index, and the second element // The first element corresponds to the missile index, and the second element
// corresponds to the target index. // corresponds to the target index.
public struct AssignmentItem public struct AssignmentItem {
{
public int MissileIndex; public int MissileIndex;
public int TargetIndex; public int TargetIndex;
public AssignmentItem(int missileIndex, int targetIndex) public AssignmentItem(int missileIndex, int targetIndex) {
{
MissileIndex = missileIndex; MissileIndex = missileIndex;
TargetIndex = targetIndex; TargetIndex = targetIndex;
} }
@ -26,13 +23,10 @@ public interface IAssignment
public abstract IEnumerable<AssignmentItem> Assign(List<Agent> missiles, List<Agent> targets); public abstract IEnumerable<AssignmentItem> Assign(List<Agent> missiles, List<Agent> targets);
// Get the list of assignable missile indices. // Get the list of assignable missile indices.
protected static List<int> GetAssignableMissileIndices(List<Agent> missiles) protected static List<int> GetAssignableMissileIndices(List<Agent> missiles) {
{
List<int> assignableMissileIndices = new List<int>(); List<int> assignableMissileIndices = new List<int>();
for (int missileIndex = 0; missileIndex < missiles.Count; missileIndex++) for (int missileIndex = 0; missileIndex < missiles.Count; missileIndex++) {
{ if (missiles[missileIndex].IsAssignable()) {
if (missiles[missileIndex].IsAssignable())
{
assignableMissileIndices.Add(missileIndex); assignableMissileIndices.Add(missileIndex);
} }
} }
@ -40,13 +34,10 @@ public interface IAssignment
} }
// Get the list of active target indices. // Get the list of active target indices.
protected static List<int> GetActiveTargetIndices(List<Agent> targets) protected static List<int> GetActiveTargetIndices(List<Agent> targets) {
{
List<int> activeTargetIndices = new List<int>(); List<int> activeTargetIndices = new List<int>();
for (int targetIndex = 0; targetIndex < targets.Count; targetIndex++) for (int targetIndex = 0; targetIndex < targets.Count; targetIndex++) {
{ if (!targets[targetIndex].IsHit()) {
if (!targets[targetIndex].IsHit())
{
activeTargetIndices.Add(targetIndex); activeTargetIndices.Add(targetIndex);
} }
} }

View File

@ -5,34 +5,27 @@ using UnityEngine;
// The round-robin assignment class assigns missiles to the targets in a // The round-robin assignment class assigns missiles to the targets in a
// round-robin order. // round-robin order.
public class RoundRobinAssignment : IAssignment public class RoundRobinAssignment : IAssignment {
{
// Previous target index that was assigned. // Previous target index that was assigned.
private int prevTargetIndex = -1; private int prevTargetIndex = -1;
// Assign a target to each missile that has not been assigned a target yet. // Assign a target to each missile that has not been assigned a target yet.
public IEnumerable<IAssignment.AssignmentItem> Assign(List<Agent> missiles, List<Agent> targets) public IEnumerable<IAssignment.AssignmentItem> Assign(List<Agent> missiles, List<Agent> targets) {
{
List<IAssignment.AssignmentItem> assignments = new List<IAssignment.AssignmentItem>(); List<IAssignment.AssignmentItem> assignments = new List<IAssignment.AssignmentItem>();
List<int> assignableMissileIndices = IAssignment.GetAssignableMissileIndices(missiles); List<int> assignableMissileIndices = IAssignment.GetAssignableMissileIndices(missiles);
if (assignableMissileIndices.Count == 0) if (assignableMissileIndices.Count == 0) {
{
return assignments; return assignments;
} }
List<int> activeTargetIndices = IAssignment.GetActiveTargetIndices(targets); List<int> activeTargetIndices = IAssignment.GetActiveTargetIndices(targets);
if (activeTargetIndices.Count == 0) if (activeTargetIndices.Count == 0) {
{
return assignments; return assignments;
} }
foreach (int missileIndex in assignableMissileIndices) foreach (int missileIndex in assignableMissileIndices) {
{ int nextActiveTargetIndex = activeTargetIndices.FindIndex(index => index > prevTargetIndex);
int nextActiveTargetIndex = activeTargetIndices
.FindIndex(index => index > prevTargetIndex);
if (nextActiveTargetIndex == -1) if (nextActiveTargetIndex == -1) {
{
nextActiveTargetIndex = 0; nextActiveTargetIndex = 0;
} }

View File

@ -6,52 +6,47 @@ using UnityEngine;
// The threat assignment class assigns missiles to the targets based // The threat assignment class assigns missiles to the targets based
// on the threat level of the targets. // on the threat level of the targets.
public class ThreatAssignment : IAssignment public class ThreatAssignment : IAssignment {
{
// Assign a target to each missile that has not been assigned a target yet. // Assign a target to each missile that has not been assigned a target yet.
public IEnumerable<IAssignment.AssignmentItem> Assign(List<Agent> missiles, List<Agent> targets) public IEnumerable<IAssignment.AssignmentItem> Assign(List<Agent> missiles, List<Agent> targets) {
{
List<IAssignment.AssignmentItem> assignments = new List<IAssignment.AssignmentItem>(); List<IAssignment.AssignmentItem> assignments = new List<IAssignment.AssignmentItem>();
List<int> assignableMissileIndices = IAssignment.GetAssignableMissileIndices(missiles); List<int> assignableMissileIndices = IAssignment.GetAssignableMissileIndices(missiles);
if (assignableMissileIndices.Count == 0) if (assignableMissileIndices.Count == 0) {
{
return assignments; return assignments;
} }
List<int> activeTargetIndices = IAssignment.GetActiveTargetIndices(targets); List<int> activeTargetIndices = IAssignment.GetActiveTargetIndices(targets);
if (activeTargetIndices.Count == 0) if (activeTargetIndices.Count == 0) {
{
return assignments; return assignments;
} }
Vector3 positionToDefend = Vector3.zero; Vector3 positionToDefend = Vector3.zero;
List<ThreatInfo> threatInfos = CalculateThreatLevels(targets, activeTargetIndices, positionToDefend); List<ThreatInfo> threatInfos =
CalculateThreatLevels(targets, activeTargetIndices, positionToDefend);
foreach (int missileIndex in assignableMissileIndices) foreach (int missileIndex in assignableMissileIndices) {
{ if (missiles[missileIndex].HasAssignedTarget())
if (missiles[missileIndex].HasAssignedTarget()) continue; continue;
if (threatInfos.Count == 0) break; if (threatInfos.Count == 0)
break;
// Find the optimal target for this missile based on distance and threat // Find the optimal target for this missile based on distance and threat
ThreatInfo optimalTarget = null; ThreatInfo optimalTarget = null;
float optimalScore = float.MinValue; float optimalScore = float.MinValue;
foreach (ThreatInfo threat in threatInfos) foreach (ThreatInfo threat in threatInfos) {
{ float distance = Vector3.Distance(missiles[missileIndex].transform.position,
float distance = Vector3.Distance(missiles[missileIndex].transform.position, targets[threat.TargetIndex].transform.position); targets[threat.TargetIndex].transform.position);
float score = threat.ThreatLevel / distance; // Balance threat level with proximity float score = threat.ThreatLevel / distance; // Balance threat level with proximity
if (score > optimalScore) if (score > optimalScore) {
{
optimalScore = score; optimalScore = score;
optimalTarget = threat; optimalTarget = threat;
} }
} }
if (optimalTarget != null) if (optimalTarget != null) {
{
assignments.Add(new IAssignment.AssignmentItem(missileIndex, optimalTarget.TargetIndex)); assignments.Add(new IAssignment.AssignmentItem(missileIndex, optimalTarget.TargetIndex));
threatInfos.Remove(optimalTarget); threatInfos.Remove(optimalTarget);
} }
@ -59,13 +54,11 @@ public class ThreatAssignment : IAssignment
return assignments; return assignments;
} }
private List<ThreatInfo> CalculateThreatLevels(List<Agent> targets, List<int> activeTargetIndices,
private List<ThreatInfo> CalculateThreatLevels(List<Agent> targets, List<int> activeTargetIndices, Vector3 missilesMeanPosition) Vector3 missilesMeanPosition) {
{
List<ThreatInfo> threatInfos = new List<ThreatInfo>(); List<ThreatInfo> threatInfos = new List<ThreatInfo>();
foreach (int targetIndex in activeTargetIndices) foreach (int targetIndex in activeTargetIndices) {
{
Agent target = targets[targetIndex]; Agent target = targets[targetIndex];
float distanceToMean = Vector3.Distance(target.transform.position, missilesMeanPosition); float distanceToMean = Vector3.Distance(target.transform.position, missilesMeanPosition);
float velocityMagnitude = target.GetVelocity().magnitude; float velocityMagnitude = target.GetVelocity().magnitude;
@ -80,13 +73,11 @@ public class ThreatAssignment : IAssignment
return threatInfos.OrderByDescending(t => t.ThreatLevel).ToList(); return threatInfos.OrderByDescending(t => t.ThreatLevel).ToList();
} }
private class ThreatInfo private class ThreatInfo {
{
public int TargetIndex { get; } public int TargetIndex { get; }
public float ThreatLevel { get; } public float ThreatLevel { get; }
public ThreatInfo(int targetIndex, float threatLevel) public ThreatInfo(int targetIndex, float threatLevel) {
{
TargetIndex = targetIndex; TargetIndex = targetIndex;
ThreatLevel = threatLevel; ThreatLevel = threatLevel;
} }

View File

@ -3,8 +3,8 @@ using System.Collections.Generic;
using UnityEngine; using UnityEngine;
[CreateAssetMenu(fileName = "SimulationConfig", menuName = "Simulation/Config", order = 1)] [CreateAssetMenu(fileName = "SimulationConfig", menuName = "Simulation/Config", order = 1)]
public class SimulationConfig : ScriptableObject public class SimulationConfig : ScriptableObject {
{ [Header("Simulation Settings")] [Header("Simulation Settings")]
public float timeScale = 0.05f; public float timeScale = 0.05f;
[Header("Missile Swarm Configurations")] [Header("Missile Swarm Configurations")]
@ -12,27 +12,22 @@ public class SimulationConfig : ScriptableObject
[Header("Target Swarm Configurations")] [Header("Target Swarm Configurations")]
public List<SwarmConfig> target_swarm_configs = new List<SwarmConfig>(); public List<SwarmConfig> target_swarm_configs = new List<SwarmConfig>();
} }
[System.Serializable] [System.Serializable]
public class DynamicConfig public class DynamicConfig {
{
public LaunchConfig launch_config; public LaunchConfig launch_config;
public SensorConfig sensor_config; public SensorConfig sensor_config;
} }
[System.Serializable] [System.Serializable]
public class SwarmConfig public class SwarmConfig {
{
public int num_agents; public int num_agents;
public AgentConfig agent_config; public AgentConfig agent_config;
} }
[System.Serializable] [System.Serializable]
public class AgentConfig public class AgentConfig {
{
public MissileType missile_type; public MissileType missile_type;
public TargetType target_type; public TargetType target_type;
public InitialState initial_state; public InitialState initial_state;
@ -41,10 +36,8 @@ public class AgentConfig
public PlottingConfig plotting_config; public PlottingConfig plotting_config;
public SubmunitionsConfig submunitions_config; public SubmunitionsConfig submunitions_config;
public static AgentConfig FromSubmunitionAgentConfig(SubmunitionAgentConfig submunitionConfig) public static AgentConfig FromSubmunitionAgentConfig(SubmunitionAgentConfig submunitionConfig) {
{ return new AgentConfig {
return new AgentConfig
{
missile_type = submunitionConfig.missile_type, missile_type = submunitionConfig.missile_type,
initial_state = submunitionConfig.initial_state, initial_state = submunitionConfig.initial_state,
standard_deviation = submunitionConfig.standard_deviation, standard_deviation = submunitionConfig.standard_deviation,
@ -59,45 +52,39 @@ public class AgentConfig
} }
[System.Serializable] [System.Serializable]
public class InitialState public class InitialState {
{
public Vector3 position; public Vector3 position;
public Vector3 rotation; public Vector3 rotation;
public Vector3 velocity; public Vector3 velocity;
} }
[System.Serializable] [System.Serializable]
public class StandardDeviation public class StandardDeviation {
{
public Vector3 position; public Vector3 position;
public Vector3 velocity; public Vector3 velocity;
} }
[System.Serializable] [System.Serializable]
public class LaunchConfig public class LaunchConfig {
{
public float launch_time; public float launch_time;
} }
[System.Serializable] [System.Serializable]
public class PlottingConfig public class PlottingConfig {
{
public Color color; public Color color;
public LineStyle linestyle; public LineStyle linestyle;
public Marker marker; public Marker marker;
} }
[System.Serializable] [System.Serializable]
public class SubmunitionsConfig public class SubmunitionsConfig {
{
public int num_submunitions; public int num_submunitions;
public LaunchConfig launch_config; public LaunchConfig launch_config;
public SubmunitionAgentConfig agent_config; public SubmunitionAgentConfig agent_config;
} }
[System.Serializable] [System.Serializable]
public class SubmunitionAgentConfig public class SubmunitionAgentConfig {
{
public MissileType missile_type; public MissileType missile_type;
public InitialState initial_state; public InitialState initial_state;
public StandardDeviation standard_deviation; public StandardDeviation standard_deviation;
@ -106,54 +93,27 @@ public class SubmunitionAgentConfig
} }
[System.Serializable] [System.Serializable]
public class SensorConfig public class SensorConfig {
{
public SensorType type; public SensorType type;
public float frequency; public float frequency;
} }
[System.Serializable] [System.Serializable]
public class TargetConfig public class TargetConfig {
{
public TargetType target_type; public TargetType target_type;
public InitialState initial_state; public InitialState initial_state;
public PlottingConfig plotting_config; public PlottingConfig plotting_config;
public string prefabName; public string prefabName;
} }
public enum MissileType public enum MissileType { HYDRA_70, MICROMISSILE }
{
HYDRA_70,
MICROMISSILE
}
public enum TargetType public enum TargetType { DRONE, MISSILE }
{
DRONE,
MISSILE
}
public enum ConfigColor public enum ConfigColor { BLUE, GREEN, RED }
{
BLUE,
GREEN,
RED
}
public enum LineStyle public enum LineStyle { DOTTED, SOLID }
{
DOTTED,
SOLID
}
public enum Marker public enum Marker { TRIANGLE_UP, TRIANGLE_DOWN, SQUARE }
{
TRIANGLE_UP,
TRIANGLE_DOWN,
SQUARE
}
public enum SensorType public enum SensorType { IDEAL }
{
IDEAL
}

View File

@ -3,11 +3,9 @@ using System.Collections.Generic;
using UnityEngine; using UnityEngine;
[System.Serializable] [System.Serializable]
public class StaticConfig public class StaticConfig {
{
[System.Serializable] [System.Serializable]
public class AccelerationConfig public class AccelerationConfig {
{
[Tooltip("Maximum reference acceleration")] [Tooltip("Maximum reference acceleration")]
public float maxReferenceAcceleration = 300f; public float maxReferenceAcceleration = 300f;
[Tooltip("Reference speed")] [Tooltip("Reference speed")]
@ -15,8 +13,7 @@ public class StaticConfig
} }
[System.Serializable] [System.Serializable]
public class BoostConfig public class BoostConfig {
{
[Tooltip("Boost time in seconds")] [Tooltip("Boost time in seconds")]
public float boostTime = 0.3f; public float boostTime = 0.3f;
[Tooltip("Boost acceleration")] [Tooltip("Boost acceleration")]
@ -24,8 +21,7 @@ public class StaticConfig
} }
[System.Serializable] [System.Serializable]
public class LiftDragConfig public class LiftDragConfig {
{
[Tooltip("Lift coefficient")] [Tooltip("Lift coefficient")]
public float liftCoefficient = 0.2f; public float liftCoefficient = 0.2f;
[Tooltip("Drag coefficient")] [Tooltip("Drag coefficient")]
@ -35,8 +31,7 @@ public class StaticConfig
} }
[System.Serializable] [System.Serializable]
public class BodyConfig public class BodyConfig {
{
[Tooltip("Mass in kg")] [Tooltip("Mass in kg")]
public float mass = 0.37f; public float mass = 0.37f;
[Tooltip("Cross-sectional area in m²")] [Tooltip("Cross-sectional area in m²")]
@ -48,8 +43,7 @@ public class StaticConfig
} }
[System.Serializable] [System.Serializable]
public class HitConfig public class HitConfig {
{
[Tooltip("Hit radius")] [Tooltip("Hit radius")]
public float hitRadius = 1f; public float hitRadius = 1f;
[Tooltip("Kill probability")] [Tooltip("Kill probability")]

View File

@ -1,20 +1,17 @@
using System; using System;
public static class Constants public static class Constants {
{
// Constants (these should be defined with appropriate values) // 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 kAirDensity = 1.204; // Sea level air density in kg/m^3
public const double kAirDensityScaleHeight = 10.4; // Scale height in km 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 kGravity = 9.80665; // Standard gravity in m/s^2
public const double kEarthMeanRadius = 6378137; // Earth's mean radius in meters public const double kEarthMeanRadius = 6378137; // Earth's mean radius in meters
public static double CalculateAirDensityAtAltitude(double altitude) public static double CalculateAirDensityAtAltitude(double altitude) {
{
return kAirDensity * Math.Exp(-altitude / (kAirDensityScaleHeight * 1000)); return kAirDensity * Math.Exp(-altitude / (kAirDensityScaleHeight * 1000));
} }
public static double CalculateGravityAtAltitude(double altitude) public static double CalculateGravityAtAltitude(double altitude) {
{
return kGravity * Math.Pow(kEarthMeanRadius / (kEarthMeanRadius + altitude), 2); return kGravity * Math.Pow(kEarthMeanRadius / (kEarthMeanRadius + altitude), 2);
} }
} }

View File

@ -3,26 +3,21 @@ using UnityEditor;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
public class GenerateCone : EditorWindow public class GenerateCone : EditorWindow {
{
private int sides = 16; private int sides = 16;
private float baseRadius = 1f; private float baseRadius = 1f;
private float height = 2f; private float height = 2f;
[MenuItem("GameObject/3D Object/Cone", false, 10)] [MenuItem("GameObject/3D Object/Cone", false, 10)]
static void CreateCone() static void CreateCone() {
{
GameObject cone; GameObject cone;
GameObject selectedObject = Selection.activeGameObject; GameObject selectedObject = Selection.activeGameObject;
if (selectedObject != null) if (selectedObject != null) {
{
// Create as child of selected object // Create as child of selected object
cone = new GameObject("Cone"); cone = new GameObject("Cone");
cone.transform.SetParent(selectedObject.transform, false); cone.transform.SetParent(selectedObject.transform, false);
} } else {
else
{
// Create as new root object // Create as new root object
cone = new GameObject("Cone"); cone = new GameObject("Cone");
} }
@ -37,14 +32,13 @@ public class GenerateCone : EditorWindow
Selection.activeGameObject = cone; Selection.activeGameObject = cone;
} }
void GenerateConeObject(GameObject cone) void GenerateConeObject(GameObject cone) {
{ Mesh mesh =
Mesh mesh = CreateConeMesh("ConeMesh", sides, Vector3.zero, Quaternion.identity, baseRadius, height); CreateConeMesh("ConeMesh", sides, Vector3.zero, Quaternion.identity, baseRadius, height);
// Save the mesh as an asset // Save the mesh as an asset
string path = "Assets/Meshes"; string path = "Assets/Meshes";
if (!AssetDatabase.IsValidFolder(path)) if (!AssetDatabase.IsValidFolder(path)) {
{
AssetDatabase.CreateFolder("Assets", "Meshes"); AssetDatabase.CreateFolder("Assets", "Meshes");
} }
string assetPath = AssetDatabase.GenerateUniqueAssetPath(path + "/ConeMesh.asset"); string assetPath = AssetDatabase.GenerateUniqueAssetPath(path + "/ConeMesh.asset");
@ -56,13 +50,11 @@ public class GenerateCone : EditorWindow
cone.GetComponent<MeshRenderer>().material = new Material(Shader.Find("Standard")); cone.GetComponent<MeshRenderer>().material = new Material(Shader.Find("Standard"));
} }
Vector2[] GetBasePoints(int vertices, float radius) Vector2[] GetBasePoints(int vertices, float radius) {
{
const float TAU = 2f * Mathf.PI; const float TAU = 2f * Mathf.PI;
var pts = new Vector2[vertices]; var pts = new Vector2[vertices];
var step = TAU / vertices; // angular step between two vertices var step = TAU / vertices; // angular step between two vertices
for (int i = 0; i < vertices; i++) for (int i = 0; i < vertices; i++) {
{
pts[i] = radius * Trig(i * step); // convert polar coordinate to cartesian space pts[i] = radius * Trig(i * step); // convert polar coordinate to cartesian space
} }
return pts; return pts;
@ -70,22 +62,22 @@ public class GenerateCone : EditorWindow
static Vector2 Trig(float rad) => new Vector2(Mathf.Cos(rad), Mathf.Sin(rad)); static Vector2 Trig(float rad) => new Vector2(Mathf.Cos(rad), Mathf.Sin(rad));
Vector3[] BuildConeVertices(Vector2[] baseVerts, float coneHeight) Vector3[] BuildConeVertices(Vector2[] baseVerts, float coneHeight) {
{ if (baseVerts == null || baseVerts.Length < 3)
if (baseVerts == null || baseVerts.Length < 3) throw new InvalidOperationException("Requires at least 3 base vertices."); throw new InvalidOperationException("Requires at least 3 base vertices.");
var verts = new Vector3[baseVerts.Length + 1]; var verts = new Vector3[baseVerts.Length + 1];
verts[0] = new Vector3(0f, coneHeight, 0f); verts[0] = new Vector3(0f, coneHeight, 0f);
for (int i = 0; i < baseVerts.Length; i++) for (int i = 0; i < baseVerts.Length; i++) {
{
verts[i + 1] = new Vector3(baseVerts[i].x, 0f, baseVerts[i].y); verts[i + 1] = new Vector3(baseVerts[i].x, 0f, baseVerts[i].y);
} }
return verts; return verts;
} }
void ConstructCone(Vector3[] coneVerts, List<Vector3> finalVerts, List<int> triangles) void ConstructCone(Vector3[] coneVerts, List<Vector3> finalVerts, List<int> triangles) {
{ if (coneVerts == null || coneVerts.Length < 4)
if (coneVerts == null || coneVerts.Length < 4) throw new InvalidOperationException("Requires at least 4 vertices."); throw new InvalidOperationException("Requires at least 4 vertices.");
if (finalVerts == null || triangles == null) throw new ArgumentNullException(); if (finalVerts == null || triangles == null)
throw new ArgumentNullException();
finalVerts.Clear(); finalVerts.Clear();
triangles.Clear(); triangles.Clear();
@ -93,20 +85,17 @@ public class GenerateCone : EditorWindow
var rimVertices = coneVerts.Length - 1; var rimVertices = coneVerts.Length - 1;
// Side faces // Side faces
for (int i = 1; i <= rimVertices; i++) for (int i = 1; i <= rimVertices; i++) {
{
int a = i, b = i < rimVertices ? i + 1 : 1; int a = i, b = i < rimVertices ? i + 1 : 1;
AddTriangle(coneVerts[0], coneVerts[b], coneVerts[a]); AddTriangle(coneVerts[0], coneVerts[b], coneVerts[a]);
} }
// Base face // Base face
for (int i = 1; i < rimVertices - 1; i++) for (int i = 1; i < rimVertices - 1; i++) {
{
AddTriangle(coneVerts[1], coneVerts[i + 1], coneVerts[i + 2]); AddTriangle(coneVerts[1], coneVerts[i + 1], coneVerts[i + 2]);
} }
void AddTriangle(Vector3 t1, Vector3 t2, Vector3 t3) void AddTriangle(Vector3 t1, Vector3 t2, Vector3 t3) {
{
finalVerts.Add(t1); finalVerts.Add(t1);
finalVerts.Add(t2); finalVerts.Add(t2);
finalVerts.Add(t3); finalVerts.Add(t3);
@ -115,8 +104,8 @@ public class GenerateCone : EditorWindow
triangles.Add(finalVerts.Count - 1); triangles.Add(finalVerts.Count - 1);
} }
} }
Mesh CreateConeMesh(string name, int sides, Vector3 apex, Quaternion rotation, float baseRadius, float height) Mesh CreateConeMesh(string name, int sides, Vector3 apex, Quaternion rotation, float baseRadius,
{ float height) {
var baseVerts = GetBasePoints(sides, baseRadius); var baseVerts = GetBasePoints(sides, baseRadius);
var coneVerts = BuildConeVertices(baseVerts, height); var coneVerts = BuildConeVertices(baseVerts, height);
@ -124,15 +113,13 @@ public class GenerateCone : EditorWindow
var tris = new List<int>(); var tris = new List<int>();
ConstructCone(coneVerts, verts, tris); ConstructCone(coneVerts, verts, tris);
for (int i = 0; i < verts.Count; i++) for (int i = 0; i < verts.Count; i++) {
{
verts[i] = rotation * (verts[i] - coneVerts[0]); verts[i] = rotation * (verts[i] - coneVerts[0]);
} }
// Recenter the cone // Recenter the cone
Vector3 center = CalculateCenter(verts); Vector3 center = CalculateCenter(verts);
for (int i = 0; i < verts.Count; i++) for (int i = 0; i < verts.Count; i++) {
{
verts[i] = verts[i] - center + apex; verts[i] = verts[i] - center + apex;
} }
@ -145,11 +132,9 @@ public class GenerateCone : EditorWindow
return mesh; return mesh;
} }
Vector3 CalculateCenter(List<Vector3> vertices) Vector3 CalculateCenter(List<Vector3> vertices) {
{
Vector3 sum = Vector3.zero; Vector3 sum = Vector3.zero;
foreach (Vector3 vert in vertices) foreach (Vector3 vert in vertices) {
{
sum += vert; sum += vert;
} }
return sum / vertices.Count; return sum / vertices.Count;

View File

@ -4,16 +4,8 @@ using System.Collections;
using System; using System;
// Integrated Air Defense 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 // Look up target status by unique target ID
public Dictionary<string, TargetStatus> _targetStatusDictionary; public Dictionary<string, TargetStatus> _targetStatusDictionary;
@ -27,8 +19,7 @@ public class IADS : MonoBehaviour
public delegate void RegisterNewTargetDelegate(Target target); public delegate void RegisterNewTargetDelegate(Target target);
public event RegisterNewTargetDelegate OnRegisterNewTarget; public event RegisterNewTargetDelegate OnRegisterNewTarget;
void Start() void Start() {
{
_targets = new List<Target>(); _targets = new List<Target>();
} }

View File

@ -1,31 +1,25 @@
using UnityEngine; using UnityEngine;
using System.Collections.Generic; using System.Collections.Generic;
public class Vessel : MonoBehaviour public class Vessel : MonoBehaviour {
{
[SerializeField] [SerializeField]
private List<Missile> missileInventory = new List<Missile>(); private List<Missile> missileInventory = new List<Missile>();
public void AddMissile(Missile missile) public void AddMissile(Missile missile) {
{ if (missile != null) {
if (missile != null)
{
missileInventory.Add(missile); missileInventory.Add(missile);
} }
} }
public void RemoveMissile(Missile missile) public void RemoveMissile(Missile missile) {
{
missileInventory.Remove(missile); missileInventory.Remove(missile);
} }
public List<Missile> GetMissileInventory() public List<Missile> GetMissileInventory() {
{
return new List<Missile>(missileInventory); return new List<Missile>(missileInventory);
} }
public int GetMissileCount() public int GetMissileCount() {
{
return missileInventory.Count; return missileInventory.Count;
} }

View File

@ -3,27 +3,24 @@ using System.Collections.Generic;
using JetBrains.Annotations; using JetBrains.Annotations;
using UnityEngine; using UnityEngine;
public class Hydra70 : Missile public class Hydra70 : Missile {
{
private Vector3 _acceleration; private Vector3 _acceleration;
private bool _submunitionsLaunched = false; private bool _submunitionsLaunched = false;
protected override void Update() { protected override void Update() {
base.Update(); base.Update();
// Check if it's time to launch submunitions // Check if it's time to launch submunitions
if (!_submunitionsLaunched && (GetFlightPhase() == FlightPhase.MIDCOURSE || GetFlightPhase() == FlightPhase.BOOST) && if (!_submunitionsLaunched &&
SimManager.Instance.GetElapsedSimulationTime() >= _agentConfig.submunitions_config.launch_config.launch_time) (GetFlightPhase() == FlightPhase.MIDCOURSE || GetFlightPhase() == FlightPhase.BOOST) &&
{ SimManager.Instance.GetElapsedSimulationTime() >=
_agentConfig.submunitions_config.launch_config.launch_time) {
SpawnSubmunitions(); SpawnSubmunitions();
_submunitionsLaunched = true; _submunitionsLaunched = true;
} }
} }
protected override void UpdateMidCourse(double deltaTime) protected override void UpdateMidCourse(double deltaTime) {
{
Vector3 accelerationInput = Vector3.zero; Vector3 accelerationInput = Vector3.zero;
// Calculate and set the total acceleration // Calculate and set the total acceleration
Vector3 acceleration = CalculateAcceleration(accelerationInput); Vector3 acceleration = CalculateAcceleration(accelerationInput);
@ -31,11 +28,9 @@ public class Hydra70 : Missile
_acceleration = acceleration; _acceleration = acceleration;
} }
protected override void DrawDebugVectors() protected override void DrawDebugVectors() {
{
base.DrawDebugVectors(); base.DrawDebugVectors();
if (_acceleration != null) if (_acceleration != null) {
{
Debug.DrawRay(transform.position, _acceleration * 1f, Color.green); Debug.DrawRay(transform.position, _acceleration * 1f, Color.green);
} }
} }
@ -45,10 +40,11 @@ public class Hydra70 : Missile
// print the callstack // print the callstack
Debug.Log(new System.Diagnostics.StackTrace().ToString()); Debug.Log(new System.Diagnostics.StackTrace().ToString());
List<Missile> submunitions = new List<Missile>(); List<Missile> submunitions = new List<Missile>();
switch(_agentConfig.submunitions_config.agent_config.missile_type) { switch (_agentConfig.submunitions_config.agent_config.missile_type) {
case MissileType.MICROMISSILE: case MissileType.MICROMISSILE:
for (int i = 0; i < _agentConfig.submunitions_config.num_submunitions; i++) { for (int i = 0; i < _agentConfig.submunitions_config.num_submunitions; i++) {
AgentConfig convertedConfig = AgentConfig.FromSubmunitionAgentConfig(_agentConfig.submunitions_config.agent_config); AgentConfig convertedConfig =
AgentConfig.FromSubmunitionAgentConfig(_agentConfig.submunitions_config.agent_config);
convertedConfig.initial_state.position = transform.position; convertedConfig.initial_state.position = transform.position;
convertedConfig.initial_state.velocity = GetComponent<Rigidbody>().velocity; convertedConfig.initial_state.velocity = GetComponent<Rigidbody>().velocity;
@ -59,7 +55,5 @@ public class Hydra70 : Missile
break; break;
} }
SimManager.Instance.AssignMissilesToTargets(submunitions); SimManager.Instance.AssignMissilesToTargets(submunitions);
} }
} }

View File

@ -2,26 +2,23 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
public class Micromissile : Missile public class Micromissile : Missile {
{ [SerializeField]
[SerializeField] private float _navigationGain = 5f; // Typically 3-5 private float _navigationGain = 5f; // Typically 3-5
private SensorOutput _sensorOutput; private SensorOutput _sensorOutput;
private Vector3 _accelerationCommand; private Vector3 _accelerationCommand;
private double _elapsedTime = 0; private double _elapsedTime = 0;
protected override void UpdateMidCourse(double deltaTime) protected override void UpdateMidCourse(double deltaTime) {
{
_elapsedTime += deltaTime; _elapsedTime += deltaTime;
Vector3 accelerationInput = Vector3.zero; Vector3 accelerationInput = Vector3.zero;
if (HasAssignedTarget()) if (HasAssignedTarget()) {
{
// Update the target model (assuming we have a target model) // Update the target model (assuming we have a target model)
// TODO: Implement target model update logic // TODO: Implement target model update logic
// Correct the state of the target model at the sensor frequency // Correct the state of the target model at the sensor frequency
float sensorUpdatePeriod = 1f / _agentConfig.dynamic_config.sensor_config.frequency; float sensorUpdatePeriod = 1f / _agentConfig.dynamic_config.sensor_config.frequency;
if (_elapsedTime >= sensorUpdatePeriod) if (_elapsedTime >= sensorUpdatePeriod) {
{
// TODO: Implement guidance filter to estimate state from sensor output // TODO: Implement guidance filter to estimate state from sensor output
// For now, we'll use the target's actual state // For now, we'll use the target's actual state
_sensorOutput = GetComponent<Sensor>().Sense(_target); _sensorOutput = GetComponent<Sensor>().Sense(_target);
@ -30,7 +27,7 @@ public class Micromissile : Missile
// Check whether the target should be considered a miss // Check whether the target should be considered a miss
SensorOutput sensorOutput = GetComponent<Sensor>().Sense(_target); SensorOutput sensorOutput = GetComponent<Sensor>().Sense(_target);
if(sensorOutput.velocity.range > 1000f) { if (sensorOutput.velocity.range > 1000f) {
this.MarkAsMiss(); this.MarkAsMiss();
} }
@ -41,18 +38,17 @@ public class Micromissile : Missile
// Calculate and set the total acceleration // Calculate and set the total acceleration
Vector3 acceleration = CalculateAcceleration(accelerationInput, compensateForGravity: true); Vector3 acceleration = CalculateAcceleration(accelerationInput, compensateForGravity: true);
GetComponent<Rigidbody>().AddForce(acceleration, ForceMode.Acceleration); GetComponent<Rigidbody>().AddForce(acceleration, ForceMode.Acceleration);
} }
private Vector3 CalculateAccelerationCommand(SensorOutput sensorOutput) private Vector3 CalculateAccelerationCommand(SensorOutput sensorOutput) {
{
// Implement Proportional Navigation guidance law // Implement Proportional Navigation guidance law
Vector3 accelerationCommand = Vector3.zero; Vector3 accelerationCommand = Vector3.zero;
// Extract relevant information from sensor output // Extract relevant information from sensor output
float los_rate_az = sensorOutput.velocity.azimuth; float los_rate_az = sensorOutput.velocity.azimuth;
float los_rate_el = sensorOutput.velocity.elevation; float los_rate_el = sensorOutput.velocity.elevation;
float closing_velocity = -sensorOutput.velocity.range; // Negative because closing velocity is opposite to range rate float closing_velocity =
-sensorOutput.velocity
.range; // Negative because closing velocity is opposite to range rate
// Navigation gain (adjust as needed) // Navigation gain (adjust as needed)
float N = _navigationGain; float N = _navigationGain;
@ -73,13 +69,10 @@ public class Micromissile : Missile
return accelerationCommand; return accelerationCommand;
} }
protected override void DrawDebugVectors() protected override void DrawDebugVectors() {
{
base.DrawDebugVectors(); base.DrawDebugVectors();
if (_accelerationCommand != null) if (_accelerationCommand != null) {
{
Debug.DrawRay(transform.position, _accelerationCommand * 1f, Color.green); Debug.DrawRay(transform.position, _accelerationCommand * 1f, Color.green);
} }
} }
} }

View File

@ -2,10 +2,9 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
public class Missile : Agent public class Missile : Agent {
{ [SerializeField]
protected bool _showDebugVectors = true;
[SerializeField] protected bool _showDebugVectors = true;
[SerializeField] [SerializeField]
private Vector3 _boostAcceleration; private Vector3 _boostAcceleration;
@ -20,7 +19,6 @@ public class Missile : Agent
base.AssignTarget(target); base.AssignTarget(target);
} }
// Unassign the target from the missile. // Unassign the target from the missile.
public override void UnassignTarget() { public override void UnassignTarget() {
base.UnassignTarget(); base.UnassignTarget();
@ -29,23 +27,23 @@ public class Missile : Agent
protected override void UpdateReady(double deltaTime) { protected override void UpdateReady(double deltaTime) {
Vector3 accelerationInput = Vector3.zero; Vector3 accelerationInput = Vector3.zero;
Vector3 acceleration = CalculateAcceleration(accelerationInput); Vector3 acceleration = CalculateAcceleration(accelerationInput);
//GetComponent<Rigidbody>().AddForce(acceleration, ForceMode.Acceleration); // GetComponent<Rigidbody>().AddForce(acceleration, ForceMode.Acceleration);
} }
protected override void Update() { protected override void Update() {
base.Update(); base.Update();
if(_showDebugVectors) { if (_showDebugVectors) {
DrawDebugVectors(); DrawDebugVectors();
} }
} }
protected override void UpdateBoost(double deltaTime) protected override void UpdateBoost(double deltaTime) {
{
// The missile only accelerates along its roll axis (forward in Unity) // The missile only accelerates along its roll axis (forward in Unity)
Vector3 rollAxis = transform.forward; Vector3 rollAxis = transform.forward;
// Calculate boost acceleration // Calculate boost acceleration
float boostAcceleration = (float)(StaticConfig.boostConfig.boostAcceleration * Constants.kGravity); float boostAcceleration =
(float)(StaticConfig.boostConfig.boostAcceleration * Constants.kGravity);
Vector3 accelerationInput = boostAcceleration * rollAxis; Vector3 accelerationInput = boostAcceleration * rollAxis;
// Calculate the total acceleration // Calculate the total acceleration
@ -55,15 +53,12 @@ public class Missile : Agent
GetComponent<Rigidbody>().AddForce(acceleration, ForceMode.Acceleration); GetComponent<Rigidbody>().AddForce(acceleration, ForceMode.Acceleration);
_boostAcceleration = acceleration; _boostAcceleration = acceleration;
} }
protected override void UpdateMidCourse(double deltaTime) { protected override void UpdateMidCourse(double deltaTime) {}
} protected Vector3 CalculateAcceleration(Vector3 accelerationInput,
bool compensateForGravity = false) {
protected Vector3 CalculateAcceleration(Vector3 accelerationInput, bool compensateForGravity = false)
{
Vector3 gravity = Physics.gravity; Vector3 gravity = Physics.gravity;
if (compensateForGravity) if (compensateForGravity) {
{
Vector3 gravityProjection = CalculateGravityProjectionOnPitchAndYaw(); Vector3 gravityProjection = CalculateGravityProjectionOnPitchAndYaw();
accelerationInput -= gravityProjection; accelerationInput -= gravityProjection;
} }
@ -78,46 +73,41 @@ public class Missile : Agent
return accelerationInput + gravity + dragAccelerationAlongRoll; return accelerationInput + gravity + dragAccelerationAlongRoll;
} }
private void OnTriggerEnter(Collider other) private void OnTriggerEnter(Collider other) {
{ if (other.gameObject.name == "Floor") {
if(other.gameObject.name == "Floor") {
this.MarkAsMiss(); this.MarkAsMiss();
} }
// Check if the collision is with another Agent // Check if the collision is with another Agent
Agent otherAgent = other.gameObject.GetComponentInParent<Agent>(); Agent otherAgent = other.gameObject.GetComponentInParent<Agent>();
if (otherAgent != null && otherAgent.GetComponent<Target>() != null) if (otherAgent != null && otherAgent.GetComponent<Target>() != null) {
{
// Check kill probability before marking as hit // Check kill probability before marking as hit
float killProbability = StaticConfig.hitConfig.killProbability; float killProbability = StaticConfig.hitConfig.killProbability;
GameObject markerObject = Instantiate(Resources.Load<GameObject>("Prefabs/HitMarkerPrefab"), transform.position, Quaternion.identity); GameObject markerObject = Instantiate(Resources.Load<GameObject>("Prefabs/HitMarkerPrefab"),
if (Random.value <= killProbability) transform.position, Quaternion.identity);
{ if (Random.value <= killProbability) {
// Set green for hit // Set green for hit
markerObject.GetComponent<Renderer>().material.color = new Color(0, 1, 0, 0.15f); markerObject.GetComponent<Renderer>().material.color = new Color(0, 1, 0, 0.15f);
// Mark both this agent and the other agent as hit // Mark both this agent and the other agent as hit
this.MarkAsHit(); this.MarkAsHit();
otherAgent.MarkAsHit(); otherAgent.MarkAsHit();
} } else {
else {
// Set red for miss // Set red for miss
markerObject.GetComponent<Renderer>().material.color = new Color(1, 0, 0, 0.15f); markerObject.GetComponent<Renderer>().material.color = new Color(1, 0, 0, 0.15f);
this.MarkAsMiss(); this.MarkAsMiss();
//otherAgent.MarkAsMiss(); // otherAgent.MarkAsMiss();
} }
} }
} }
protected float CalculateMaxAcceleration() protected float CalculateMaxAcceleration() {
{ float maxReferenceAcceleration =
float maxReferenceAcceleration = (float)(StaticConfig.accelerationConfig.maxReferenceAcceleration * Constants.kGravity); (float)(StaticConfig.accelerationConfig.maxReferenceAcceleration * Constants.kGravity);
float referenceSpeed = StaticConfig.accelerationConfig.referenceSpeed; float referenceSpeed = StaticConfig.accelerationConfig.referenceSpeed;
return Mathf.Pow(GetComponent<Rigidbody>().velocity.magnitude / referenceSpeed, 2) * maxReferenceAcceleration; return Mathf.Pow(GetComponent<Rigidbody>().velocity.magnitude / referenceSpeed, 2) *
maxReferenceAcceleration;
} }
protected Vector3 CalculateGravityProjectionOnPitchAndYaw() protected Vector3 CalculateGravityProjectionOnPitchAndYaw() {
{
Vector3 gravity = Physics.gravity; Vector3 gravity = Physics.gravity;
Vector3 pitchAxis = transform.right; Vector3 pitchAxis = transform.right;
Vector3 yawAxis = transform.up; Vector3 yawAxis = transform.up;
@ -131,8 +121,7 @@ public class Missile : Agent
gravityProjectionYawCoefficient * yawAxis; gravityProjectionYawCoefficient * yawAxis;
} }
private float CalculateDrag() private float CalculateDrag() {
{
float dragCoefficient = StaticConfig.liftDragConfig.dragCoefficient; float dragCoefficient = StaticConfig.liftDragConfig.dragCoefficient;
float crossSectionalArea = StaticConfig.bodyConfig.crossSectionalArea; float crossSectionalArea = StaticConfig.bodyConfig.crossSectionalArea;
float mass = StaticConfig.bodyConfig.mass; float mass = StaticConfig.bodyConfig.mass;
@ -141,23 +130,19 @@ public class Missile : Agent
return dragForce / mass; return dragForce / mass;
} }
private float CalculateLiftInducedDrag(Vector3 accelerationInput) private float CalculateLiftInducedDrag(Vector3 accelerationInput) {
{
float liftAcceleration = Vector3.Dot(accelerationInput, transform.forward); float liftAcceleration = Vector3.Dot(accelerationInput, transform.forward);
float liftDragRatio = StaticConfig.liftDragConfig.liftDragRatio; float liftDragRatio = StaticConfig.liftDragConfig.liftDragRatio;
return Mathf.Abs(liftAcceleration / liftDragRatio); return Mathf.Abs(liftAcceleration / liftDragRatio);
} }
protected virtual void DrawDebugVectors() {
protected virtual void DrawDebugVectors() if (_target != null) {
{
if (_target != null)
{
// Line of sight // Line of sight
Debug.DrawLine(transform.position, _target.transform.position, new Color(1, 1, 1, 0.15f)); Debug.DrawLine(transform.position, _target.transform.position, new Color(1, 1, 1, 0.15f));
// Velocity vector // Velocity vector
Debug.DrawRay(transform.position, GetVelocity()*0.01f, new Color(0, 0, 1, 0.15f)); Debug.DrawRay(transform.position, GetVelocity() * 0.01f, new Color(0, 0, 1, 0.15f));
// Current forward direction // Current forward direction
Debug.DrawRay(transform.position, transform.forward * 5f, Color.yellow); Debug.DrawRay(transform.position, transform.forward * 5f, Color.yellow);

View File

@ -1,14 +1,11 @@
using UnityEngine; using UnityEngine;
public class IdealSensor : Sensor public class IdealSensor : Sensor {
{ protected override void Start() {
protected override void Start()
{
base.Start(); base.Start();
} }
public override SensorOutput Sense(Agent target) public override SensorOutput Sense(Agent target) {
{
SensorOutput targetSensorOutput = new SensorOutput(); SensorOutput targetSensorOutput = new SensorOutput();
// Sense the target's position // Sense the target's position
@ -22,8 +19,7 @@ public class IdealSensor : Sensor
return targetSensorOutput; return targetSensorOutput;
} }
protected override PositionOutput SensePosition(Agent target) protected override PositionOutput SensePosition(Agent target) {
{
PositionOutput positionSensorOutput = new PositionOutput(); PositionOutput positionSensorOutput = new PositionOutput();
// Calculate the relative position of the target // Calculate the relative position of the target
@ -33,17 +29,18 @@ public class IdealSensor : Sensor
positionSensorOutput.range = relativePosition.magnitude; positionSensorOutput.range = relativePosition.magnitude;
// Calculate azimuth (horizontal angle relative to forward) // Calculate azimuth (horizontal angle relative to forward)
positionSensorOutput.azimuth = Vector3.SignedAngle(transform.forward, relativePosition, transform.up); positionSensorOutput.azimuth =
Vector3.SignedAngle(transform.forward, relativePosition, transform.up);
// Calculate elevation (vertical angle relative to forward) // Calculate elevation (vertical angle relative to forward)
Vector3 flatRelativePosition = Vector3.ProjectOnPlane(relativePosition, transform.up); Vector3 flatRelativePosition = Vector3.ProjectOnPlane(relativePosition, transform.up);
positionSensorOutput.elevation = Vector3.SignedAngle(flatRelativePosition, relativePosition, transform.right); positionSensorOutput.elevation =
Vector3.SignedAngle(flatRelativePosition, relativePosition, transform.right);
return positionSensorOutput; return positionSensorOutput;
} }
protected override VelocityOutput SenseVelocity(Agent target) protected override VelocityOutput SenseVelocity(Agent target) {
{
VelocityOutput velocitySensorOutput = new VelocityOutput(); VelocityOutput velocitySensorOutput = new VelocityOutput();
// Calculate relative position and velocity // Calculate relative position and velocity
@ -54,21 +51,21 @@ public class IdealSensor : Sensor
velocitySensorOutput.range = Vector3.Dot(relativeVelocity, relativePosition.normalized); velocitySensorOutput.range = Vector3.Dot(relativeVelocity, relativePosition.normalized);
// Project relative velocity onto a plane perpendicular to relative position // Project relative velocity onto a plane perpendicular to relative position
Vector3 tangentialVelocity = Vector3.ProjectOnPlane(relativeVelocity, relativePosition.normalized); Vector3 tangentialVelocity =
Vector3.ProjectOnPlane(relativeVelocity, relativePosition.normalized);
// Calculate azimuth rate // Calculate azimuth rate
Vector3 horizontalVelocity = Vector3.ProjectOnPlane(tangentialVelocity, transform.up); Vector3 horizontalVelocity = Vector3.ProjectOnPlane(tangentialVelocity, transform.up);
velocitySensorOutput.azimuth = Vector3.Dot(horizontalVelocity, transform.right) / relativePosition.magnitude; velocitySensorOutput.azimuth =
Vector3.Dot(horizontalVelocity, transform.right) / relativePosition.magnitude;
// Calculate elevation rate // Calculate elevation rate
Vector3 verticalVelocity = Vector3.Project(tangentialVelocity, transform.up); Vector3 verticalVelocity = Vector3.Project(tangentialVelocity, transform.up);
velocitySensorOutput.elevation = verticalVelocity.magnitude / relativePosition.magnitude; velocitySensorOutput.elevation = verticalVelocity.magnitude / relativePosition.magnitude;
if (Vector3.Dot(verticalVelocity, transform.up) < 0) if (Vector3.Dot(verticalVelocity, transform.up) < 0) {
{
velocitySensorOutput.elevation *= -1; velocitySensorOutput.elevation *= -1;
} }
return velocitySensorOutput; return velocitySensorOutput;
} }
} }

View File

@ -1,11 +1,9 @@
using UnityEngine; using UnityEngine;
public abstract class Sensor : MonoBehaviour public abstract class Sensor : MonoBehaviour {
{
protected Agent _agent; protected Agent _agent;
protected virtual void Start() protected virtual void Start() {
{
_agent = GetComponent<Agent>(); _agent = GetComponent<Agent>();
} }
@ -54,21 +52,18 @@ public abstract class Sensor : MonoBehaviour
protected abstract VelocityOutput SenseVelocity(Agent target); protected abstract VelocityOutput SenseVelocity(Agent target);
} }
public struct SensorOutput public struct SensorOutput {
{
public PositionOutput position; public PositionOutput position;
public VelocityOutput velocity; public VelocityOutput velocity;
} }
public struct PositionOutput public struct PositionOutput {
{
public float range; public float range;
public float azimuth; public float azimuth;
public float elevation; public float elevation;
} }
public struct VelocityOutput public struct VelocityOutput {
{
public float range; public float range;
public float azimuth; public float azimuth;
public float elevation; public float elevation;

View File

@ -3,17 +3,13 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
public class SimManager : MonoBehaviour public class SimManager : MonoBehaviour {
{
// Singleton instance // Singleton instance
public static SimManager Instance { get; private set; } public static SimManager Instance { get; private set; }
[SerializeField] [SerializeField]
public SimulationConfig simulationConfig; public SimulationConfig simulationConfig;
private List<Missile> _missiles = new List<Missile>(); private List<Missile> _missiles = new List<Missile>();
private List<Target> _unassignedTargets = new List<Target>(); private List<Target> _unassignedTargets = new List<Target>();
private List<Target> _targets = new List<Target>(); private List<Target> _targets = new List<Target>();
@ -23,28 +19,23 @@ public class SimManager : MonoBehaviour
private IAssignment _assignmentScheme; private IAssignment _assignmentScheme;
public double GetElapsedSimulationTime() public double GetElapsedSimulationTime() {
{
return _elapsedSimulationTime; return _elapsedSimulationTime;
} }
void Awake() void Awake() {
{
// Ensure only one instance of SimManager exists // Ensure only one instance of SimManager exists
if (Instance == null) if (Instance == null) {
{
Instance = this; Instance = this;
DontDestroyOnLoad(gameObject); DontDestroyOnLoad(gameObject);
} } else {
else
{
Destroy(gameObject); Destroy(gameObject);
} }
} }
void Start() { void Start() {
// Slow down time by simulationConfig.timeScale // Slow down time by simulationConfig.timeScale
if(Instance == this) { if (Instance == this) {
Time.timeScale = simulationConfig.timeScale; Time.timeScale = simulationConfig.timeScale;
Time.fixedDeltaTime = Time.timeScale * 0.02f; Time.fixedDeltaTime = Time.timeScale * 0.02f;
Time.maximumDeltaTime = Time.timeScale * 0.15f; Time.maximumDeltaTime = Time.timeScale * 0.15f;
@ -53,12 +44,10 @@ public class SimManager : MonoBehaviour
} }
} }
private void InitializeSimulation() private void InitializeSimulation() {
{
List<Missile> missiles = new List<Missile>(); List<Missile> missiles = new List<Missile>();
// Create missiles based on config // Create missiles based on config
foreach (var swarmConfig in simulationConfig.missile_swarm_configs) foreach (var swarmConfig in simulationConfig.missile_swarm_configs) {
{
for (int i = 0; i < swarmConfig.num_agents; i++) { for (int i = 0; i < swarmConfig.num_agents; i++) {
var missile = CreateMissile(swarmConfig.agent_config); var missile = CreateMissile(swarmConfig.agent_config);
} }
@ -66,11 +55,9 @@ public class SimManager : MonoBehaviour
List<Target> targets = new List<Target>(); List<Target> targets = new List<Target>();
// Create targets based on config // Create targets based on config
foreach (var swarmConfig in simulationConfig.target_swarm_configs) foreach (var swarmConfig in simulationConfig.target_swarm_configs) {
{
for (int i = 0; i < swarmConfig.num_agents; i++) { for (int i = 0; i < swarmConfig.num_agents; i++) {
var target = CreateTarget(swarmConfig.agent_config); var target = CreateTarget(swarmConfig.agent_config);
} }
} }
@ -78,8 +65,7 @@ public class SimManager : MonoBehaviour
// Perform initial assignment // Perform initial assignment
} }
public void AssignMissilesToTargets() public void AssignMissilesToTargets() {
{
AssignMissilesToTargets(_missiles); AssignMissilesToTargets(_missiles);
} }
@ -87,47 +73,41 @@ public class SimManager : MonoBehaviour
_unassignedTargets.Add(target); _unassignedTargets.Add(target);
} }
public void AssignMissilesToTargets(List<Missile> missilesToAssign) public void AssignMissilesToTargets(List<Missile> missilesToAssign) {
{
// Convert Missile and Target lists to Agent lists // Convert Missile and Target lists to Agent lists
List<Agent> missileAgents = new List<Agent>(missilesToAssign.ConvertAll(m => m as Agent)); List<Agent> missileAgents = new List<Agent>(missilesToAssign.ConvertAll(m => m as Agent));
// Convert Target list to Agent list, excluding already assigned targets // Convert Target list to Agent list, excluding already assigned targets
List<Agent> targetAgents = _unassignedTargets.ToList<Agent>(); List<Agent> targetAgents = _unassignedTargets.ToList<Agent>();
// Perform the assignment // Perform the assignment
IEnumerable<IAssignment.AssignmentItem> assignments = _assignmentScheme.Assign(missileAgents, targetAgents); IEnumerable<IAssignment.AssignmentItem> assignments =
_assignmentScheme.Assign(missileAgents, targetAgents);
// Apply the assignments to the missiles // Apply the assignments to the missiles
foreach (var assignment in assignments) foreach (var assignment in assignments) {
{ if (assignment.MissileIndex < missilesToAssign.Count) {
if (assignment.MissileIndex < missilesToAssign.Count)
{
Missile missile = missilesToAssign[assignment.MissileIndex]; Missile missile = missilesToAssign[assignment.MissileIndex];
Target target = _unassignedTargets[assignment.TargetIndex]; Target target = _unassignedTargets[assignment.TargetIndex];
missile.AssignTarget(target); missile.AssignTarget(target);
Debug.Log($"Missile {missile.name} assigned to target {target.name}"); Debug.Log($"Missile {missile.name} assigned to target {target.name}");
} }
} }
// TODO this whole function should be optimized // TODO this whole function should be optimized
_unassignedTargets.RemoveAll(target => missilesToAssign.Any(missile => missile.GetAssignedTarget() == target)); _unassignedTargets.RemoveAll(
target => missilesToAssign.Any(missile => missile.GetAssignedTarget() == target));
} }
public Missile CreateMissile(AgentConfig config) public Missile CreateMissile(AgentConfig config) {
{ string prefabName = config.missile_type switch { MissileType.HYDRA_70 => "Hydra70",
string prefabName = config.missile_type switch
{
MissileType.HYDRA_70 => "Hydra70",
MissileType.MICROMISSILE => "Micromissile", MissileType.MICROMISSILE => "Micromissile",
_ => "Hydra70" _ => "Hydra70" };
};
GameObject missileObject = CreateAgent(config, prefabName); GameObject missileObject = CreateAgent(config, prefabName);
if (missileObject == null) return null; if (missileObject == null)
return null;
// Missile-specific logic // Missile-specific logic
switch(config.dynamic_config.sensor_config.type) { switch (config.dynamic_config.sensor_config.type) {
case SensorType.IDEAL: case SensorType.IDEAL:
missileObject.AddComponent<IdealSensor>(); missileObject.AddComponent<IdealSensor>();
break; break;
@ -152,16 +132,14 @@ public class SimManager : MonoBehaviour
return missileObject.GetComponent<Missile>(); return missileObject.GetComponent<Missile>();
} }
private Target CreateTarget(AgentConfig config) private Target CreateTarget(AgentConfig config) {
{ string prefabName = config.target_type switch {
string prefabName = config.target_type switch TargetType.DRONE => "DroneTarget", TargetType.MISSILE => "MissileTarget",
{
TargetType.DRONE => "DroneTarget",
TargetType.MISSILE => "MissileTarget",
_ => throw new System.ArgumentException($"Unsupported target type: {config.target_type}") _ => throw new System.ArgumentException($"Unsupported target type: {config.target_type}")
}; };
GameObject targetObject = CreateAgent(config, prefabName); GameObject targetObject = CreateAgent(config, prefabName);
if (targetObject == null) return null; if (targetObject == null)
return null;
// Target target = targetObject.GetComponent<Target>(); // Target target = targetObject.GetComponent<Target>();
// if (target == null) // if (target == null)
@ -180,11 +158,9 @@ public class SimManager : MonoBehaviour
return targetObject.GetComponent<Target>(); return targetObject.GetComponent<Target>();
} }
public GameObject CreateAgent(AgentConfig config, string prefabName) public GameObject CreateAgent(AgentConfig config, string prefabName) {
{
GameObject prefab = Resources.Load<GameObject>($"Prefabs/{prefabName}"); GameObject prefab = Resources.Load<GameObject>($"Prefabs/{prefabName}");
if (prefab == null) if (prefab == null) {
{
Debug.LogError($"Prefab '{prefabName}' not found in Resources/Prefabs folder."); Debug.LogError($"Prefab '{prefabName}' not found in Resources/Prefabs folder.");
return null; return null;
} }
@ -192,7 +168,8 @@ public class SimManager : MonoBehaviour
Vector3 noiseOffset = Utilities.GenerateRandomNoise(config.standard_deviation.position); Vector3 noiseOffset = Utilities.GenerateRandomNoise(config.standard_deviation.position);
Vector3 noisyPosition = config.initial_state.position + noiseOffset; Vector3 noisyPosition = config.initial_state.position + noiseOffset;
GameObject agentObject = Instantiate(prefab, noisyPosition, Quaternion.Euler(config.initial_state.rotation)); GameObject agentObject =
Instantiate(prefab, noisyPosition, Quaternion.Euler(config.initial_state.rotation));
Rigidbody agentRigidbody = agentObject.GetComponent<Rigidbody>(); Rigidbody agentRigidbody = agentObject.GetComponent<Rigidbody>();
Vector3 velocityNoise = Utilities.GenerateRandomNoise(config.standard_deviation.velocity); Vector3 velocityNoise = Utilities.GenerateRandomNoise(config.standard_deviation.velocity);
@ -204,28 +181,21 @@ public class SimManager : MonoBehaviour
return agentObject; return agentObject;
} }
private void RestartSimulation() {
private void RestartSimulation()
{
// Reset simulation time // Reset simulation time
_elapsedSimulationTime = 0f; _elapsedSimulationTime = 0f;
simulationRunning = true; simulationRunning = true;
// Clear existing missiles and targets // Clear existing missiles and targets
foreach (var missile in _missiles) foreach (var missile in _missiles) {
{ if (missile != null) {
if (missile != null)
{
Destroy(missile.gameObject); Destroy(missile.gameObject);
} }
} }
_missiles.Clear(); _missiles.Clear();
foreach (var target in _targets) foreach (var target in _targets) {
{ if (target != null) {
if (target != null)
{
Destroy(target.gameObject); Destroy(target.gameObject);
} }
} }
@ -234,35 +204,25 @@ public class SimManager : MonoBehaviour
InitializeSimulation(); InitializeSimulation();
} }
void Update() void Update() {
{
// Check if all missiles have terminated // Check if all missiles have terminated
bool allMissilesTerminated = true; bool allMissilesTerminated = true;
foreach (var missile in _missiles) foreach (var missile in _missiles) {
{ if (missile != null && !missile.IsHit() && !missile.IsMiss()) {
if (missile != null && !missile.IsHit() && !missile.IsMiss())
{
allMissilesTerminated = false; allMissilesTerminated = false;
break; break;
} }
} }
// If all missiles have terminated, restart the simulation // If all missiles have terminated, restart the simulation
if (allMissilesTerminated) if (allMissilesTerminated) {
{
RestartSimulation(); RestartSimulation();
} }
if (simulationRunning && _elapsedSimulationTime < endTime) if (simulationRunning && _elapsedSimulationTime < endTime) {
{
_elapsedSimulationTime += Time.deltaTime; _elapsedSimulationTime += Time.deltaTime;
} } else if (_elapsedSimulationTime >= endTime) {
else if (_elapsedSimulationTime >= endTime)
{
simulationRunning = false; simulationRunning = false;
Debug.Log("Simulation completed."); Debug.Log("Simulation completed.");
} }
} }
} }

View File

@ -2,29 +2,20 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
public class DroneTarget : Target public class DroneTarget : Target {
{
// Start is called before the first frame update // Start is called before the first frame update
protected override void Start() protected override void Start() {
{
base.Start(); base.Start();
} }
// Update is called once per frame // Update is called once per frame
protected override void Update() protected override void Update() {
{
base.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) {
}
} }

View File

@ -2,17 +2,10 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
public class MissileTarget : MonoBehaviour public class MissileTarget : MonoBehaviour {
{
// Start is called before the first frame update // Start is called before the first frame update
void Start() void Start() {}
{
}
// Update is called once per frame // Update is called once per frame
void Update() void Update() {}
{
}
} }

View File

@ -2,8 +2,7 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
public abstract class Target : Agent public abstract class Target : Agent {
{
public override bool IsAssignable() { public override bool IsAssignable() {
return false; return false;
} }

View File

@ -1,13 +1,9 @@
using UnityEngine; using UnityEngine;
public static class Utilities public static class Utilities {
{ public static Vector3 GenerateRandomNoise(Vector3 standardDeviation) {
public static Vector3 GenerateRandomNoise(Vector3 standardDeviation) return new Vector3(Random.Range(-standardDeviation.x, standardDeviation.x),
{
return new Vector3(
Random.Range(-standardDeviation.x, standardDeviation.x),
Random.Range(-standardDeviation.y, standardDeviation.y), Random.Range(-standardDeviation.y, standardDeviation.y),
Random.Range(-standardDeviation.z, standardDeviation.z) Random.Range(-standardDeviation.z, standardDeviation.z));
);
} }
} }