Merge branch 'krazerleo/core/1' into lisin/character/1

This commit is contained in:
2022-04-18 17:04:36 +07:00
64 changed files with 1576 additions and 1114 deletions

View File

@ -0,0 +1,22 @@
using UnityEngine;
public class Character
{
public Team Team { get; set; }
public float LastTimeHit = 0;
public CharacterCondition Condition;
public Character()
{
Condition = new CharacterCondition();
}
public void ResetCharacter()
{
}
}
public interface ICharacter
{
Character GetCharacter { get; }
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 44d6a17ad31b31241928e1a17e9aba37
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,39 +1,62 @@
using System;
using UnityEngine;
public class CharacterCondition : MonoBehaviour
public class CharacterCondition
{
public event Action<object> OnKilledEvent;
public event Action<int> OnDamageHealthTakenEvent;
public event Action<int> OnDamageArmourTakenEvent;
public event Action<int> OnAmmunitionTakenEvent;
public event Action<int> OnChangeHealthEvent;
public event Action<int> OnChangeArmourEvent;
public event Action<int> OnChangeAmmunitionEvent;
[SerializeField] private int HealthPoints;
[SerializeField] private int ArmourPoints;
[SerializeField] private int Ammunition;
public void Start()
{
private int health;
public int HealthPoints
{
get
{
return health;
}
private set
{
health = value;
OnChangeHealthEvent?.Invoke(value);
}
}
public void GetDamage(float damage)
private int armour;
public int ArmourPoints
{
HealthPoints -= Mathf.RoundToInt(damage * (1 - ArmourPoints * 0.5f));
ArmourPoints -= Mathf.RoundToInt(Mathf.Sqrt(damage) * 5);
OnDamageHealthTakenEvent?.Invoke(HealthPoints);
OnDamageArmourTakenEvent?.Invoke(ArmourPoints);
if (HealthPoints < 0)
OnKilledEvent?.Invoke(gameObject);
get
{
return armour;
}
private set
{
armour = value;
OnChangeArmourEvent?.Invoke(value);
}
}
private int ammo;
public int Ammunition
{
get
{
return ammo;
}
private set
{
ammo = value;
OnChangeAmmunitionEvent?.Invoke(value);
}
}
public CharacterCondition()
{
var settings = SettingsReader.Instance.GetSettings;
ammo = settings.maxAmmo;
health = settings.maxHealth;
armour = settings.maxArmour;
}
public void GiveHealth(int health) => HealthPoints = Mathf.Clamp(health + HealthPoints, 0, 100);
public void SetHealth(int health) => HealthPoints = Mathf.Clamp(health, 0, 100);
public void GiveArmour(int armour) => ArmourPoints = Mathf.Clamp(armour + ArmourPoints, 0, 100);
public void SetArmour(int armour) => ArmourPoints = Mathf.Clamp(armour, 0, 100);
public void TakeAmmo(int ammo)
{
Ammunition += ammo;
OnAmmunitionTakenEvent?.Invoke(Ammunition);
}
public void TakeAmmo(int ammo) => Ammunition += ammo;
}

24
Assets/Scripts/Character/MovementController.cs Executable file → Normal file
View File

@ -7,7 +7,6 @@ using UnityEngine.AI;
public class MovementController : MonoBehaviour
{
public NavPoint currentPosition { get; private set; }
[SerializeField] private MapManager mapManager;
[SerializeField] private NavMeshAgent navMeshAgent;
private void Start()
@ -15,24 +14,19 @@ public class MovementController : MonoBehaviour
navMeshAgent.speed = SettingsReader.Instance.GetSettings.movementSpeed;
}
public void Move()
{
var pointCandidate = getPointCandidate();
goToNextNavPoint(pointCandidate);
public void MoveToRandomPoint()
{
Debug.Log(MapManager.navPoints == null);
goToNextNavPoint(MapManager.navPoints[Random.Range(0, MapManager.navPoints.Count)]);
}
// todo внутри сенсора передавать в mlagents как variable length observations: https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Learning-Environment-Design-Agents.md#variable-length-observations
private NavPoint getPointCandidate()
public List<NavPoint> getPointsCandidate()
{
var NavPointsPositions = mapManager.navPoints
.Select(point => point.transform.position)
.Where(point => (currentPosition.transform.position - point).magnitude <= SettingsReader.Instance.GetSettings.movementSpeed)
return MapManager.navPoints
.Where(point => (currentPosition.position - point.position).magnitude <= SettingsReader.Instance.GetSettings.movementSpeed)
.ToList();
//TODO AI
return null;
}
private void goToNextNavPoint(NavPoint destination) =>
navMeshAgent.SetDestination(destination.transform.position);
public void goToNextNavPoint(NavPoint destination) =>
navMeshAgent.SetDestination(destination.position);
}

118
Assets/Scripts/Character/NPC.cs Executable file → Normal file
View File

@ -1,37 +1,117 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using Unity.MLAgents;
using Unity.MLAgents.Sensors;
using Unity.MLAgents.Actuators;
using System.Collections.Generic;
public class NPC : Agent
[RequireComponent(typeof(MovementController))]
public class NPC : Agent, ICharacter
{
public float LastTimeHit;
private BaseBehaviour NPCBehaviour;
public List<Action> ActionList;
[SerializeField]
private List<ISensor> SensorList; // todo тут интерфейс должен быть наш
[HideInInspector]
public Character AgentCharacter;
public CharacterCondition Condition;
public void SetBehaviour(BaseBehaviour behaviour) => NPCBehaviour = behaviour;
public Team Team { get; set; }
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<MovementController>();
bufferSensor = gameObject.GetComponent<BufferSensorComponent>();
GameManager.OnResetScene += AgentCharacter.ResetCharacter;
}
public override void OnEpisodeBegin()
{
}
public override void CollectObservations(VectorSensor sensor)
{
// Target and Agent positions
foreach (var _sensor in SensorList)
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)
{
sensor.AddObservation(1); // todo
// sensor.AddObservation(_sensor.GetValue());
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
});
}
}
private void Update()
public override void Heuristic(in ActionBuffers actionsOut)
{
//NPCBehaviour.DoAction();
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<object> 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");
}
}

View File

@ -0,0 +1,46 @@
public enum NPC_EnumState
{
InCover,
InDirectPoint,
InRunning,
}
public interface NPC_BaseState
{
NPC_EnumState State { get; }
bool InCover { get; }
bool IsRunning { get; }
bool InDirectPoint { get; }
float HitChance { get; }
float DoDamageChance { get; }
}
public class NPC_DirectPointState : NPC_BaseState
{
public bool InCover => false;
public bool IsRunning => false;
public bool InDirectPoint => false;
public float HitChance => SettingsReader.Instance.GetSettings.GetHitChanceInDirectPoint;
public float DoDamageChance => SettingsReader.Instance.GetSettings.DoDamageChanceInDirectPoint;
public NPC_EnumState State => NPC_EnumState.InDirectPoint;
}
public class NPC_RunningState : NPC_BaseState
{
public bool InCover => false;
public bool IsRunning => true;
public bool InDirectPoint => false;
public float HitChance => SettingsReader.Instance.GetSettings.GetHitChanceInRunning;
public float DoDamageChance => SettingsReader.Instance.GetSettings.DoDamageChanceInRunning;
public NPC_EnumState State => NPC_EnumState.InRunning;
}
public class NPC_InCoverState : NPC_BaseState
{
public bool InCover => true;
public bool IsRunning => false;
public bool InDirectPoint => false;
public float HitChance => SettingsReader.Instance.GetSettings.GetHitChanceInCover;
public float DoDamageChance => SettingsReader.Instance.GetSettings.DoDamageChanceInCover;
public NPC_EnumState State => NPC_EnumState.InCover;
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a192e433e26797745ad0b46de2586de3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,34 @@
using System;
using UnityEngine;
public class Player : MonoBehaviour, ICharacter
{
[HideInInspector]
public Character PlayerCharacter;
public CharacterCondition Condition;
public Character GetCharacter => PlayerCharacter;
private void Start()
{
PlayerCharacter = new Character();
Condition = PlayerCharacter.Condition;
GameManager.OnResetScene += PlayerCharacter.ResetCharacter;
}
public event Action<object> OnKilledEvent;
public void GetDamage(float damage)
{
PlayerCharacter.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);
}
private void OnDestroy()
{
Debug.LogWarning("Pooled object was destroyed");
}
}

11
Assets/Scripts/Character/Player.cs.meta generated Normal file
View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a8c9a8e604d395c4ab9d03d28adc4982
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: