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 { [HideInInspector] public Character AgentCharacter; public 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; moveController = gameObject.GetComponent(); bufferSensor = gameObject.GetComponent(); } public void ResetCharacter() { Condition = new CharacterCondition(); EndEpisode(); } public override void OnEpisodeBegin() { NPC_State = DirectState; } 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) { var parray = 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 }; var _parray = string.Join(" ", parray); Debug.Log("OBS: " + _parray); bufferSensor.AppendObservation(parray); } } 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; } else if (actions.DiscreteActions[0] == 2) { moveController.MoveToPointById(actions.DiscreteActions[1]); } } 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"); } }