Merge branch 'krazerleo/core/1' into lisin/character/1
This commit is contained in:
22
Assets/Scripts/Character/Character.cs
Normal file
22
Assets/Scripts/Character/Character.cs
Normal 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; }
|
||||
}
|
11
Assets/Scripts/Character/Character.cs.meta
generated
Normal file
11
Assets/Scripts/Character/Character.cs.meta
generated
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44d6a17ad31b31241928e1a17e9aba37
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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
24
Assets/Scripts/Character/MovementController.cs
Executable file → Normal 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
118
Assets/Scripts/Character/NPC.cs
Executable file → Normal 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");
|
||||
}
|
||||
}
|
||||
|
46
Assets/Scripts/Character/NPC_State.cs
Normal file
46
Assets/Scripts/Character/NPC_State.cs
Normal 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;
|
||||
}
|
11
Assets/Scripts/Character/NPC_State.cs.meta
generated
Normal file
11
Assets/Scripts/Character/NPC_State.cs.meta
generated
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a192e433e26797745ad0b46de2586de3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
34
Assets/Scripts/Character/Player.cs
Normal file
34
Assets/Scripts/Character/Player.cs
Normal 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
11
Assets/Scripts/Character/Player.cs.meta
generated
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8c9a8e604d395c4ab9d03d28adc4982
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user