在這學期我們寢室共同制作的2D游戲專案中,我仔細研究了2D游戲角色的操作邏輯,
在我們的專案中,Player 類是玩家類,這個類中的 move( ) 函式負責玩家移動,
玩家移動需要考慮四個方向:跳躍,向右移動、向左移動、重力,
另外,我們還要考慮碰撞,
1、move( ) 函式部分
我將 move( ) 函式分為三個部分:
- 左右移動
- 跳躍
- 重力作用下的向下移動
分別在move函式中呼叫這三個移動函式,角色就可以實作移動功能,
1.1、左右移動函式
左右移動是最簡單的部分,我是這樣實作的:
- 創建兩個臨時的變數 x‘、y’ ;將玩家坐標 x、y 保存,
- 進行判斷
- 如果同時按下 A、D 按鍵,不進行任何操作,
- 只按 A 不按 D ,如果玩家x坐標在視窗范圍內;更改玩家x坐標使其向左移動,
- 只按 D 不按 A ,如果玩家x坐標在視窗范圍內;更改玩家x坐標使其向右移動,
- 呼叫碰撞函式(后面會詳細說)檢測碰撞,如果碰撞就將玩家位置改為 x'、y‘,
1.2、跳躍函式
跳躍比較復雜,我經過思考后,決定使用狀態機的思想實作跳躍,
為Player類創建一個 int 變數表示跳躍狀態,Player的狀態有下面三種:
- 狀態0:處于物體上
如果玩家按下空格,游戲就要作出反應,將狀態切換為1 - 狀態1:跳躍上升中
此狀態說明玩家正在按下空格,
處于此狀態下時,如果檢測到玩家沒有按下空格,則立即將狀態切換成狀態2 - 狀態2:正在下落
此時重力部分正在起作用,
處于此狀態時,如果呼叫表面檢測函式檢測到Player正在處于物體上,就將狀態改為1,
下落時玩家按下空格不會有反應,不會跳躍,
跳躍函式需要計算按下空格時,每幀將Player向上移動多遠的距離,
但是跳躍一般是非線性的,
這意味著我們不能只知道兩幀之間的時間差 Δt,我們還需要知道玩家按下空格的時間 st,
st 只在狀態1中有用,且每次跳躍剛開始的時候都是0,因此我們需要在狀態切換的時候清空 st,
st 還能用來判斷按下空格時間是否達到最大跳躍時間,
這樣能夠避免一直按下空格一直向上運動,
在跳躍函式的開頭,我們要檢測并切換當前Player狀態,
- 當前狀態為0且按下空格:狀態變為1,清空 st,
- 當前狀態為1且沒有按下空格:狀態變為2,清空 st,
- 當前狀態為1且 st 已經達到了最大跳躍時間:狀態變為2,清空 st,
- 當前狀態為2且在物體上方表面:狀態變為0,清空 st,
隨后進行操作:
- 狀態0:處于物體上
- 無操作
- 狀態1:跳躍上升中
- 更新空格按下時長
st += Δt, - 創建兩個臨時的變數 x‘、y’ ;將玩家坐標 x、y 保存,
- 計算應當上升多少像素,
- 更改Player的 y 值,
- 呼叫碰撞函式檢測碰撞,如果碰撞就回傳x'、y'的位置,
- 更新空格按下時長
- 狀態2:正在下落
- 無操作
1.3、重力函式
重力部分比較簡單,
- 創建兩個臨時的變數 x‘、y’ ;將玩家坐標 x、y 保存,
- 檢查跳躍狀態:
- 如果處于上升狀態就直接
return, - 如果不處于上升狀態,更改 Player 的 y 坐標使其向下移動,
- 如果處于上升狀態就直接
- 呼叫碰撞函式(后面會詳細說)檢測碰撞,如果碰撞就將玩家位置改為 x'、y‘,
考慮到一個問題,如果有這樣的情況:
如果每幀重力令 Player 下降2個像素,而 Player 現在正處于物體的一個像素上方;
這樣每幀呼叫碰撞函式都會檢測到碰撞,那么 Player 就會永遠懸空物體一個像素,解決方法我想到兩個:
- 更改邏輯,使得碰撞函式能夠檢測重疊距離,如果發生重疊可以只移動重疊距離即可,不需要回到原來位置,
- (代碼量少但是效率低)當重力函式檢測到碰撞的時候,嘗試將物體向下移動一個像素,再檢測碰撞,
2、碰撞
一個函式負責檢測碰撞(即 Player 與其他物體是否有重疊),
另外還有一個函式負責檢測 Player 是否在物體表面,
下面的函式負責檢測兩個 GameObject 之間是否有碰撞:
bool CheckCollision(GameObject& one, GameObject& two)
// 碰撞檢測
{
// collision x-axis?
bool collisionX = one.Position.x + one.Size.x >= two.Position.x &&
two.Position.x + two.Size.x >= one.Position.x;
// collision y-axis?
bool collisionY = one.Position.y + one.Size.y >= two.Position.y &&
two.Position.y + two.Size.y >= one.Position.y;
// collision only if on both axes
return collisionX && collisionY;
}
由于本專案中,Player類與其他物體都是GameObject類的子類,
因此寫一個函式,令Player與其他所有的物體(例如磚塊等)檢測一遍碰撞即可,
3、總結
最終我們決定角色可以無限上升(體現幽靈飄的特性),而不是開始的時候設想的類似馬里奧的跳躍感覺,
所以我最初寫的跳躍邏輯沒有了用武之地,不過好在最后游戲的呈現效果不錯,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/532590.html
標籤:其他
