using System.Collections; using System.Collections.Generic; using TMPro; using Unity.PlasticSCM.Editor.UI; using Unity.VisualScripting; using UnityEngine; public abstract class Agent : MonoBehaviour { public enum FlightPhase { INITIALIZED, READY, BOOST, MIDCOURSE, TERMINAL, TERMINATED } [SerializeField] private FlightPhase _flightPhase = FlightPhase.INITIALIZED; [SerializeField] protected Agent _target; protected bool _isHit = false; protected bool _isMiss = false; protected AgentConfig _agentConfig; protected double _timeSinceLaunch = 0; protected double _timeInPhase = 0; [SerializeField] public StaticConfig StaticConfig; public void SetFlightPhase(FlightPhase flightPhase) { Debug.Log( $"Setting flight phase to {flightPhase} at time {SimManager.Instance.GetElapsedSimulationTime()}"); _timeInPhase = 0; _flightPhase = flightPhase; } public FlightPhase GetFlightPhase() { return _flightPhase; } public bool HasLaunched() { return (_flightPhase != FlightPhase.INITIALIZED) && (_flightPhase != FlightPhase.READY); } public bool HasTerminated() { return _flightPhase == FlightPhase.TERMINATED; } public virtual void SetAgentConfig(AgentConfig config) { _agentConfig = config; } public virtual bool IsAssignable() { return true; } public virtual void AssignTarget(Agent target) { _target = target; } public Agent GetAssignedTarget() { return _target; } public bool HasAssignedTarget() { return _target != null; } public void CheckTargetHit() { if (HasAssignedTarget() && _target.IsHit()) { UnassignTarget(); } } public virtual void UnassignTarget() { _target = null; } // Return whether the agent has hit or been hit. public bool IsHit() { return _isHit; } public bool IsMiss() { return _isMiss; } public void TerminateAgent() { _flightPhase = FlightPhase.TERMINATED; transform.position = new Vector3(0, 0, 0); gameObject.SetActive(false); } // Mark the agent as having hit the target or been hit. public void MarkAsHit() { _isHit = true; TerminateAgent(); } public void MarkAsMiss() { _isMiss = true; if (_target != null) { SimManager.Instance.RegisterTargetMiss(_target as Target); _target = null; } TerminateAgent(); } public double GetSpeed() { return GetComponent().velocity.magnitude; } public Vector3 GetVelocity() { return GetComponent().velocity; } public double GetDynamicPressure() { var airDensity = Constants.CalculateAirDensityAtAltitude(transform.position.y); var flowSpeed = GetSpeed(); return 0.5 * airDensity * (flowSpeed * flowSpeed); } protected abstract void UpdateReady(double deltaTime); protected abstract void UpdateBoost(double deltaTime); protected abstract void UpdateMidCourse(double deltaTime); // Start is called before the first frame update protected virtual void Start() { _flightPhase = FlightPhase.READY; } // Update is called once per frame protected virtual void Update() { _timeSinceLaunch += Time.deltaTime; _timeInPhase += Time.deltaTime; var launch_time = _agentConfig.dynamic_config.launch_config.launch_time; var boost_time = launch_time + StaticConfig.boostConfig.boostTime; double elapsedSimulationTime = SimManager.Instance.GetElapsedSimulationTime(); if (_flightPhase == FlightPhase.TERMINATED) { return; } if (elapsedSimulationTime >= launch_time && _flightPhase == FlightPhase.READY) { SetFlightPhase(FlightPhase.BOOST); } if (_timeSinceLaunch > boost_time && _flightPhase == FlightPhase.BOOST) { SetFlightPhase(FlightPhase.MIDCOURSE); } AlignWithVelocity(); switch (_flightPhase) { case FlightPhase.INITIALIZED: break; case FlightPhase.READY: UpdateReady(Time.deltaTime); break; case FlightPhase.BOOST: UpdateBoost(Time.deltaTime); break; case FlightPhase.MIDCOURSE: case FlightPhase.TERMINAL: UpdateMidCourse(Time.deltaTime); break; case FlightPhase.TERMINATED: break; } } protected virtual void AlignWithVelocity() { Vector3 velocity = GetVelocity(); if (velocity.magnitude > 0.1f) // Only align if we have significant velocity { // Create a rotation with forward along velocity and up along world up Quaternion targetRotation = Quaternion.LookRotation(velocity, Vector3.up); // Smoothly rotate towards the target rotation transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, 1000f * Time.deltaTime); } } }