using System; using UnityEngine; using Unity.MLAgents; using Unity.MLAgents.Sensors; using Unity.MLAgents.Actuators; using System.Collections.Generic; [RequireComponent(typeof(MovementController))] public class NPC : Agent, ICharacter { private Character AgentCharacter; private CharacterCondition Condition; 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; } private void Start() { AgentCharacter = new Character(); Condition = AgentCharacter.Condition; moveController = gameObject.GetComponent(); bufferSensor = gameObject.GetComponent(); //GameManager.OnResetScene += AgentCharacter.ResetCharacter; } public override void OnEpisodeBegin() { } public override void CollectObservations(VectorSensor sensor) { sensor.AddObservation(Condition.HealthPoints); sensor.AddObservation(Condition.ArmourPoints); sensor.AddObservation(Condition.Ammunition); sensor.AddObservation((int)NPC_State.State); var candidates = moveController.getPointsCandidate(); foreach (var point in candidates) { bufferSensor.AppendObservation(new float[] { //1 position in navpointId (float)moveController.currentPosition.PointId, //2 distance to flag moveController.currentPosition.FlagDistance, //3 death count in point moveController.currentPosition.DeathAttr, //4 flagEnemyDistance GameManager.IsCloserToFlagFromNextNavPoint(point, transform.position)==true?1:0, //5 EnemyVsNavPointDistance GameManager.IsCloserToEnemyThanToNextNavPoint(point,transform.position, AgentCharacter.Team)==true?1:0 }); } } 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.currentPosition.DeathAttr += 1; } } private void OnDestroy() { Debug.LogWarning("Pooled object was destroyed"); } }