ContextMenu確實替Debug的過程帶來巨大的便利性,但太過耀眼的光茫卻讓旅人忽視了其底下隱藏的陷阱……
前言
對Unity的Inspector有點研究的人都會知道一個叫作ContexMenu
的標籤
只要把它加到無參數且宣告為public的Method上
public class Foo : MonoBehaviour { [ContextMenu("hello world")] public void Hello() { Debug.Log("Hello world"); } }
就能直接在Inspector的右鍵選單上看到它,點兩下就能出現結果,簡直就是懶人Debug及測試的神兵利器。
BUT! 前幾天就被這好用到不行的東西給攞了一道。
且聽我細細說來
且說當時做的是一個經營遊戲的建造模式,打開建造模式就會在每個建地上彈出建造按鈕。由於建地是在Wold座標下,所以必需計算出其投影在螢幕上的座標方能生成按鈕,當時的代碼如下。
public class BuildSystem : MonoBehaviour { public Transform target;//建地 public GameObject buildBtnPrefab;//按鈕的預置物 public Transform canvas; [ContextMenu("Open Build Mode")] public void OpenBuildMode() { var screenPos= Camera.main.WorldToScreenPoint(target.position); Instantiate(buildBtnPrefab, screenPos, Quaternion.identity, canvas); } }
把腳本拖到Inspector上然後把target指定為Cube
結果實際執行後卻得到了下面的結果。
為什麼按鈕跑到了奇怪的地方?這時我就開時思考了,或許是投影的公式錯了?亦或是RectTransform座標不能直接在Instantiate內指定?但最後檢查結果沒問題。
見鬼了
最後我突然萌生了一個想法﹐如果把Code改成下面這樣呢?
private void Start() { OpenBuildMode(); } public void OpenBuildMode() { Debug.Log(Camera.main); var screenPos= Camera.main.WorldToScreenPoint(target.position); Instantiate(buildBtnPrefab, screenPos, Quaternion.identity, canvas); }
嗯~一點問題都沒有呢~
真TMD見鬼了
好的,那麼罪魁禍首100%出在ContexMenu
上沒跑了。
經過仔細的測試後,結論是如果在編輯器暫停時呼叫ContexMenu
,座標計算就不會出錯。
結論
如果有使用到Camera.main.WorldToScreenPoint
或是其它會牽涉到座標投影函式的情況下,切記不要使用ContextMenu
來做測試,自己用OnGUI或是用Canvas做個按鈕吧。
不過OnGUI在部份平台上會導致記憶體無法釋放要小心唷~(笑)