iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 22
1
Modern Web

用 Three.js 來當個創世神系列 第 22

用 Three.js 來當個創世神 (21):專案實作#10 - 使用 PointerLockControls 實現射擊遊戲視角 Part.1

眼見鐵人賽已經要接近尾聲,接下來幾天將邊實現射擊效果邊直接整合專案,而為了達成射擊遊戲的條件,首先就需要設定一個可以根據鼠標瞄準的第一人稱視角控制器,以下我們將使用 PointerLockControls 來實現。

pubg

PUBG Game Screenshot on DBLTAP


這是本系列第 21 篇,如果還沒看過第 20 篇可以點以下連結前往:

用 Three.js 來當個創世神 (20):Cannon.js 基本練習


專案分析

原本還想多練習幾個 Cannon.js 的範例,但眼看時間快不夠了,只能硬著頭皮直接從 Hello world 跳到直接實戰第一人稱射擊遊戲的應用了。前面有說過,其實本系列當時定題目的初衷就是因為看到這個範例開始去延伸的:

cannon

但要怎麼寫呢?就這個射擊效果而言大概有以下幾個部分要完成:

  1. 第一人稱視角控制器(前後左右與跳躍)
  2. 準備物理世界中的剛體效果
  3. 點擊滑鼠射出子彈

實際拆解分析後,最不熟悉當屬第一點,而二跟三應該都是想好邏輯後交給 Cannon.js 處理就好,昨天 Hello world 有理解應該沒什麼問題。

於是目前的 roadmap 就是先從視角控制器的地方開始切入研究,並使用之前的苦力怕專案來做為背景;視角控制就緒後,再將場景內物體賦予物理剛體效果,最後再加上射擊子彈的事件,接下來幾天就直接開始邊學邊整合,準備替專案來個大收尾囉!Go!Go!Go!

 

PointerLockControls

在第一人稱類型的視角控制器上有許多種選擇,例如第一人稱視角控制器(FirstPersonControls)飛行控制器(FlyControls)鼠標鎖定視角控制器(PointerLockControls)等等,而在射擊遊戲中,因為需要透過鼠標位置來做瞄準射擊,所以採用 PointerLockControls 這個控制器會是比較好的選擇,以下我們將參考官網範例

pointer

PointerLockControls 的效果套用至專案中。

後記:後來發現此控制器看起來是包裝原生的 Pointer Lock API

 

今日目標

利用第 16 篇的模板搭配官方 PointerLockControls 範例將視角控制器改為PointerLockControls,並能使用鍵盤操控前後左右移動、跳躍及使用鼠標旋轉視角:

21_demo

請參考完整原始碼成果展示,另外筆者先暫時調整了掉出邊界後會下墜一段距離後重生,之後的遊戲場地會大更多,請各位看官先一起與苦力怕賞個雪,也可以開啟動畫玩個你追我跑。

 

程式解析

關於今天的控制器套用相關程式內容在以下部分:

  1. initPointerLockControls():處理初始化及滑鼠鍵盤事件監聽
  2. pointerLockControlsRender():處理任何移動與跳躍需更新視角的邏輯

由於第二部分比較複雜,今天會先來看第一部分,PointerLockControls 以下簡稱鼠標控制器。

1. 載入鼠標控制器函式庫

到官方 Github 下載 PointerLockControls.js 這個檔案(連結),並在適當的地方引入。

<script src="./lib/PointerLockControls.js"></script>

2. 初始化鼠標控制器

controls = new THREE.PointerLockControls(camera)
controls.getObject().position.set(10, 0, 60)
scene.add(controls.getObject())

鼠標控制器透過 getObject() 來提供一個玩家本身的實體,可以通過設定它的位置來操控視角位置,而在 Cannon.js 的範例中看起來還可以設定這個實體的形狀,後面再來做進階設定。

3. 使用者觸發使用鼠標控制器

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.requestPointerLockdocument.exitPointerLock

4. 偵測鍵盤事件移動方向與跳躍

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 來當個創世神 (20):Cannon.js 基本練習
下一篇
用 Three.js 來當個創世神 (22):專案實作#11 - 使用 PointerLockControls 實現射擊遊戲視角 Part.2
系列文
用 Three.js 來當個創世神31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

1
神Q超人
iT邦研究生 5 級 ‧ 2018-11-06 21:21:13

大大加油!!
之後學three.js就靠這系列入門了!

ckchuang iT邦新手 4 級 ‧ 2018-11-06 21:51:20 檢舉

感謝神Q超人大大的支持!期望自己能寫得夠淺顯易懂了,如果有哪裡看起來解釋得太模糊再留言提醒我,再回來修改的更好一些/images/emoticon/emoticon41.gif

我要留言

立即登入留言