using System; using System.Collections.Generic; using UnityEngine; namespace Game { public class SkillHitInfo { public AttackBehaviour SkillParam; public Vector3 HitDir; public int OwnerEntity; public int HitEntity; public float AttackRate; public float StunkRate; public string SkillId; //是否技能造成的伤害 public bool IsBreak; public int HitIndex; public int HitCount; public float Rank; public bool Continue; } public class ClipAttack : TimelineClipBase { private AttackClip _mRealAsset; private readonly List _tempHitInfoList = new List(); public override void OnEnter() { _mRealAsset = Asset as AttackClip; } public override void OnStay() { var param = _mRealAsset.template; var skill = Owner.skill; var castShape = param.Shape; var castDir = Util.IgnoreY(skill.CastDir); var rot = Quaternion.FromToRotation(Vector3.right, castDir); var castPos = rot * castShape.Offset + Owner.Pos(); Util.DrawShape(castShape, castPos, castDir, Color.red); _tempHitInfoList.Clear(); var (rankMin, rankMax) = (float.MaxValue, float.MinValue); Util.ForeachEnemies(Owner.Team(), target => { //检测命中 var isHit = UtilShape.IsOverlap(castShape, castPos, castDir, target.hp.HitBoxShape, target.Pos()); if (!isHit) return; //排除重复命中 var hitKey = new Tuple(target.ID(), param.hitId); if (skill.HitSet.Contains(hitKey)) return; skill.HitSet.Add(hitKey); //计算结算顺序rank var rank = GetRank(param.hitOrderType, target, castPos, castDir); if (rank < rankMin) rankMin = rank; if (rank > rankMax) rankMax = rank; var skillHitInfo = new SkillHitInfo { SkillParam = param, AttackRate = 1, StunkRate = 1, OwnerEntity = Owner.ID(), HitEntity = target.ID(), HitDir = GetHitDir(param.hitDirType, target, castPos, castDir), SkillId = skill.SkillId.Value, IsBreak = true, Rank = rank, }; if (!string.IsNullOrEmpty(skillHitInfo.SkillId)) { var skillCfg = Util.GetSkillMasterConfigData(skillHitInfo.SkillId); if (skillCfg != null) { var featureSkill = skillCfg.GetFeatureSkill(); skillHitInfo.AttackRate = featureSkill.AttackRate; skillHitInfo.StunkRate = featureSkill.StunRate; } } _tempHitInfoList.Add(skillHitInfo); }); _tempHitInfoList.Sort((l, r) => l.Rank.CompareTo(r.Rank)); var hitNum = _tempHitInfoList.Count; var rankGroup = 0; var rankRange = rankMax - rankMin; //rank范围大小 var rankRangeEach = rankRange / GameConst.HitMaxSettle; //单个group的rank范围大小 for (var i = 0; i < hitNum; i++) { var info = _tempHitInfoList[i]; info.HitIndex = i; info.HitCount = hitNum; var rate = (info.Rank - rankMin) / rankRange; if (rate > rankGroup * rankRangeEach) { rankGroup++; } else { info.Continue = true; } skill.HitInfo.Enqueue(info); if (!info.SkillParam.isAoe) { break; } } } private Vector3 GetHitDir(EHitDirType hitOrderType, GameEntity target, Vector3 castPos, Vector3 castDir) { var targetPos = target.Pos(); var targetDir = targetPos - castPos; targetDir.y = 0; switch (hitOrderType) { case EHitDirType.Center: //从中心到外围 return targetDir; case EHitDirType.Backward: //从前往后 return -castDir; case EHitDirType.Forward: //从后往前 return castDir; case EHitDirType.Clockwise: //顺时针 return GetDirRot(targetDir, true); case EHitDirType.CounterClockwise: //逆时针 return GetDirRot(targetDir, false); case EHitDirType.CenterForward: //中心向前 return targetDir + castDir; case EHitDirType.ClockwiseForward: //顺时针向前 return GetDirRot(targetDir, true) + castDir; case EHitDirType.CounterClockwiseForward: //逆时针向前 return GetDirRot(targetDir, false) + castDir; } return targetDir; } private Vector3 GetDirRot(Vector3 targetDir, bool isClockwise) { var sub = (Owner.move.IsRight ? -1 : 1) * (isClockwise ? 1 : -1); return Vector3.Cross(targetDir, Vector3.up * sub).normalized; } private float GetRank(EHitOrderType hitOrderType, GameEntity target, Vector3 castPos, Vector3 castDir) { //小在前 var targetPos = target.Pos(); var targetDir = targetPos - castPos; switch (hitOrderType) { case EHitOrderType.Center: //按距离 return Vector3.Distance(targetPos, castPos); case EHitOrderType.Backward: //从前往后 return -Vector3.Dot(targetDir, castDir); case EHitOrderType.Forward: //从后往前 return Vector3.Dot(targetDir, castDir); case EHitOrderType.Clockwise: //顺时针 return -GetRankRot(castDir, targetDir); case EHitOrderType.CounterClockwise: //逆时针 return GetRankRot(castDir, targetDir); } return 0; } private float GetRankRot(Vector3 castDir, Vector3 targetDir) { var rot = Quaternion.FromToRotation(-castDir, Vector3.right); return Util.Vec3ToRot(rot * targetDir) * (Owner.move.IsRight ? 1 : -1); } } }