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); } } }