iT邦幫忙

2022 iThome 鐵人賽

DAY 3
3

自幼時玩過迷魂車之後,心中就埋下了一個製作開車遊戲的夢想。不過長大後開始寫遊戲,卻一直沒花時間想通這個四輪車前輪轉後輪不轉的運動軌跡,到底要如何不藉助物理引擎的幫助就能模擬出來。
rally-x
如果你也跟我一樣在心中有著這個困擾,那就來對地方了。請接著看下去,跟著我一解幼時的疑惑吧。

問題所在

經典的迷魂車其實並沒有解決這個四輪車的問題,迷魂車在轉彎時,只是以中心為軸旋轉至前進的方向而己。
迷魂車轉彎系統
這樣的設計符合迷魂車容易操縱的遊戲需求,但如果我們要更貼近真實四輪車的運動軌跡,就不能用這麼簡單的方法來處理了。

合理的輪胎軌跡應該會在輪胎正後方產生一條同向的胎痕,但是在迷魂車的後輪上,我們看到後輪後方的胎痕和後輪的方向並不一致,這就是迷魂車開起來不像真正四輪車的原因。
合理的輪胎軌跡

四輪車演算法

這個演算法講開了其實很簡單,我們在每幀將車子依方向盤及車速移動的時候,依以下四個步驟逐步操作,

  1. 車子的方向由兩個前輪的中心點,以及兩個後輪的中心點決定(這其實不算步驟,而是個前提)。
  2. 只有前輪能產生改變車子方向的力矩,因此要先算前輪位置。
  3. 前輪中心已固定,新的前輪位置會決定新的後輪方向(也等於車體方向)。
  4. 再把整台車沿新的方向拉,直到前輪中心被拉至正確的位置。
    四輪車演算法

我們用TypeScript來寫個示意程式碼,首先定義一下車子需要的屬性。

class Car {
    /** 車子的中心位置,用一個 Point 物件來表示。
     * Point是一個向量的類別,裏面除了x和y,還有一些向量的運算函式。
     * 今天我們只會用到以下兩個函式,往後的日子會有專門的文章解說向量。
     * - Point.add(other): 兩個向量相加
     * - Point.sub(other): 兩個向量相減
     */
    position = new Point();
    /** 車體的旋轉角度 */
    rotation = 0;
    /** 方向盤的角度,也就是前輪的旋轉角度 */
    steerAngle = 0;
    /** 兩個前輪中心相對於車子中心的相對位置 */
    headCenter = new Point(8, 0);
    /** 兩個後輪中心相對於車子中心的相對位置 */
    tailCenter = new Point(-10, 0);
    /** 車子速度 */
    speed = 1;
}
/** 新增一個車子的實體,方便等一下講解 */
let car = new Car();

Point是CG的基本模組提供的向量類別,原始碼在這兒,小哈往後幾日會再專門寫文章介紹向量各種運算的幾何意義。

接著假設我們把方向盤轉了一個角度,再套用四輪車演算法,來計算更新後車子的新位置與新角度。

/** 轉動方向盤,這邊設定的0.52單位是弧度,一般程式中都是使用弧度來計算
 * 180度大約等於3.14的弧度。
 */
car.steerAngle = 0.52;
/** 步驟(1)是要定義車體的結構,這個我們在定義Car時已經完成了 */

/** 步驟(2): 依方向盤角度以及車子速度移動前輪中心 */
// 首先找到前輪中心原本的絕對位置
let headCenterOld = car.position.add(car.headCenter);
// 用極座標算出前輪移動的向量
let moveVector = Point.polar(car.speed, car.steerAngle);
// 計算移動完成後前輪中心的位置
headCenterNew = headCenterOld.add(moveVector);

/** 步驟(3): 計算更新後的車體角度(也就是後輪角度) */
// 先找到後輪中心的絕對位置
let tailCenterOld = car.position.add(car.tailCenter);
// 將前後輪中心連成一個向量
let carVector = headCenterNew.sub(tailCenterOld);
// 計算後輪轉向新的前輪中心後的新角度
car.rotation = Math.atan2(carVector.y, carVector.x);

/** 步驟(4): 將車子拉向前輪新的位置 */
// 將前後輪連成的向量縮小至前輪中心離車子中心的距離
carVector.normalize(car.headCenter.length);
// 車體中心應該就等於新的前輪中心減去carVector
car.position = headCenterNew.sub(carVector);

如此一來,車子就被更新到新的位置和角度,持續用這個方法計算車子每一幀的位置和角度,就能真實地反應四輪車的運動軌跡。

大家可以前往CG看看實際用這個演算法製作出來的車子,開起來是什麼感覺。

四輪車CG專案


上一篇
Trick 1: 萬惡的摸彩箱
下一篇
Trick 3: 火焰傷害的頻率管理
系列文
30個遊戲程設的錦囊妙計32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
AndrewYEE
iT邦新手 3 級 ‧ 2023-07-13 20:29:50

原來是這樣,超讚!

我要留言

立即登入留言