/// <summary> /// 矩形判定 /// 1、求圆心与中心向量(取绝对值) /// 2、求圆心与第一象限顶点距离 /// 3、得到点到矩形边的距离(分离轴即为圆心与最近的一边的垂线段) /// 4、与半径对比即可 /// </summary> /// <returns></returns> public static bool RectCollideCheck(SRect sRect, SSphere pTarget, Vector3 vDir) { Quaternion quat = Quaternion.LookRotation(vDir); Quaternion inverseQuat = Quaternion.Inverse(quat); Vector3 sTemp = pTarget.pos - sRect.center; sTemp.y = 0; sTemp = inverseQuat * sTemp; //Vector2 sRectPos = new Vector2(sRect.center.x, sRect.center.z); //Vector2 sTargetPos = new Vector2(pTarget.pos.x, pTarget.pos.z); Vector2 vAimDir = new Vector2(0, 1); Vector2 vOpAimDir = new Vector2(1, 0); //test ////取二维向量绝对值 //Vector2 offestVec = Vector2.Max((sRectPos - sTargetPos), (sTargetPos - sRectPos)); //取二维向量绝对值 Vector2 offestVec = new Vector2(Mathf.Abs(sTemp.x), Mathf.Abs(sTemp.z)); //取第一象限顶点 Vector2 vertexVec = vAimDir * (sRect.length * 0.5f) + vOpAimDir * (sRect.width * 0.5f); //当x,y某值小于0时即非垂直向量,归置为0即可 Vector2 verticalVec = Vector2.Max(offestVec - vertexVec, Vector2.zero); return(verticalVec.sqrMagnitude <= pTarget.r * pTarget.r); }
/// <summary> /// 球体判定只要比R+r小即可(分离轴即为两个圆心的连线) /// </summary> /// <returns></returns> public static bool SphereCollideCheck(SSphere sSphere, SSphere pTarget, Vector3 vDir) { Vector2 sSpherePos = new Vector2(sSphere.pos.x, sSphere.pos.z); Vector2 sTargetPos = new Vector2(pTarget.pos.x, pTarget.pos.z); float distance = Vector2.Distance(sSpherePos, sTargetPos); if (distance <= sSphere.r + pTarget.r) { return(true); } return(false); }
/// <summary> /// 扇形判定 /// 共有三种分离轴 /// 1、扇形圆心和圆盘圆心的方向(扇形的圆弧部分) /// 2、扇形两边的法线 /// 3、扇形三个顶点和圆盘圆心的方向 /// /// 1、先判断扇形与圆盘的方向 /// 2、计算圆盘圆心与扇形的最近点的向量 p /// 3、计算当前圆心是否在扇形内部 /// 4、计算扇形左边半径是否与圆形相交 /// </summary> /// <returns></returns> public static bool SectorCollideCheck(SSector sSector, SSphere pTarget, Vector3 vDir) { Vector2 sSectorPos = new Vector2(sSector.pos.x, sSector.pos.z); Vector2 sTargetPos = new Vector2(pTarget.pos.x, pTarget.pos.z); vDir.Normalize(); Vector2 vAimDir = new Vector2(vDir.x, vDir.z); Vector2 vOpAimDir = new Vector2(-vDir.z, vDir.x); float angle = sSector.angle * 0.5f * Mathf.Deg2Rad; // 1. 如果扇形圆心和圆盘圆心的方向 Vector2 vOffest = sTargetPos - sSectorPos; if (vOffest.sqrMagnitude >= (sSector.r_max + pTarget.r) * (sSector.r_max + pTarget.r)) { return(false); } if (vOffest.sqrMagnitude <= (sSector.r_min - pTarget.r) * (sSector.r_min - pTarget.r)) { return(false); } // 2. 计算出扇形局部空间的 p float px = Vector2.Dot(vOffest, vAimDir); float py = Mathf.Abs(Vector2.Dot(vOffest, vOpAimDir)); //取仅为第一\二象限的情况化简难度 // 3. 如果 p_x > ||p|| cos theta,两形状相交 当前圆心在扇形内部 if (px > vOffest.magnitude * Mathf.Cos(angle)) { return(true); } // 4. 求左边线段与圆盘是否相交 Vector2 q = sSector.r_max * new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)); //得到扇形左边坐标 Vector2 p = new Vector2(px, py); //得到扇形与圆形相对坐标 //计算出左边线段与圆盘的分离轴,之后通过长度对比即可 float t = Vector2.Dot(p - Vector2.zero, q) / q.sqrMagnitude; float length = (p - (Vector2.zero + Mathf.Clamp(t, 0, 1) * q)).sqrMagnitude; return(length <= pTarget.r * pTarget.r); }
/// <summary> /// 环形判定 /// 简单进行半径与敌人比对即可 /// </summary> /// <returns></returns> public static bool RingCollideCheck(SRing sRing, SSphere pTarget, Vector3 vDir) { Vector2 sRingPos = new Vector2(sRing.pos.x, sRing.pos.z); Vector2 sTargetPos = new Vector2(pTarget.pos.x, pTarget.pos.z); vDir.Normalize(); //Vector2 vAimDir = new Vector2(vDir.x, vDir.z); //Vector2 vOpAimDir = new Vector2(-vDir.z, vDir.x); Vector2 vOffest = sTargetPos - sRingPos; if (vOffest.sqrMagnitude >= (sRing.r_max + pTarget.r) * (sRing.r_max + pTarget.r)) { return(false); } if (vOffest.sqrMagnitude <= (sRing.r_min - pTarget.r) * (sRing.r_min - pTarget.r)) { return(false); } return(true); }
public override List <Avatar> GetTargetList(DRSkillData pSkillData, Avatar pCaster, GTargetInfo sTarInfo, HashSet <int> vExcludeList) { List <Avatar> vTargetList = new List <Avatar>(); if (pSkillData == null || !pCaster) { return(vTargetList); } Avatar pTarget = GameEntry.Entity.GetGameEntity(sTarInfo.m_nTargetID) as Avatar; if (!pTarget) { pTarget = pCaster; } int cnt = GetTargetCount(pSkillData /*, vExcludeList*/); int filter = pSkillData.MSV_AreaFilter; float minDis = pSkillData.MSV_AreaParam1; float maxDis = pSkillData.MSV_AreaParam2; float w = pSkillData.MSV_AreaParam3; List <UnityGameFramework.Runtime.Entity> pList = new List <UnityGameFramework.Runtime.Entity>(); GameEntry.Entity.GetAllLoadedEntities(pList); if (pList == null || pList.Count == 0) { return(vTargetList); } Vector3 pos = /*pSkillData.IsAreaUseTarPos() ? sTarInfo.m_vTarPos :*/ sTarInfo.m_vSrcPos; Vector3 dir = sTarInfo.m_vAimDir; Vector3 center = pos + dir * ((minDis + maxDis) / 2); SRect sRect = new SRect(center, maxDis - minDis, w); foreach (var item in pList) { Avatar actor = item.Logic as Avatar; if (actor == null || actor == pCaster) { continue; } SSphere sTarSphere = new SSphere(actor.GetPos(), actor.ModelRadius); if (GCollider.RectCollideCheck(sRect, sTarSphere, dir)) { TryAddTarget(pSkillData, pCaster, actor, vExcludeList); if (vTargetList.Count >= cnt) { if (filter > 0) { UpdateAreaFilter(filter, cnt, vTargetList); } else { return(vTargetList); } } break; } } return(vTargetList); }