using System;
using System.Collections.Generic;
using UnityEngine;
using XGame;
namespace FL.Battle
{
public interface ITargetHandle
{
IEntity Entity { get; }
Vector3 Position { get; }
///
/// 是否可选中
///
bool IsCanSelected { get; }
float Radius { get; }
float AtkRange { get; }
void SelectTarget(ITargetHandle target, int skillId);
}
public struct FindTargetArgs
{
public int entityId;
public EEntityType entityType;
///
/// 范围
///
public float range;
///
/// 为零表示普通攻击
///
public int skillId;
}
///
/// 目标选择组件
///
public class TargetSelector
{
private Dictionary> _typeToHandlesMap;
private Dictionary _idToHandlesMap;
private Dictionary _waitingMap;
private List _tempLst = new List();
public void Register(ITargetHandle handle)
{
if (_typeToHandlesMap == null)
{
_typeToHandlesMap = new Dictionary>();
_idToHandlesMap = new Dictionary();
}
var type = handle.Entity.EntityType;
if (!_typeToHandlesMap.TryGetValue(type, out var handles))
{
handles = new HashSet();
_typeToHandlesMap.Add(type, handles);
}
handles.Add(handle);
_idToHandlesMap.Add(handle.Entity.EntityId, handle);
}
public void Unregister(ITargetHandle handle)
{
if (_typeToHandlesMap == null) return;
foreach(var handles in _typeToHandlesMap.Values)
{
if (handles.Contains(handle))
{
handles.Remove(handle);
break;
}
}
_idToHandlesMap.Remove(handle.Entity.EntityId);
_waitingMap?.Remove(handle);
}
public void Start(FindTargetArgs args)
{
if (_idToHandlesMap == null || _idToHandlesMap.TryGetValue(args.entityId, out var handle) == false)
{
return;
}
if (_waitingMap == null)
{
_waitingMap = new Dictionary();
}
_waitingMap[handle] = args;
}
public void Selects()
{
var count = _waitingMap?.Count ?? 0;
if (count == 0)
return;
_tempLst.AddRange(_waitingMap.Keys);
for(var i = 0; i < count; i++)
{
var director = _tempLst[i];
if (!director.IsCanSelected)
continue;
if (!_waitingMap.TryGetValue(director, out var args))
{
continue;
}
if (!TryGetTargets(args.entityType, out var targets))
{
Log.Debug($"没有可选目标 Entity:{director.Entity.TableId} Relation:{director.Entity.EntityType} Target:{args.entityType}");
continue;
}
ITargetHandle preTarget = null;
var distanceMin = float.MaxValue;
foreach (var target in targets)
{
if (!target.IsCanSelected)
continue;
if (IsInRange(director, target, args.range, out var distance))
{
if (preTarget == null || distanceMin > distance)
{
preTarget = target;
distanceMin = distance;
}
}
}
if (preTarget != null)
{
try
{
director.SelectTarget(preTarget, args.skillId);
_waitingMap.Remove(director);
}
catch (Exception ex)
{
Log.Exception(ex);
}
}
}
_tempLst.Clear();
}
private bool TryGetTargets(EEntityType entityType, out HashSet targets)
{
if (_typeToHandlesMap != null && _typeToHandlesMap.TryGetValue(entityType, out targets))
{
return true;
}
targets = null;
return false;
}
private bool IsInRange(ITargetHandle director, ITargetHandle target, float range, out float distance)
{
distance = Vector3.Distance(target.Position, director.Position);
distance -= (director.Radius + target.Radius); // 去掉双方的半径
return true;// range >= distance;
}
public void Clear()
{
_typeToHandlesMap?.Clear();
_idToHandlesMap?.Clear();
_waitingMap?.Clear();
_tempLst?.Clear();
}
}
}