using FL.Battle.Actions;
using FL.Battle.Skills;
using System;
using System.Collections.Generic;
using UnityEngine;
using XGame.Database;
using XGame.Framework;
using XGame.Framework.Components;
using XGame.Framework.Time;
namespace FL.Battle.Components.AI
{
public interface IAOEEntityAIContext
{
long UID { get; }
long MasterId { get; }
int TableId { get; }
ITargetSelector Selector { get; }
ITimeModule Time { get; }
Vector3 Position { get; }
Transform Tr { get; }
MoveComponent Move { get; }
VfxComponent Vfx { get; }
}
///
/// AI组件和具体的EntityView绑定,其他Component最好不要尝试获取AI组件
/// 虫群特效半径为1,配置宽高需要X2,该特效不适合缩放,预制按照目标尺寸重复摆放基础特效
///
public class AOEEntityAI : Component
{
private EEntityType _targetType;
private ITimer _aoeTimer;
private ITimer _stopTimer;
private SkillTable _skill;
private SkillVfxsTable _skillVfxs;
private List _targets = new List();
private HashSet _selectedTargetIds = new();
private Dictionary _targetHitTimesMap = new();
protected override void OnDispose()
{
_selectedTargetIds.Clear();
_targetHitTimesMap.Clear();
_targets.Clear();
_aoeTimer?.Cancel();
_aoeTimer = null;
_stopTimer?.Cancel();
_stopTimer = null;
_skill = null;
_skillVfxs = null;
}
public void Start(Vector3 targetPosition, EEntityType targetType)
{
_skill = SkillTableRepo.Get(Context.TableId);
_skillVfxs = SkillVfxsTableRepo.Get(Context.TableId);
_targetType = targetType;
//Context.ParticleTr.localScale = new Vector3(_skill.Ranges[1] * 0.5f, _skill.Ranges[2] * 0.5f, 1);
// 飞到目标位置
if (_skill.SkillVfxType == (int)ESkillVfxType.AOE)
{
var moveArgs = new MoveArgs()
{
target = targetPosition,
speed = _skillVfxs.SkillVfxSpeed,
timeScale = 1,
onComplete = StopAOE
};
if (Enum.TryParse(_skillVfxs.SkillVfxMoveEase, true, out var ease))
{
moveArgs.ease = ease;
}
//Context.Tr.forward = (targetPosition - Context.Position).normalized;
Context.Move.MoveTo(moveArgs);
}
else
{ //TODO 判断是否需要左右镜像
Context.Tr.localScale = new Vector3(-1, 1, 1);
_stopTimer = Context.Time.AddDelayTimer(_skillVfxs.SkillVfxTime, StopAOE);
}
_aoeTimer = Context.Time.AddDelayLooperTimer(_skill.DamageArgs[1], _skill.DamageArgs[2], OnAOE, _skill.DamageArgs[0]);
}
private void OnAOE(int obj)
{
// 是否重复选中,0:false
var isSelectOnce = _skill.DamageArgs[3] == 0;
// 受击次数,-1:不限,1:1次
var hitLimit = _skill.DamageArgs[4];
bool IsFilt(ITarget a)
{
if (isSelectOnce)
return _selectedTargetIds.Contains(a.Entity.EntityId);
return false;
}
bool isHaveTargets;
if (_skill.Ranges[0] == 1)
{ // 矩形
var size = new Vector2(_skill.Ranges[1], _skill.Ranges[2]);
Vector2 position = Context.Position;
position -= (size * 0.5f);
var rect = new Rect(position, size);
isHaveTargets = Context.Selector.FindTargets(rect, _targetType, ETargetFindType.InRangeAlive, IsFilt, ref _targets);
}
else
{
var finder = new FinderInfo()
{
uid = Context.UID,
position = Context.Position,
radius = _skill.Ranges[1]
};
isHaveTargets = Context.Selector.FindTargets(finder, _targetType, ETargetFindType.InRangeAlive, IsFilt, ref _targets);
}
if (isHaveTargets)
{
// 计算受击伤害
foreach (var target in _targets)
{
var targetId = target.Entity.EntityId;
var hitTimes = 0;
var damage = _skill.Damage;
if (hitLimit < 0 || _targetHitTimesMap.TryGetValue(targetId, out hitTimes) == false || hitTimes < hitLimit)
{ // 没有有受击次数限制 或 受击次数未达到上限
PlayHitVfx(target.Position);
if (_skill.Ranges[0] == 2 && _skill.Ranges.Length == 5)
{ // 圆形,有半径递减
var distance = Vector3.Distance(target.Position, Context.Position);
if (distance > _skill.Ranges[3])
{
// 向上取整
damage = Mathf.CeilToInt((1 - _skill.Ranges[4]) * damage);
}
}
}
else
{ // 本次受击不造成伤害,但是还是要判断触发buff等
damage = 0;
}
//if (_skill.SkillVfxType == (int)ESkillVfxType.AOETarget)
//{
// Log.Debug($"Skill AOE Id:{_skill.Id} target:{targetId} damage:{damage}");
//}
target.Calculation.Damage(-damage, Context.MasterId, _skill);
if (hitLimit > 0)
{ // 记录目标受击次数
_targetHitTimesMap[targetId] = ++hitTimes;
}
if (isSelectOnce)
_selectedTargetIds.Add(targetId);
}
_targets.Clear();
}
//if (_skill.SkillVfxType == (int)ESkillVfxType.AOENoMove)
//{
// StopAOE();
//}
}
///
/// 受击特效
///
///
private void PlayHitVfx(Vector3 targetPosition)
{
if (string.IsNullOrEmpty(_skillVfxs.HitVfx))
return;
var actPosition = ObjectPool.Acquire();
actPosition.position = targetPosition;
var hitArgs = ObjectPool.Acquire();
hitArgs.vfxName = _skillVfxs.HitVfx;
hitArgs.duration = _skillVfxs.HitVfxTime;
hitArgs.followType = EVfxFollowType.World;
hitArgs.action = actPosition;
Context.Vfx.Play(hitArgs);
}
private void StopAOE()
{
_aoeTimer?.Cancel();
_aoeTimer = null;
_stopTimer?.Cancel();
_stopTimer = null;
EventSingle.Instance.Notify(EventDefine.GameMainMapRemoveSimpleEntity, Context.UID);
}
}
}