//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityGameFramework.Runtime;
namespace MetaClient
{
///
/// AI 工具类。
///
public static class AIUtility
{
private static Dictionary s_CampPairToRelation = new Dictionary();
private static Dictionary, CampType[]> s_CampAndRelationToCamps = new Dictionary, CampType[]>();
static AIUtility()
{
s_CampPairToRelation.Add(new CampPair(CampType.Player, CampType.Player), RelationType.Friendly);
s_CampPairToRelation.Add(new CampPair(CampType.Player, CampType.Enemy), RelationType.Hostile);
s_CampPairToRelation.Add(new CampPair(CampType.Player, CampType.Neutral), RelationType.Neutral);
s_CampPairToRelation.Add(new CampPair(CampType.Player, CampType.Player2), RelationType.Hostile);
s_CampPairToRelation.Add(new CampPair(CampType.Player, CampType.Enemy2), RelationType.Hostile);
s_CampPairToRelation.Add(new CampPair(CampType.Player, CampType.Neutral2), RelationType.Neutral);
s_CampPairToRelation.Add(new CampPair(CampType.Enemy, CampType.Enemy), RelationType.Friendly);
s_CampPairToRelation.Add(new CampPair(CampType.Enemy, CampType.Neutral), RelationType.Neutral);
s_CampPairToRelation.Add(new CampPair(CampType.Enemy, CampType.Player2), RelationType.Hostile);
s_CampPairToRelation.Add(new CampPair(CampType.Enemy, CampType.Enemy2), RelationType.Hostile);
s_CampPairToRelation.Add(new CampPair(CampType.Enemy, CampType.Neutral2), RelationType.Neutral);
s_CampPairToRelation.Add(new CampPair(CampType.Neutral, CampType.Neutral), RelationType.Neutral);
s_CampPairToRelation.Add(new CampPair(CampType.Neutral, CampType.Player2), RelationType.Neutral);
s_CampPairToRelation.Add(new CampPair(CampType.Neutral, CampType.Enemy2), RelationType.Neutral);
s_CampPairToRelation.Add(new CampPair(CampType.Neutral, CampType.Neutral2), RelationType.Hostile);
s_CampPairToRelation.Add(new CampPair(CampType.Player2, CampType.Player2), RelationType.Friendly);
s_CampPairToRelation.Add(new CampPair(CampType.Player2, CampType.Enemy2), RelationType.Hostile);
s_CampPairToRelation.Add(new CampPair(CampType.Player2, CampType.Neutral2), RelationType.Neutral);
s_CampPairToRelation.Add(new CampPair(CampType.Enemy2, CampType.Enemy2), RelationType.Friendly);
s_CampPairToRelation.Add(new CampPair(CampType.Enemy2, CampType.Neutral2), RelationType.Neutral);
s_CampPairToRelation.Add(new CampPair(CampType.Neutral2, CampType.Neutral2), RelationType.Neutral);
}
///
/// 获取两个阵营之间的关系。
///
/// 阵营一。
/// 阵营二。
/// 阵营间关系。
public static RelationType GetRelation(CampType first, CampType second)
{
if (first > second)
{
CampType temp = first;
first = second;
second = temp;
}
RelationType relationType;
if (s_CampPairToRelation.TryGetValue(new CampPair(first, second), out relationType))
{
return relationType;
}
Log.Warning("Unknown relation between '{0}' and '{1}'.", first.ToString(), second.ToString());
return RelationType.Unknown;
}
///
/// 获取和指定具有特定关系的所有阵营。
///
/// 指定阵营。
/// 关系。
/// 满足条件的阵营数组。
public static CampType[] GetCamps(CampType camp, RelationType relation)
{
KeyValuePair key = new KeyValuePair(camp, relation);
CampType[] result = null;
if (s_CampAndRelationToCamps.TryGetValue(key, out result))
{
return result;
}
// TODO: GC Alloc
List camps = new List();
Array campTypes = Enum.GetValues(typeof(CampType));
for (int i = 0; i < campTypes.Length; i++)
{
CampType campType = (CampType)campTypes.GetValue(i);
if (GetRelation(camp, campType) == relation)
{
camps.Add(campType);
}
}
// TODO: GC Alloc
result = camps.ToArray();
s_CampAndRelationToCamps[key] = result;
return result;
}
///
/// 获取实体间的距离。
///
/// 实体间的距离。
public static float GetDistance(Entity fromEntity, Entity toEntity)
{
Transform fromTransform = fromEntity.CachedTransform;
Transform toTransform = toEntity.CachedTransform;
return (toTransform.position - fromTransform.position).magnitude;
}
public static void PerformCollision(TargetableObject entity, Entity other)
{
if (entity == null || other == null)
{
return;
}
TargetableObject target = other as TargetableObject;
if (target != null)
{
ImpactData entityImpactData = entity.GetImpactData();
ImpactData targetImpactData = target.GetImpactData();
if (GetRelation(entityImpactData.Camp, targetImpactData.Camp) == RelationType.Friendly)
{
return;
}
int entityDamageHP = CalcDamageHP(targetImpactData.Attack, entityImpactData.Defense);
int targetDamageHP = CalcDamageHP(entityImpactData.Attack, targetImpactData.Defense);
int delta = Mathf.Min(entityImpactData.HP - entityDamageHP, targetImpactData.HP - targetDamageHP);
if (delta > 0)
{
entityDamageHP += delta;
targetDamageHP += delta;
}
entity.ApplyDamage(target, entityDamageHP);
target.ApplyDamage(entity, targetDamageHP);
return;
}
Bullet bullet = other as Bullet;
if (bullet != null)
{
ImpactData entityImpactData = entity.GetImpactData();
ImpactData bulletImpactData = bullet.GetImpactData();
if (GetRelation(entityImpactData.Camp, bulletImpactData.Camp) == RelationType.Friendly)
{
return;
}
int entityDamageHP = CalcDamageHP(bulletImpactData.Attack, entityImpactData.Defense);
entity.ApplyDamage(bullet, entityDamageHP);
GameEntry.Entity.HideEntity(bullet);
return;
}
}
private static int CalcDamageHP(int attack, int defense)
{
if (attack <= 0)
{
return 0;
}
if (defense < 0)
{
defense = 0;
}
return attack * attack / (attack + defense);
}
[StructLayout(LayoutKind.Auto)]
private struct CampPair
{
private readonly CampType m_First;
private readonly CampType m_Second;
public CampPair(CampType first, CampType second)
{
m_First = first;
m_Second = second;
}
public CampType First
{
get
{
return m_First;
}
}
public CampType Second
{
get
{
return m_Second;
}
}
}
}
}