眼見鐵人賽已經要接近尾聲,接下來幾天將邊實現射擊效果邊直接整合專案,而為了達成射擊遊戲的條件,首先就需要設定一個可以根據鼠標瞄準的第一人稱視角控制器,以下我們將使用 PointerLockControls 來實現。
PUBG Game Screenshot on DBLTAP
這是本系列第 21 篇,如果還沒看過第 20 篇可以點以下連結前往:
用 Three.js 來當個創世神 (20):Cannon.js 基本練習
原本還想多練習幾個 Cannon.js 的範例,但眼看時間快不夠了,只能硬著頭皮直接從 Hello world 跳到直接實戰第一人稱射擊遊戲的應用了。前面有說過,其實本系列當時定題目的初衷就是因為看到這個範例開始去延伸的:
但要怎麼寫呢?就這個射擊效果而言大概有以下幾個部分要完成:
實際拆解分析後,最不熟悉當屬第一點,而二跟三應該都是想好邏輯後交給 Cannon.js 處理就好,昨天 Hello world 有理解應該沒什麼問題。
於是目前的 roadmap 就是先從視角控制器的地方開始切入研究,並使用之前的苦力怕專案來做為背景;視角控制就緒後,再將場景內物體賦予物理剛體效果,最後再加上射擊子彈的事件,接下來幾天就直接開始邊學邊整合,準備替專案來個大收尾囉!Go!Go!Go!
在第一人稱類型的視角控制器上有許多種選擇,例如第一人稱視角控制器(FirstPersonControls)、飛行控制器(FlyControls)、鼠標鎖定視角控制器(PointerLockControls)等等,而在射擊遊戲中,因為需要透過鼠標位置來做瞄準射擊,所以採用 PointerLockControls
這個控制器會是比較好的選擇,以下我們將參考官網範例:
將 PointerLockControls
的效果套用至專案中。
後記:後來發現此控制器看起來是包裝原生的 Pointer Lock API。
利用第 16 篇的模板搭配官方 PointerLockControls 範例將視角控制器改為PointerLockControls
,並能使用鍵盤操控前後左右移動、跳躍及使用鼠標旋轉視角:
請參考完整原始碼及成果展示,另外筆者先暫時調整了掉出邊界後會下墜一段距離後重生,之後的遊戲場地會大更多,請各位看官先一起與苦力怕賞個雪,也可以開啟動畫玩個你追我跑。
關於今天的控制器套用相關程式內容在以下部分:
initPointerLockControls()
:處理初始化及滑鼠鍵盤事件監聽pointerLockControlsRender()
:處理任何移動與跳躍需更新視角的邏輯由於第二部分比較複雜,今天會先來看第一部分,PointerLockControls
以下簡稱鼠標控制器。
到官方 Github 下載 PointerLockControls.js
這個檔案(連結),並在適當的地方引入。
<script src="./lib/PointerLockControls.js"></script>
controls = new THREE.PointerLockControls(camera)
controls.getObject().position.set(10, 0, 60)
scene.add(controls.getObject())
鼠標控制器透過 getObject()
來提供一個玩家本身的實體,可以通過設定它的位置來操控視角位置,而在 Cannon.js 的範例中看起來還可以設定這個實體的形狀,後面再來做進階設定。
const blocker = document.getElementById('blocker')
const instructions = document.getElementById('instructions')
instructions.addEventListener(
'click',
function() {
controls.lock()
},
false
)
controls.addEventListener('lock', function() {
instructions.style.display = 'none'
blocker.style.display = 'none'
})
controls.addEventListener('unlock', function() {
blocker.style.display = 'block'
instructions.style.display = ''
})
因為鼠標控制器會取得使用者鼠標的控制權,所以需要通過使用者觸發才能使用,因此這邊需要卡一個進入畫面,滑鼠點擊使用控制器,按 Esc
退出控制器,
深入查看鼠標控制器的 lock()
及 unlock()
方法,其實就是在做 element.requestPointerLock 與 document.exitPointerLock。
const onKeyDown = function(event) {
switch (event.keyCode) {
case 38: // up
case 87: // w
moveForward = true
break
case 37: // left
case 65: // a
moveLeft = true
break
case 40: // down
case 83: // s
moveBackward = true
break
case 39: // right
case 68: // d
moveRight = true
break
case 32: // space
if (canJump === true) velocity.y += 350 // 跳躍高度
canJump = false
break
}
}
const onKeyUp = function(event) {
switch (event.keyCode) {
case 38: // up
case 87: // w
moveForward = false
break
case 37: // left
case 65: // a
moveLeft = false
break
case 40: // down
case 83: // s
moveBackward = false
break
case 39: // right
case 68: // d
moveRight = false
break
}
}
document.addEventListener('keydown', onKeyDown, false)
document.addEventListener('keyup', onKeyUp, false)
這邊監聽鍵盤按鍵來判斷目前要往什麼方向移動、是否有進行跳躍,利用四個方向與是否跳躍的旗標值,紀錄之後在 render()
中要做更新畫面時視角需移動與跳躍的判斷。
今天將 PointerLockControls
視角控制器引入專案中,讓遊戲有第一人稱視角的效果,今天先解析初始化的部分,因為畫面更新的設定牽涉到碰撞、重力、及速度的邏輯,稍微複雜一些,明天將繼續完成所有鼠標控制器的解析及優化,我們明天見!
大大加油!!
之後學three.js就靠這系列入門了!
感謝神Q超人大大的支持!期望自己能寫得夠淺顯易懂了,如果有哪裡看起來解釋得太模糊再留言提醒我,再回來修改的更好一些