2022-01-13 22:58:54 +03:00

246 lines
8.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Controller;
using DefaultNamespace;
using DefaultNamespace.AI;
using HexFiled;
using Items;
using Runtime.Controller;
using Units;
using UnityEngine;
using Object = UnityEngine.Object;
using Random = UnityEngine.Random;
namespace AI
{
public class AIManager
{
private List<AIAgent> _agents;
private int _triesToCalculatePath = 0;
private int _maxTriesToCalculatePath = 5;
private static AIManager _instance;
public static AIManager Instance
{
get => _instance;
private set => _instance ??= value;
}
public AIManager(List<AIAgent> agents)
{
_agents = agents;
agents.ForEach(agent => { SetBehaviour(BotState.Patrol, agent); });
}
public AIManager()
{
_agents = new List<AIAgent>();
Instance = this;
HexManager.agents = new Dictionary<GameObject, AIAgent>();
}
public void AddAgent(AIAgent agent)
{
_agents.Add(agent);
agent.OnAgentInited += InitAI;
}
public void RemoveAgent(AIAgent agent)
{
_agents.Remove(agent);
agent.OnAgentInited -= InitAI;
}
private void InitAI(AIAgent agent)
{
SetBehaviour(BotState.Patrol, agent);
}
private void StartPatrolBehaviour(AIAgent agent)
{
HexManager.GetNearestDifferCell(agent.Enemy.Color, agent.currentPath);
while (agent.currentPath.Count == 0 && _triesToCalculatePath < _maxTriesToCalculatePath)
{
HexManager.GetNearestDifferCell(agent.Enemy.Color, agent.currentPath);
_triesToCalculatePath++;
}
_triesToCalculatePath = 0;
}
private Unit GetNearestUnit(int cellDist, AIAgent agent)
{
return (from unit in HexManager.UnitCurrentCell
where unit.Key != agent.Enemy.Color &&
Vector3.Distance(unit.Value.unit.Instance.transform.position,
agent.Enemy.Instance.transform.position) <= cellDist * HexGrid.HexDistance
select unit.Value.unit).FirstOrDefault();
}
public BotState GetNewBehaviour(AIAgent agent)
{
var attack = agent.Enemy.Inventory.Where(x => x is Bonus { Type: BonusType.Attack }).ToList();
if (agent.CurentState is BotState.Attack && agent.Enemy.AttackBonus == 0 && attack.Count > 0)
{
SetBehaviour(BotState.AttackBonusUsage, agent);
return BotState.AttackBonusUsage;
}
var enemy = GetNearestUnit(6, agent);
if (enemy != null && agent.Enemy.Hp > agent.Enemy.Data.maxHP / 4 && enemy.IsAlive)
{
if (Vector3.Distance(agent.Enemy.Instance.transform.position, enemy.Instance.transform.position) < 4)
{
SetBehaviour(BotState.Attack, agent);
return BotState.Attack;
}
SetBehaviour(BotState.Agressive, agent);
return BotState.Agressive;
}
if (agent.Enemy.Mana <= agent.Enemy.Data.maxMana / 3 &&
agent.Enemy.Inventory.Count < agent.Enemy.InventoryCapacity)
{
SetBehaviour(BotState.CollectingBonus, agent);
return BotState.CollectingBonus;
}
var protect = agent.Enemy.Inventory.Where(x => x is Bonus { Type: BonusType.Defence }).ToList();
if (protect.Count > 0 && agent.Enemy.Hp <= agent.Enemy.Data.maxHP / 4 && agent.Enemy.DefenceBonus == 0)
{
SetBehaviour(BotState.ProtectBonusUsage, agent);
return BotState.ProtectBonusUsage;
}
if (agent.Enemy.Hp <= agent.Enemy.Data.maxHP / 4 && GetNearestUnit(5, agent) != null)
{
SetBehaviour(BotState.Retreet, agent);
return BotState.Retreet;
}
SetBehaviour(BotState.Patrol, agent);
return BotState.Patrol;
}
private void SetBehaviour(BotState state, AIAgent agent)
{
switch (state)
{
case BotState.Patrol:
StartPatrolBehaviour(agent);
break;
case BotState.Agressive:
MoveToEnemy(agent);
break;
case BotState.Attack:
AttackEnemy(agent);
break;
case BotState.CollectingBonus:
MoveToBonus(agent);
break;
case BotState.ProtectBonusUsage:
UseBonus(agent, BonusType.Defence);
break;
case BotState.AttackBonusUsage:
UseBonus(agent, BonusType.Attack);
break;
case BotState.Dead:
break;
case BotState.Retreet:
Retreet(agent);
break;
default:
throw new ArgumentOutOfRangeException(nameof(state), state, null);
}
}
private void UseBonus(AIAgent agent, BonusType type)
{
var attack = agent.Enemy.Inventory.Where(x => x is Bonus bonus && bonus.Type == type).ToList();
if (attack.Count == 0)
{
GetNewBehaviour(agent);
return;
}
((Bonus)attack.First()).Invoke();
}
private void Retreet(AIAgent agent)
{
var enemy = GetNearestUnit(6, agent)?.Instance.transform;
if (enemy == null)
{
return;
}
var dir = -DirectionHelper.DirectionTo(agent.Enemy.Instance.transform.position,
enemy.position);
agent.currentPath.Clear();
agent.currentPath.Enqueue(DirectionHelper.VectorToDirection(new Vector2(dir.x, dir.z)));
}
private void MoveToBonus(AIAgent agent)
{
HexCell itemToMove = null;
var min = 10 * HexGrid.HexDistance;
foreach (var itemCell in ItemFabric.Items)
{
if (Vector3.Distance(agent.Enemy.Instance.transform.position, itemCell.Key.transform.position) < min)
{
min = Vector3.Distance(agent.Enemy.Instance.transform.position, itemCell.Key.transform.position);
itemToMove = itemCell.Value;
}
}
if (itemToMove == null)
{
return;
}
Pathfinding.FindPath(HexManager.UnitCurrentCell[agent.Enemy.Color].cell, itemToMove, agent.currentPath);
}
private void AttackEnemy(AIAgent agent)
{
var enemy = GetNearestUnit(3, agent);
var dir = DirectionHelper.DirectionTo(agent.Enemy.Instance.transform.position,
enemy.Instance.transform.position);
agent.AttackTarget(new Vector2(dir.x, dir.z));
}
private void MoveToEnemy(AIAgent agent)
{
var enemies = HexManager.UnitCurrentCell
.Where(unit =>
unit.Value.unit.Color != agent.Enemy.Color &&
Vector3.Distance(unit.Value.unit.Instance.transform.position,
agent.Enemy.Instance.transform.position) <= 6 * HexGrid.HexDistance).ToList();
Pathfinding.FindPath(HexManager.UnitCurrentCell[agent.Enemy.Color].cell,
enemies[Random.Range(0, enemies.Count)].Value.cell, agent.currentPath);
}
}
public enum BotState
{
Patrol,
Agressive,
Attack,
CollectingBonus,
AttackBonusUsage,
ProtectBonusUsage,
Dead,
Retreet
}
}