using System; using System.Collections.Generic; using Unity.MLAgents; using Unity.MLAgents.Actuators; using Unity.MLAgents.Sensors; using UnityEngine; [RequireComponent(typeof(MovementController),typeof(BufferSensor))] public class NPC : Agent, ICharacter { [HideInInspector] private Character AgentCharacter; public CharacterCondition Condition; private FlagZone flagZone = null; public INpcBaseState NpcState { get; private set; } public INpcBaseBodyState NpcBodyState { get; private set; } public Character GetCharacter => AgentCharacter; private NpcDirectPointState DirectState; private NpcInCoverState CoverState; private NpcRunningState RunningState; private NpcStandingState StandingState; private NpcCrouchingState CrouchingState; private MovementController moveController; private BufferSensorComponent bufferSensor; private Dictionary navPointIdDict; #region UnityEvents and ML private void Awake() { DirectState = new NpcDirectPointState(); CoverState = new NpcInCoverState(); RunningState = new NpcRunningState(); NpcState = DirectState; CrouchingState = new NpcCrouchingState(); StandingState = new NpcStandingState(); NpcBodyState = StandingState; AgentCharacter = new Character(); Condition = AgentCharacter.Condition; moveController = gameObject.GetComponent(); bufferSensor = gameObject.GetComponent(); flagZone = GameObject.FindObjectOfType(); if (flagZone == null) Debug.LogError("Flag Is Not Setted"); navPointIdDict = MapManager.IDToNavPoint; if (navPointIdDict is null) Debug.LogError("Cant Find Nav Point Dictionary"); } private void OnDestroy() { Debug.LogWarning("Pooled object was destroyed"); } public override void OnEpisodeBegin() { NpcState = DirectState; flagZone = GameObject.FindObjectOfType(); } public override void CollectObservations(VectorSensor sensor) { <<<<<<< HEAD var candidates = moveController.GetPointsCandidate(); ======= sensor.AddObservation(Condition.HealthPoints); sensor.AddObservation(Condition.ArmourPoints); sensor.AddObservation(Condition.Ammunition); sensor.AddObservation((int) NPC_State.State); >>>>>>> 351fa8ee12c499a0374be71a192a5f288611f467 //common sensors sensor.AddObservation(GameManager.IsHaveSeenByEnemy(AgentCharacter.Team.GetOppositeTeam(), NpcBodyState.GetPointToHit(gameObject)).ToInt()); sensor.AddObservation(AgentCharacter.LastTimeHit); sensor.AddObservation((!flagZone.IsNotOccup).ToInt()); sensor.AddObservation(Condition.GetHealthPointsInQuantile()); sensor.AddObservation(Condition.GetArmourPointsInQuantile()); sensor.AddObservation(candidates.Count); sensor.AddObservation(moveController.PointStartID); sensor.AddObservation(moveController.PointEndID); //state sensors sensor.AddObservation((int)NpcState.State); sensor.AddObservation((int)NpcBodyState.State); sensor.AddObservation(GameManager.IsEnemyNearby(gameObject.transform.position, AgentCharacter.Team)); sensor.AddObservation(navPointIdDict[moveController.PointStartID].DeathAttr); sensor.AddObservation(navPointIdDict[moveController.PointEndID].DeathAttr); sensor.AddObservation(moveController.FlagDistance); //point sensors foreach (var point in candidates) { <<<<<<< HEAD bufferSensor.AppendObservation(new float[] { point.DeathAttr, (int)point.navType, //4 flagEnemyDistance GameManager.IsCloserToFlagFromNextNavPoint(point, transform.position).ToInt(), //5 EnemyVsNavPointDistance GameManager.IsCloserToEnemyThanToNextNavPoint(point,transform.position, AgentCharacter.Team.GetOppositeTeam()).ToInt(), //6 Have been seen by enemy in this point GameManager.IsHaveSeenByEnemy(AgentCharacter.Team.GetOppositeTeam(), point.Position).ToInt() }); ======= 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; >>>>>>> 351fa8ee12c499a0374be71a192a5f288611f467 } } public override void OnActionReceived(ActionBuffers actions) { var result = actions.DiscreteActions; if (result[0] == 0) { <<<<<<< HEAD if (navPointIdDict[moveController.PointStartID].navType != NavPointType.Cover) return; NpcState = CoverState; switch (result[1]) { case 0: Peek(); break; case 1: Cover(); break; case 3: Peek(); moveController.GoToNextNavPoint(navPointIdDict[result[2]]); break; case 4: NpcState = DirectState; break; default: throw new ArgumentException("Undefined Action recieved"); } } if (result[0] == 1) { if (navPointIdDict[moveController.PointStartID].navType != NavPointType.Direction) return; switch (result[1]) { case 0: moveController.GoToNextNavPoint(navPointIdDict[result[2]]); NpcState = RunningState; break; case 1: NpcState = DirectState; break; default: throw new ArgumentException("Undefined Action recieved"); } } if (result[0] == 2) { if (moveController.PointStartID == moveController.PointEndID && moveController.PointEndID != -1) return; switch (result[1]) { case 0: moveController.StopOnPath(); NpcState = DirectState; break; case 1: moveController.ReturnToStartPoint(); NpcState = RunningState; break; default: throw new ArgumentException("Undefined Action recieved"); } ======= moveController.MoveToRandomPoint(); NPC_State = RunningState; } else if (actions.DiscreteActions[0] == 2) { moveController.MoveToPointById(actions.DiscreteActions[1]); >>>>>>> 351fa8ee12c499a0374be71a192a5f288611f467 } } #endregion public event Action OnChangePosition; private void Peek() { OnChangePosition?.Invoke(global::NpcBodyState.Standing); NpcBodyState = StandingState; } private void Cover() { OnChangePosition?.Invoke(global::NpcBodyState.Crouching); NpcBodyState = CrouchingState; } public event Action OnDamageRecieved; 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) { MapManager.AddDeathAttributeToPoints(moveController.PointStartID, moveController.PointEndID, moveController.DistanceToGo, moveController.RemainingDistance); var pos = gameObject.transform.position; var id = moveController.PointStartID; CharacterFactory.Instance.ReSpawn(this, ref pos, ref id); } } public void ResetCharacter() { Condition.Reset(); EndEpisode(); } }