概述
概括地說,在確定出發點與落點后,工坊的代碼會為我們找到投擲的角度。非常感謝將這個工坊移植到外服的小伙伴albertewang。
-
國服代碼:
T8RPA
-
Workshop code for servers outside of China:
DTV45
基礎用法
- 按下
Q
鍵將當前位置設為落點,任意時刻按下CTRL+Q
回到落點。 - 在任意位置,按下
SHIFT
鍵獲得投擲方向。 - 按下
E
鍵投擲生物手雷,若它未被阻擋,則一定會墜至落點。
輔助功能
- 按下鼠標
左鍵
傳送至准星處。 - 按住
F
將鏡頭移至落點,鏡頭的角度於設置落點時確定。- 按下
F+CTRL
以前移鏡頭。 - 按下
F+SPACE
以后移鏡頭。
- 按下
- 按住鼠標
右鍵
可進入自動模式,此時會出現動態更新的紅色指示器輔助瞄准。 - 按下
R
鍵保存當前位置,任意時刻按下CTRL+R
傳送到上一次保存的位置。
演示視頻
設計思路
驗證猜想
出於生活的慣性思維,我猜想生物手雷的軌跡是一段拋物線,於是嘗試驗證。驗證的過程需要兩個參數:投擲速度(\(v_0\))、重力加速度(\(g\))。這些參數都是能夠在工坊中測量得到的。
- 投擲速度:豎直上拋,時間、重力加速度、初速度三者滿足:\(gt=2v_0\)。
- 重力加速度:在國王大道A點三樓記錄高度與自由落體的滯空時間,滿足:\(h=\frac{1}{2}gt^2\)。
至此,\(v_0\)、\(g\)成為已知量。之后我嘗試設計了一個demo,在投擲手雷的同時繪制從玩家朝向出發,初速度為\(v_0\),加速度為\(g\)的拋物線。觀察到拋物線與軌跡幾乎完全重合,猜想成立。
導出投擲角度
已知投擲角度的情況下繪制軌跡是非常直觀且簡單的,但我們的任務是通過起點、落點、初速度求出投擲角度。盡管用到的都是初等數學知識,后者卻繁雜了許多。
參考手雷在二維平面中的軌跡(上圖),我們可以列出以下四個式子:
重力加速度\(g\)與拋出速度\(v_0\)是常量,已經通過測量得到了。因為拋出位置與落點是手動設置的,我們可以通過它們的向量得到\(h\)與\(w\)。
剩余共四個未知數,我們剛好有四個等式,於是能夠得到:
接下來我們解一元二次方程,這里只需要向上拋的那一個解就好了。得到\(v_x\)、\(v_y\)后,將它們分解為三維空間中的單位方向向量即可。
導出滯空時間
在導出投擲角度的中間步驟中我們用到了所需的兩段時間\(t_s\)、\(t_d\),遺憾的是在實現的過程中它們已被消除。不過在已經求出\(v_y\)的情況下,滯空時間的計算也很便捷。將拋物線的運動分為兩部分:
- 從起點到最高點
- 從最高點到落點
這兩部分在豎直方向上均可視作自由落體運動。對於前一段我們已知最大速度\(v_y\),則\(t_1=\frac{v_y}{g}\);對於后一段我們能夠求出豎直方向上的位移,則\(t_2=\sqrt{\frac{2(h_p+h)}{g}}\),其中\(h_p=\frac{1}{2}gt_1^2\),而\(h\)為起點與落點在豎直方向上的高度差。最終用時為:\(t_1+t_2\)。
實現
實踐出真知,許多問題只有行動起來以后才能夠被發現。
克服精度限制
地圖工坊的數字在\(x\)正半軸的表示范圍為\([10^{-3}, 10^8]\)。測試時發現在對一般規模的輸入參數進行運算的過程中,部分中間值遠大於\(10^8\) 。為了能夠得到正確答案,我們可以將所有的中間值乘以\(10^{-3}\),將小數位利用起來。在玩家尺度下,一定的的誤差是能夠接受的,代碼中的這個值是\(10^{-4}\)。最終我們的代碼滿足了一般尺度下的求解需求。
改善穿模問題
通過射線命中位置
命令,我們可以得到玩家瞄准的目標坐標;但直接將玩家傳送到該坐標是極其不負責任的,玩家有可能因穿模被傳送到牆體后方、落入地下、卡入牆體中。有兩個簡單的候選方案:
方案一 | 方案二 | |
---|---|---|
改進 | 添加最近的可行走位置 約束 |
通過射線命中法線 修正傳送點 |
優點 | 一定能夠傳送到安全的位置 | 誤差較小 |
缺點 | 無法上高台且誤差較大 | 可能會卡入牆體 |
無法上高台是致命的缺點,所以最終采用了方案二。但兩個方案並不完全互斥,我們可以嘗試在檢測到玩家卡入牆體時將其傳送至最近的可行走位置。目前的傳送功能還是非常好用的,測試的過程中完全沒有遇到問題。
代碼
- 注意:因為兼容性或本地化存在的某些問題,導入中文代碼時工坊可能會報錯,可以嘗試先在戰網客戶端中將語言(文字)切換為英文,粘貼英文版本的代碼並保存,再將語言恢復至中文。