Greetings~ 這裡是鐵匠史密斯!
昨日確定了角色橫移、旋轉矩陣的功能
接下來就是碰撞檢測的部分了
還記得我們目前的功能嗎?
當玩家超出界線外,會看到無盡的牆壁
// Check if ray is out of bounds
if ((nTestX < 0) || (nTestX >= nMapWidth) || (nTestY < 0) || (nTestY >= nMapHeight))
{
bHitWall = true; // Out of bounds, we hit the wall
fDistanceToWall = fDepth; // Set distance to the maximum depth
}
else // If ray is still in bounds
{
if (map[nTestY * nMapWidth + nTestX] == '#') // If we hit a wall
{
bHitWall = true;
}
}
現在,我們要避免玩家超出界線外
map
來決定當我們進行移動( W
/ S
/ A
/ D
)時,fPlayerX
以及 fPlayerY
都會隨時記錄著我們的位置
玩家當下的位置,想必也會與世界地圖 map
同步,
我們可以藉由玩家在地圖 map
的當前位置,查看是否為 #
(牆壁)
如果:
我們可以判定玩家在前進一步時在 map
地圖上的位置是否為牆壁 #
來決定玩家前進的這一步是否有效~
if (GetAsyncKeyState((unsigned short)'W') & 0x8000)
{
fPlayerX += sinf(fPlayerA) * fElaspedTime * 5;
fPlayerY += cosf(fPlayerA) * fElaspedTime * 5;
if (map[(int)fPlayerY * nMapWidth + (int)fPlayerX] == '#')
{
fPlayerX -= sinf(fPlayerA) * fElaspedTime * 5;
fPlayerY -= cosf(fPlayerA) * fElaspedTime * 5;
}
}
if (GetAsyncKeyState((unsigned short)'S') & 0x8000)
{
fPlayerX -= sinf(fPlayerA) * fElaspedTime * 5;
fPlayerY -= cosf(fPlayerA) * fElaspedTime * 5;
if (map[(int)fPlayerY * nMapWidth + (int)fPlayerX] == '#')
{
fPlayerX += sinf(fPlayerA) * fElaspedTime * 5;
fPlayerY += cosf(fPlayerA) * fElaspedTime * 5;
}
}
// Move Left&Right in the map
if (GetAsyncKeyState((unsigned short)'A') & 0x8000)
{
fPlayerX += cosf(fPlayerA) * fElaspedTime * 5;
fPlayerY -= sinf(fPlayerA) * fElaspedTime * 5;
if (map[(int)fPlayerY * nMapWidth + (int)fPlayerX] == '#')
{
fPlayerX -= cosf(fPlayerA) * fElaspedTime * 5;
fPlayerY += sinf(fPlayerA) * fElaspedTime * 5;
}
}
if (GetAsyncKeyState((unsigned short)'D') & 0x8000)
{
fPlayerX -= cosf(fPlayerA) * fElaspedTime * 5;
fPlayerY += sinf(fPlayerA) * fElaspedTime * 5;
if (map[(int)fPlayerY * nMapWidth + (int)fPlayerX] == '#')
{
fPlayerX += cosf(fPlayerA) * fElaspedTime * 5;
fPlayerY -= sinf(fPlayerA) * fElaspedTime * 5;
}
}
p.s. 記得,map
是 1-D wstring
array -> 使用 index (int
) 提取矩陣的值。
在移動的功能( W
/ S
/ A
/ D
) 增加判定式,就可以進行碰撞偵測了~
原本光線檢測時,只處理了「超出界線 → 畫無盡牆壁」的情況
為了避免玩家衝出地圖,我們在( W
/ S
/ A
/ D
) 的移動程式碼中加上了「先移動 → 判斷是否撞牆 → 撞牆就退回」的邏輯
藉由 map[(int)fPlayerY * nMapWidth + (int)fPlayerX]
來判斷玩家當前位置是否為 '#'
牆壁,實現了 簡單的碰撞偵測
現在,我們有了方向旋轉、前後左右移動、牆壁與地板渲染、碰撞偵測 ——
基本上,已經是一個完整的第一人稱小遊戲引擎了。
明天就是 Day30 最終回,我會做一個完整的總結,回顧這一路的推導、程式碼與學到的觀念,
也會講講接下來繼續這一系列文章的下一步。
鐵人賽 30 天的旅程,終於要走到終點了。
最後一哩路,我們繼續走下去!