using System; using UnityEngine; using Unity.MLAgents; using Unity.MLAgents.Sensors; using Unity.MLAgents.Actuators; [RequireComponent(typeof(MovementController))] public class NPC : Agent, ICharacter { [HideInInspector] public Character AgentCharacter; public CharacterCondition Condition; private FlagZone flagZone; public NPC_BaseState NPC_State { get; private set; } public Character GetCharacter => AgentCharacter; private NPC_DirectPointState DirectState; private NPC_InCoverState CoverState; private NPC_RunningState RunningState; private MovementController moveController; private BufferSensorComponent bufferSensor; private void Awake() { DirectState = new NPC_DirectPointState(); CoverState = new NPC_InCoverState(); RunningState = new NPC_RunningState(); NPC_State = DirectState; AgentCharacter = new Character(); Condition = AgentCharacter.Condition; moveController = gameObject.GetComponent(); bufferSensor = gameObject.GetComponent(); } public void ResetCharacter() { Condition = new CharacterCondition(); EndEpisode(); } public override void OnEpisodeBegin() { NPC_State = DirectState; flagZone = GameObject.FindObjectOfType(); } public override void CollectObservations(VectorSensor sensor) { var candidates = moveController.getPointsCandidate(); sensor.AddObservation(Condition.HealthPoints); sensor.AddObservation(Condition.ArmourPoints); sensor.AddObservation(Condition.Ammunition); sensor.AddObservation((int)NPC_State.State); sensor.AddObservation((!flagZone.isNotOccup).ToInt()); sensor.AddObservation(AgentCharacter.LastTimeHit); sensor.AddObservation(Condition.GetHealthPointsInQuantile()); sensor.AddObservation(candidates.Count); sensor.AddObservation(GameManager.IsEnemyNearby(gameObject.transform.position, AgentCharacter.Team)); foreach (var point in candidates) { Debug.Log((float)moveController.CurrentNavPoint.PointId); bufferSensor.AppendObservation(new float[] { //1 position in navpointId (float)moveController.CurrentNavPoint.PointId, //2 distance to flag moveController.FlagDistance, //3 death count in point moveController.CurrentNavPoint.DeathAttr, //4 flagEnemyDistance GameManager.IsCloserToFlagFromNextNavPoint(point, transform.position).ToInt(), //5 EnemyVsNavPointDistance GameManager.IsCloserToEnemyThanToNextNavPoint(point,transform.position, AgentCharacter.Team).ToInt() }); } } public override void Heuristic(in ActionBuffers actionsOut) { var discreteActionsOut = actionsOut.DiscreteActions; if (Input.GetKeyDown(KeyCode.W)) { discreteActionsOut[0] = 1; } } public override void OnActionReceived(ActionBuffers actions) { if (actions.DiscreteActions[0] == 1) { moveController.MoveToRandomPoint(); NPC_State = RunningState; } } public event Action OnKilledEvent; public void GetDamage(float damage) { AgentCharacter.LastTimeHit = TimeManager.Instance.CurrentTime; Condition.GiveHealth(-Mathf.RoundToInt(damage * (1 - Condition.ArmourPoints * 0.5f))); Condition.GiveArmour(-Mathf.RoundToInt(Mathf.Sqrt(damage) * 5)); if (Condition.HealthPoints < 0) { OnKilledEvent?.Invoke(this); moveController.CurrentNavPoint.DeathAttr += 1; } } private void OnDestroy() { Debug.LogWarning("Pooled object was destroyed"); } }