Format all files
parent
df4c8dfbfe
commit
9be43821ef
|
@ -2,3 +2,6 @@ BasedOnStyle: Google
|
||||||
---
|
---
|
||||||
Language: CSharp
|
Language: CSharp
|
||||||
ColumnLimit: 100
|
ColumnLimit: 100
|
||||||
|
---
|
||||||
|
Language: Json
|
||||||
|
DisableFormat: true
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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")]
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {}
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue