遊戲建模之碰撞時間

遊戲建模之碰撞時間

『物體』運動核心是碰撞.你試想下當『物體』高速運動時有可能會穿越牆壁.這因遊戲世界中CPU會輪詢處理所有『物體』. 並只會分到有限『運算/時間』,所以每一次你都需要準確計算碰撞時間.通過不斷遞歸而確定最後移動位置

通過使用基於時間二維方程式進行碰撞檢測.

xf=x0+v0t+(1/2)at2

ax2+bx+c=0

利用係數替換可得到

a=(1/2)*a

b=v0

c=x0-xf

將其擴展可得到三維方程式

xt=cx+bxt+axt2

yt=cy+byt+ayt2

zt=cz+bzt+azt2

如果將三維方程應用於平面方程可得

Axt+Byt+C*zt+D=0

此方程說面如果物體與平面發生碰撞.其碰撞點位於(xt,yt,zt)通過代數運算可得到

(Aax+Bay+Caz)x2+(Abx+Bby+Cbz)x+(Acx+Bcy+Ccz)+D=0

這其實就是平面二次方程式(ax2+bx+c=0) ,其點積形式為:

ax2=(Aax+Bay+Caz)x2=N•(1/2)A

利用點積得到二次方程係數:

加速度係數: a=N•(0.5A)

速度係數:  b=N•V

距離係數:  c=N•X+D

有上序二次方程係數就可計算碰撞時間

float a = n % (acceleration * 0.5f);// 加速度係數

float b = n % velocity;// 速度係數

float c = n % position + D – radius;// 距離係數

若a=0加速度係數為零,碰撞時間等於距離係數除以速度係數.因為距離係數小於零所以要去負值.

collisionTime = -c/b;

若a!=≠0加速度係數不為零,可以使用二次方程計算碰撞時間:

x=(-b+√(b2-4ac) ) / 2a

在計算碰撞時間之前可先計算D=b2-4ac 若D小於零則無解.若D大於零則有解

float D = b * b – 4 * a*c;

if (D > 0) // 如果判斷式大於等於零

collisionTime = (-b – sqrtf(D)) / (2 * a); // 計算碰撞時間

因為發生碰撞物體會彈開,方向矢量產生返射需要重新計算位置.通過減去碰撞時間進行遞歸.直到『幀時間』為零

 

下面是『曲棍球』碰撞函式.

puck 是曲棍球.

table 是球臺

deltaTime是幀時間

void Update_Puck(PUCK_PTR puck, TABLE_PTR table, float deltaTime){

float  fastestTime = deltaTime;// 最早碰撞時間

float  collisionTime;// 碰撞時間

PLANE3D_PTR plane          = NULL;// 平面

PLANE3D_PTR planeCollision = NULL;// 碰撞平面

if (deltaTime <= 0.000f)// 遞歸

return;

// 對球臺四個圍邊檢查碰撞

for (int i = 0; i < 4; i++){

plane = &table->wall[i];// 平面

// 點積二次方程

float a = plane->n % (puck->acceleration * 0.5f);// 加速度係數

float b = plane->n % puck->velocity;// 速度係數

float c = plane->n % puck->position + plane->D – puck->radius;// 距離係數

if (a == 0 && b != 0 && c != 0){// 如果無加速度

// 碰撞時間等於距離除以速度

collisionTime = -c/b;// 碰撞時間

if (collisionTime >= 0 && collisionTime < fastestTime){// 發生碰撞

fastestTime = collisionTime;// 保存碰撞時間

planeCollision = plane;// 平面

}

}

else

if(a != 0){

// 加速度a不等於零

// 計算判別式

float D = b * b – 4 * a*c;

if (D > 0) {// 如果判斷式大於等於零

// 計算碰撞時間

collisionTime = (-b – sqrtf(D)) / (2 * a);

if (collisionTime >= 0.0f && collisionTime < fastestTime) {// 發生碰撞

fastestTime = collisionTime;

planeCollision = plane;

}

}

}

}// END FOR

// 速度設上限每秒800米

if (Length_VECTOR3D(&puck->velocity) > 800)

puck->velocity = Normalize_VECTOR3D(&puck->velocity) * 800;

// 如果冰球正移動,則應用磨擦力

if (Length_VECTOR3D(&puck->velocity) > 0)

puck->acceleration = -puck->velocity * 0.2f;// 計算加速度

// 計算當前位置

puck->position = puck->position + puck->velocity * fastestTime + puck->acceleration * (fastestTimefastestTime0.5f);

// 應用磨擦力

puck->velocity = puck->velocity + puck->acceleration * fastestTime;

// 如果發生碰撞,反轉速度

if (planeCollision != NULL)// 碰撞平面

puck->velocity = Reflection_VECTOR3D(&puck->velocity, &planeCollision->n);

// 遞歸調用

Update_Puck(puck, table, deltaTime – fastestTime);

}

評論