日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Unity 攻击范围检测

發布時間:2024/3/13 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Unity 攻击范围检测 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?眾所周知moba中的每個英雄都有一套自己的技能的攻擊范圍方式,有如廉頗一樣的圓形范圍,有火舞一樣的直線范圍,呂布的扇形方天戟范圍,還有上圖的牛魔大招時的矩形范圍等等。

????一些技能是通過物理的碰撞檢測來判斷的,一些則是通過這樣的范圍來檢測的。物理檢測的詬病就在于開銷過大,在能考慮不用物理來檢測的情況下更傾向來自己通過算法模擬實現。

小菜的學習研究中,將這些自己算法檢測的攻擊范圍劃分了幾種類型,并做了幾個demo的演示。

?

如上演示,小菜簡單的講這些類型劃分成了如下幾類:

1). Circle? ? ? ? ? ? ? ? ? ?? ? ?圓形

2).?Triangle? ? ? ? ? ? ? ? ? ??三角形

3).?Fanshaped? ? ? ? ? ? ? ??扇形

4).?Rectangle? ? ? ? ? ? ? ? ?矩形

5).?Sector? ? ? ? ? ? ? ? ? ? ? ?扇面

6). Ring? ? ? ? ? ? ? ? ? ? ? ? ??環形

?

[Circle 圓形]

這應該是最簡單的類型,只要去判斷self和target的distance就可以做到了。

我們希望能直觀看到范圍的情況,故使用Debug.DrawLine做了調試的繪制。

繪制編碼:

小菜不想由于各個對象高度的不同帶來的檢測差異,故用NormalizePosition將位置的y信息都歸置成了0。

?

范圍檢測編碼:

?

[Triangle?三角形]

三角形范圍的判定,實際就是點在三角形內的判定。

數學上檢測點在三角形內有三種推論方法。內角和法/同向法/重心法。

對數學感興趣的可以參考:https://www.cnblogs.com/graphics/archive/2010/08/05/1793393.html

小菜這里直接套用了重心法檢測。

檢測編碼:

?

繪制編碼:

?

[Fanshaped?扇形]

?

扇形的范圍檢測我們實際可以抽象成兩個步驟。

1).判斷self和target的distance.

2).由于點乘,使用點乘dot來計算self到target的單位向量,與self的forward向量(本身也是單位向量)來計算得夾角cos值。使用Mathf.Acos將其轉化為弧度,再轉換成角度做一次判斷就好了。

?

繪制編碼:

?

范圍檢測編碼:

?

[Rectangle?矩形]

矩形的檢測小菜大概是有兩種方法:

1).通過點在矩形內的數學推導公式來計算。

2).通過點乘和distance來計算。

?

還是先將矩形繪制出來吧。

繪制編碼:

?

范圍檢測:

通過點在矩形內的數學推導公式來計算矩形范圍

判斷一個點是否在兩條線段之間夾著就轉化成,判斷一個點是否在某條線段的一邊上,就可以利用叉乘的方向性,來判斷夾角是否超過了180度?。

只要判斷(AB X AE ) * (CDX CE) ?>= 0 就說明E在AB,CD中間夾著,同理計算另兩邊DA和BC就可以了。

最后就是只需要判斷

(AB X AE ) * (CD X CE) ?>= 0?&& (DA X DE ) * (BC X BE) >= 0 。

?

范圍檢測編碼:

?

通過點乘和distance來計算矩形范圍

還是先上一張圖輔助理解吧。

兩次點乘的結果在于判斷target的前后和左右關系。

編碼看似比上面的少很多,實際關聯的理解可一點都不簡單。

?

[Sector?扇面]

扇面和扇形的檢測很相似,不同的只是多了一層距離的檢測。

?

繪制編碼:

?

?

范圍檢測編碼:

?

[Ring?環形]

環形和圓形的檢測很相似,也只是多了一層距離的檢測。

繪制編碼:

?

范圍檢測編碼:

附上完整代碼:

using System.Collections; using System.Collections.Generic; using UnityEngine;public enum CheckType {None,/// <summary> 圓形 </summary>Circle,/// <summary> 三角形 </summary>Triangle,/// <summary> 扇形 </summary>Fanshaped,/// <summary> 矩形 </summary>Rectangle,/// <summary> 扇面 </summary>Sector,/// <summary> 環形 </summary>Ring, }[ExecuteInEditMode] public class RangeCheckScript : MonoBehaviour {public CheckType currType = CheckType.None;public Transform mPalyer;public Transform mTarget;public bool mCheckOpen = true;void Update(){if (!mCheckOpen)return;if (null != mPalyer)Debug.DrawLine(mPalyer.position, mPalyer.position + mPalyer.forward * 8,Color.yellow);bool bResult = false;switch (currType){case CheckType.None:break;case CheckType.Circle:bResult = CircleCheck(mPalyer, mTarget, 6);break;case CheckType.Triangle:bResult = TriangleCheck(mPalyer, mTarget, 1, 10);break;case CheckType.Fanshaped:bResult = FanshapedCheck(mPalyer, mTarget, 45, 5);break;case CheckType.Rectangle://bResult = SimulateRectangleCheck(mPalyer, mTarget, 2, 8);bResult = RectangleCheck(mPalyer, mTarget, 2, 8);break;case CheckType.Sector:bResult = SectorCheck(mPalyer, mTarget, 45, 5, 8);break;case CheckType.Ring:bResult = RingCheck(mPalyer, mTarget, 4, 8);break;default:break;}if (bResult)Debug.LogError("檢測到目標");}/// <summary>/// 圓形范圍檢測/// </summary>private bool CircleCheck(Transform self, Transform target, float distance){if (null == self || null == target)return false;//---------------------繪制圖形-----------------------------------Vector3 selfPosition = NormalizePosition(self.position);Vector3 targetPosition = NormalizePosition(target.position);int nCircleDentity = 360;Vector3 beginPoint = selfPosition;Vector3 endPoint = Vector3.zero;float tempStep = 2 * Mathf.PI / nCircleDentity;bool bFirst = true;for (float step = 0; step < 2 * Mathf.PI; step += tempStep){float x = distance * Mathf.Cos(step);float z = distance * Mathf.Sin(step);endPoint.x = selfPosition.x + x;endPoint.z = selfPosition.z + z;if (bFirst)bFirst = false;elseDebug.DrawLine(beginPoint, endPoint, Color.red);beginPoint = endPoint;}//---------------------范圍檢測-----------------------------------float currDistance = Vector3.Distance(selfPosition, targetPosition);if (currDistance <= distance)return true;return false;}/// <summary>/// 三角形范圍檢測/// </summary>private bool TriangleCheck(Transform self, Transform target, float halfWidth,float distance){if (null == self || null == target)return false;//---------------------繪制圖形-----------------------------------Vector3 selfPosition = NormalizePosition(self.position);Vector3 targetPosition = NormalizePosition(target.position);Quaternion tempQuat = self.rotation;//三角形的三個點Vector3 leftPoint = selfPosition + (tempQuat * Vector3.left) * halfWidth;Vector3 rightPoint = selfPosition + (tempQuat * Vector3.right) * halfWidth;Vector3 forwardPoint = selfPosition + (tempQuat * Vector3.forward) * distance;Debug.DrawLine(leftPoint,rightPoint,Color.red);Debug.DrawLine(rightPoint, forwardPoint, Color.red);Debug.DrawLine(forwardPoint, leftPoint, Color.red);//---------------------范圍檢測-----------------------------------bool bResult = IsPointInTriangle(leftPoint, forwardPoint, rightPoint, targetPosition);return bResult;}/// <summary>/// 扇形范圍檢測/// </summary>private bool FanshapedCheck(Transform self, Transform target, float halfAngle, float distance){if (null == self || null == target)return false;//---------------------繪制圖形-----------------------------------Vector3 selfPosition = NormalizePosition(self.position);Vector3 targetPosition = NormalizePosition(target.position);Quaternion selfQuat = self.rotation;int nCircleDentity = 360;Vector3 firstPoint = Vector3.zero;Vector3 beginPoint = selfPosition;Vector3 endPoint = Vector3.zero;float tempStep = 2 * Mathf.PI / nCircleDentity;float leftRadian = Mathf.PI / 2 + Mathf.Deg2Rad * halfAngle;float rightRadian = Mathf.PI / 2 - Mathf.Deg2Rad * halfAngle;bool bFirst = true;for (float step = 0; step < 2 * Mathf.PI; step += tempStep){float x = distance * Mathf.Cos(step);float z = distance * Mathf.Sin(step);endPoint.x = selfPosition.x + x;endPoint.z = selfPosition.z + z;if (step >= rightRadian && step <= leftRadian){if (bFirst){firstPoint = endPoint;bFirst = false;}Debug.DrawLine(beginPoint, endPoint, Color.red);beginPoint = endPoint;}}Debug.DrawLine(selfPosition, firstPoint, Color.red);Debug.DrawLine(selfPosition, beginPoint, Color.red);//---------------------范圍檢測-----------------------------------//計算距離float currDis = Vector3.Distance(selfPosition, targetPosition);if (currDis > distance)return false;//計算self到target的向量Vector3 dir = targetPosition - selfPosition;//點乘dir向量和自身的forward向量 cosqfloat dotForward = Vector3.Dot(dir.normalized, (selfQuat * Vector3.forward).normalized);//得到夾角弧度并轉換成角度float radian = Mathf.Acos(dotForward);float currAngle = Mathf.Rad2Deg * radian;if (Mathf.Abs(currAngle) <= halfAngle)return true;return false;}/// <summary>/// 矩形范圍檢測(數學點和矩形關系判斷)/// </summary>private bool SimulateRectangleCheck(Transform self, Transform target, float halfWidth, float distance){if (null == self || null == target)return false;//---------------------繪制圖形-----------------------------------Vector3 selfPosition = NormalizePosition(self.position);Vector3 targetPosition = NormalizePosition(target.position);Vector3 selfEulerAngles = self.rotation.eulerAngles;Quaternion selfQuat = self.rotation;//矩形的四個點Vector3 leftPoint = selfPosition + (selfQuat * Vector3.left) * halfWidth;Vector3 rightPoint = selfPosition + (selfQuat * Vector3.right) * halfWidth;Vector3 leftUpPoint = leftPoint + (selfQuat * Vector3.forward) * distance;Vector3 rightUpPoint = rightPoint + (selfQuat * Vector3.forward) * distance;Debug.DrawLine(selfPosition, leftPoint, Color.red);Debug.DrawLine(selfPosition, rightPoint, Color.red);Debug.DrawLine(leftPoint, leftUpPoint, Color.red);Debug.DrawLine(rightPoint, rightUpPoint, Color.red);Debug.DrawLine(leftUpPoint, rightUpPoint, Color.red);//---------------------范圍檢測-----------------------------------Vector2 point = Vector2.zero;point.x = targetPosition.x;point.y = targetPosition.z;Vector2 point1 = Vector2.zero;point1.x = leftUpPoint.x;point1.y = leftUpPoint.z;Vector2 point2 = Vector2.zero;point2.x = rightUpPoint.x;point2.y = rightUpPoint.z;Vector2 point3 = Vector2.zero;point3.x = rightPoint.x;point3.y = rightPoint.z;Vector2 point4 = Vector2.zero;point4.x = leftPoint.x;point4.y = leftPoint.z;bool bResult = IsPointInRectangle(point1, point2, point3, point4, point);return bResult;}/// <summary>/// 矩形范圍檢測(點乘方式)/// </summary>private bool RectangleCheck(Transform self, Transform target, float halfWidth, float distance){if (null == self || null == target)return false;//---------------------繪制圖形-----------------------------------Vector3 selfPosition = NormalizePosition(self.position);Vector3 targetPosition = NormalizePosition(target.position);Vector3 selfEulerAngles = self.rotation.eulerAngles;Quaternion selfQuat = self.rotation;//矩形的四個點Vector3 leftPoint = selfPosition + (selfQuat * Vector3.left) * halfWidth;Vector3 rightPoint = selfPosition + (selfQuat * Vector3.right) * halfWidth;Vector3 leftUpPoint = leftPoint + (selfQuat * Vector3.forward) * distance;Vector3 rightUpPoint = rightPoint + (selfQuat * Vector3.forward) * distance;Debug.DrawLine(selfPosition, leftPoint, Color.red);Debug.DrawLine(selfPosition, rightPoint, Color.red);Debug.DrawLine(leftPoint, leftUpPoint, Color.red);Debug.DrawLine(rightPoint, rightUpPoint, Color.red);Debug.DrawLine(leftUpPoint, rightUpPoint, Color.red);//---------------------范圍檢測-----------------------------------//計算self到target的向量Vector3 dir = targetPosition - selfPosition;//點乘dir向量和自身的forward向量float dotForward = Vector3.Dot(dir, (selfQuat * Vector3.forward).normalized);//target處于self的前方的height范圍if (dotForward > 0 && dotForward <= distance){float dotRight = Vector3.Dot(dir, (selfQuat * Vector3.right).normalized);//target處于self的左右halfWidth的范圍if (Mathf.Abs(dotRight) <= halfWidth)return true;}return false;}/// <summary>/// 扇面范圍檢測/// </summary>private bool SectorCheck(Transform self, Transform target, float halfAngle, float nearDis, float farDis){if (null == self || null == target)return false;if (nearDis > farDis){float tempDis = nearDis;nearDis = farDis;farDis = tempDis;}//---------------------繪制圖形-----------------------------------Vector3 selfPosition = NormalizePosition(self.position);Vector3 targetPosition = NormalizePosition(target.position);Quaternion selfQuat = self.rotation;int nCircleDentity = 360;Vector3 nearFirstPoint = Vector3.zero;Vector3 nearBeginPoint = selfPosition;Vector3 nearEndPoint = Vector3.zero;Vector3 farFirstPoint = Vector3.zero;Vector3 farBeginPoint = selfPosition;Vector3 farEndPoint = Vector3.zero;float tempStep = 2 * Mathf.PI / nCircleDentity;float leftRadian = Mathf.PI / 2 + Mathf.Deg2Rad * halfAngle;float rightRadian = Mathf.PI / 2 - Mathf.Deg2Rad * halfAngle;bool bFirst = true;for (float step = 0; step < 2 * Mathf.PI; step += tempStep){float nearX = nearDis * Mathf.Cos(step);float nearZ = nearDis * Mathf.Sin(step);float farX = farDis * Mathf.Cos(step);float farZ = farDis * Mathf.Sin(step);if (step >= rightRadian && step <= leftRadian){//-------繪制近扇面nearEndPoint.x = selfPosition.x + nearX;nearEndPoint.z = selfPosition.z + nearZ;//-------繪制遠扇面farEndPoint.x = selfPosition.x + farX;farEndPoint.z = selfPosition.z + farZ;if (bFirst){nearFirstPoint = nearEndPoint;farFirstPoint = farEndPoint;bFirst = false;}else{Debug.DrawLine(nearBeginPoint, nearEndPoint, Color.red);Debug.DrawLine(farBeginPoint, farEndPoint, Color.red);}nearBeginPoint = nearEndPoint;farBeginPoint = farEndPoint;}}Debug.DrawLine(nearFirstPoint, farFirstPoint, Color.red);Debug.DrawLine(nearEndPoint, farEndPoint, Color.red);Debug.DrawLine(selfPosition, nearFirstPoint, Color.blue);Debug.DrawLine(selfPosition, nearEndPoint, Color.blue);//---------------------范圍檢測-----------------------------------//計算距離float currDis = Vector3.Distance(selfPosition, targetPosition);if (currDis < nearDis || currDis > farDis)return false;//計算self到target的向量Vector3 dir = targetPosition - selfPosition;//點乘dir向量和自身的forward向量 cosqfloat dotForward = Vector3.Dot(dir.normalized, (selfQuat * Vector3.forward).normalized);//得到夾角弧度并轉換成角度float radian = Mathf.Acos(dotForward);float currAngle = Mathf.Rad2Deg * radian;if (Mathf.Abs(currAngle) <= halfAngle)return true;return false;}/// <summary>/// 雙圓范圍檢測/// </summary>private bool RingCheck(Transform self, Transform target, float nearDis, float farDis){if (null == self || null == target)return false;if (nearDis > farDis){float tempDis = nearDis;nearDis = farDis;farDis = tempDis;}//---------------------繪制圖形-----------------------------------Vector3 selfPosition = NormalizePosition(self.position);Vector3 targetPosition = NormalizePosition(target.position);int nCircleDentity = 360;Vector3 nearBeginPoint = selfPosition;Vector3 nearEndPoint = Vector3.zero;Vector3 farBeginPoint = selfPosition;Vector3 farEndPoint = Vector3.zero;float tempStep = 2 * Mathf.PI / nCircleDentity;bool bFirst = true;for (float step = 0; step < 2 * Mathf.PI; step += tempStep){float nearX = nearDis * Mathf.Cos(step);float nearZ = nearDis * Mathf.Sin(step);nearEndPoint.x = selfPosition.x + nearX;nearEndPoint.z = selfPosition.z + nearZ;float farX = farDis * Mathf.Cos(step);float farZ = farDis * Mathf.Sin(step);farEndPoint.x = selfPosition.x + farX;farEndPoint.z = selfPosition.z + farZ;if (bFirst)bFirst = false;else{Debug.DrawLine(nearBeginPoint, nearEndPoint, Color.red);Debug.DrawLine(farBeginPoint, farEndPoint, Color.red);}nearBeginPoint = nearEndPoint;farBeginPoint = farEndPoint;}//---------------------范圍檢測-----------------------------------float currDistance = Vector3.Distance(selfPosition, targetPosition);if (currDistance >= nearDis && currDistance <= farDis )return true;return false;}/// <summary>/// 規范位置(去除高度帶來的影響)/// </summary>private Vector3 NormalizePosition(Vector3 position,float hight = 0.0f){Vector3 tempPosition = Vector3.zero;tempPosition.x = position.x;tempPosition.y = hight;tempPosition.z = position.z;return tempPosition;}/// <summary>/// 三角形檢查/// </summary>private bool IsPointInTriangle(Vector3 point1, Vector3 point2, Vector3 point3, Vector3 targetPoint){Vector3 v0 = point2 - point1;Vector3 v1 = point3 - point1;Vector3 v2 = targetPoint - point1;float dot00 = Vector3.Dot(v0, v0);float dot01 = Vector3.Dot(v0, v1);float dot02 = Vector3.Dot(v0, v2);float dot11 = Vector3.Dot(v1, v1);float dot12 = Vector3.Dot(v1, v2);float inverDeno = 1 / (dot00 * dot11 - dot01 * dot01);float u = (dot11 * dot02 - dot01 * dot12) * inverDeno;if (u < 0 || u > 1)return false;float v = (dot00 * dot12 - dot01 * dot02) * inverDeno;if (v < 0 || v > 1)return false;return u + v <= 1;}/// <summary>/// 判斷點p是否在p1 p2 p3 p4構成的矩形內/// </summary>private bool IsPointInRectangle(Vector2 point1, Vector2 point2, Vector2 point3, Vector2 point4, Vector2 point){return GetCross(point1, point2, point) * GetCross(point3, point4, point) >= 0&& GetCross(point2, point3, point) * GetCross(point4, point1, point) >= 0;}/// <summary>/// 計算 |p1 p2| X |p1 p|/// </summary>private float GetCross(Vector2 point1, Vector2 point2, Vector2 point){return ((point2.x - point1.x) * (point.y - point1.y) - (point.x - point1.x) * (point2.y - point1.y));} }

?

總結

以上是生活随笔為你收集整理的Unity 攻击范围检测的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。