Unity3d:在屏幕邊緣顯示其他玩家/敵人/物體的方位

系列傳送門

IOS:
IOS:使用shell命令打包并上傳Itunes
Unity3d:
Unity3d:Canvas適配屏幕分辨率與錨點(Anchors與Pivot)
Unity3d:在屏幕邊緣顯示其他玩家方位
Unity3d:命令行打包Android
Unity3d:命令行編譯IOS
Unity3d:使用Jenkins自動編譯打包IOS(只能打包Development)
Unity3d:使用Jenkins自動編譯打包IOS(打包Ad-hoc,上傳itunes)

最近需要我完成一個小功能:當有玩家在屏幕外時,就在屏幕邊緣顯示該玩家所在的方位。
特此記下解決方法,予以大家借鑒。
感謝幫助過的朋友們??。

1、先復習點數學小知識

1.1、已知兩個點:P1(x1, y1)、P2(x2, y2),在直線方程為:a * x + b = y 的直線上,求a,b

解:
由 :a * x1 + b=y1,a * x2 + b=y2
=> a * x2 + y1 - a * x1 = y2
=> a = (y2 - y1) / (x2 - x1)
把a代入: a * x1 + b = y1
=> (y2 - y1) / (x2 - x1) * x1 + b=y1
=> b = y1 - (y2 - y1) / (x2 - x1) * x1
 最終:
a = (y2 - y1) / (x2 - x1)
b = y1 - (y2 - y1) / (x2 - x1) * x1

需要注意兩個點x坐標相等的情況:
如果兩個點x坐標相等,則該直線與y軸平行;
如果兩個點y坐標相等,則該直線與x軸平行;
如果兩個點x,y坐標都相等,則不是線,是同一個點。

1.2、已知兩條直線的方程:a1 * x + b1 = y 和 a2 * x + b2 = y,求這兩條直線的交點

解:
由 :a1 * x + b1=y,a2 * x + b2=y
=> a1 * x + b1 = a2 * x + b2
=> x = (b2 - b1) / (a2 - a1)
把x代入: a1 * x + b1=y
=> y = a1 * (b2 - b1) / (a2 - a1) + b1
 最終:
x = (b2 - b1) / (a2 - a1)
y = a1 * (b2 - b1) / (a2 - a1) + b1

需要注意a1和a2相等的情況:
如果a1和a2相等,b1和b2不相等,則兩條直線平行,無交點;
如果a1和a2相等,b1和b2相等,則兩條直線是同一條線,無交點;
如果a1和a2不相等,b1和b2相等,則兩條直線不平行,有交點,相交于y軸b1點或b2點;
如果a1和a2不相等,b1和b2不相等,則兩條直線不平行,有交點。

1.3、已知線段1和線段2的端點,求這兩條線段的交點

注意是線段,不是直線。
通過(1)求得端點所在的直線的方程;
通過(2)求得這兩條直線的交點。

這里需要判斷下交點是落在線段內,還是線段外(虛交點):
如果交點x坐標小于線段1的左側端點的x坐標,或者交點x坐標大于線段1的右側端點的x坐標,則該交點落在線段1外,即線段的延長線上,是個虛交點。
反之,是線段1的正常交點。

2、再學習點Unity小知識

傳送門

Unity3d:Canvas適配屏幕分辨率與錨點(Anchors與Pivot)

3、進入正題

場景準備:當前玩家(我)是playerA;另一個玩家是playerB。
方位指示器的UI我們放在Root Canvas下。
Root Canvas的CanvasScaler組件配置如下:

  • UI Scale Mode:Scale With Screen Size
  • Reference Resolution:X 1080 ,Y 1920
  • Screen Match Mode:Expand

3.1、理清思路

首先,playerA是一定在屏幕內的,這里需要判斷playerB是不是在屏幕內。
如果playerB是在屏幕內,則無需后面的處理。
如果playerB是在屏幕外,讓我們繼續。

然后,把playerA和playerB的世界坐標轉換成屏幕坐標系里的坐標,分別記作A和B。
注意:這里有個容易鉆進去的誤區,就是很容易想到去計算方向向量,即(BA)。計算完之后又會自然而然的想著用這個向量去處理上面的問題,最后會發現,自己已經進入了一個深坑里,深深的把自己的思維給圈住了,即使偶爾換個方向思考,比如求交點的方式,還是容易被這個向量給迷惑,總想著去用這個向量去解決,盡管這個向量在這個方式里沒啥卵用。

這時,因為A點在屏幕內,B點在屏幕外,所以線段AB一定與屏幕的某一個邊框有一個交點(實交點,非虛交點)。
這個交點的位置就是我們需要放置方位指示器UI的位置了。
:實交點,即交點位于線段上;虛交點,即交點位于線段的延長線上。

3.2、著手解決

屏幕有4個邊框,所以我們要先找出這四個邊框線段各自擁有的端點坐標。

這里需要注意,A和B兩個點是在屏幕坐標系上,線段AB與屏幕邊框的交點也是位于屏幕坐標系上。
而方位指示器UI是放在Canvas上的,位于Canvas坐標系內。
所以在計算之前要先做坐標系轉換。

這里有兩個轉換方式:

  • 方式1:把A和B兩個點轉換到Canvas的坐標系內,用轉換之后的線段AB計算出與Canvas的四個邊框相交的交點。
  • 方式2:先在屏幕坐標系上,計算出線段AB與屏幕的四個邊框相交的交點,然后把交點轉換到Canvas的坐標系內。

注意:后面用到的知識在文章Unity3d:Canvas適配屏幕分辨率與錨點(Anchors與Pivot)中有詳細說明,遇到問題可自行查閱。

3.2.1、按方式1解決

先把A點和B點轉換到Canvas的坐標系內:
cA = (A.x * Canvas.Width / Screen.Width, A.y * Canvas.Height / Screen.Height)
cB = (B.x * Canvas.Width / Screen.Width, B.y * Canvas.Height / Screen.Height)

再找出Canvas的四個邊框線段對應的端點(左下角是原點):
左側邊框端點:lbP(0, 0) 、ltP(0, Canvas.Height) ;
底部邊框端點:lbP(0, 0) 、rbP(Canvas.Width, 0) ;
右側邊框端點:rbP(Canvas.Width, 0) 、rtP(Canvas.Width, Canvas.Height) ;
頂部邊框端點:ltP(0, Canvas.Height) 、rtP(Canvas.Width, Canvas.Height) ;

有了線段cAcB和Canvas的四個邊框線段,根據上面的數學知識,可以輕松求得線段cAcB與Canvas某一個邊框的交點,我們記作點P。此時點P位于Canvas的坐標系內。
最后把方位指示器UI在P點顯示出來即可。在文章Unity3d:Canvas適配屏幕分辨率與錨點(Anchors與Pivot)的最后有相關知識,請自行查閱_

3.2.2、按方式2解決

現在線段AB的兩個端點有了(即A、B點),下面再找出屏幕的四個邊框線段對應的端點(左下角是原點):
左側邊框端點:lbP(0, 0) 、ltP(0, Screen.Height) ;
底部邊框端點:lbP(0, 0) 、rbP(Screen.Width, 0) ;
右側邊框端點:rbP(Screen.Width, 0) 、rtP(Screen.Width, Screen.Height) ;
頂部邊框端點:ltP(0, Screen.Height) 、rtP(Screen.Width, Screen.Height) ;

有了線段AB和屏幕的四個邊框線段,根據上面的數學知識,可以輕松求得線段AB與屏幕某一個邊框的交點,我們記作點P。此時點P位于屏幕的坐標系內。

然后把交點P轉換到Canvas的坐標系內:
cP = (P.x * Canvas.Width / Screen.Width, P.y * Canvas.Height / Screen.Height)
最后把方位指示器UI在cP點顯示出來即可。在文章Unity3d:Canvas適配屏幕分辨率與錨點(Anchors與Pivot)的最后有相關知識,請自行查閱_

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。