簡介
Pointer Lock API 可協助在瀏覽器遊戲中妥善實作第一人稱射擊遊戲。例如,如果沒有相對的滑鼠移動,玩家的遊標可能會直接移動至畫面右側邊緣,而繼續往右移動的幅度沒有折扣,因為畫面無法繼續向右平移,而玩家也無法追上壞人,陷入他們的機器槍戰。玩家會陷入困境並造成挫折。使用指標鎖定時,無法達到這種不理想的行為。
Pointer Lock API 可讓應用程式執行下列操作:
- 取得原始滑鼠資料 (包括相對滑鼠移動)
- 將所有滑鼠事件轉送至特定元素
滑鼠遊標鎖定是啟用指標鎖定的副作用,讓您可以選擇是否繪製特定的應用程式指標,或保持隱藏滑鼠遊標,讓使用者可用滑鼠移動頁框。相對滑鼠移動是指滑鼠指標位置與前一個影格的位置差異 (無論絕對位置為何)。例如,如果滑鼠遊標從 (640, 480) 移動到 (520, 490),相對移動動作是 (-120, 10)。請見下方互動式範例,瞭解原始滑鼠位置差異值。
本教學課程涵蓋兩個主題:啟用和處理指標鎖定事件的注意事項,以及如何實施第一人稱射擊控制機制。沒錯,閱讀完本文後,您將瞭解如何使用指標鎖定,以及為自己的瀏覽器遊戲實作 Quake 樣式的控制項!
瀏覽器相容性
指標鎖定機制
特徵偵測
如要判斷使用者的瀏覽器是否支援指標鎖定,您需要檢查文件物件中是否有 pointerLockElement
或廠商前置字串的版本。在程式碼中:
var havePointerLock = 'pointerLockElement' in document ||
'mozPointerLockElement' in document ||
'webkitPointerLockElement' in document;
遊標鎖定功能目前僅適用於 Firefox 和 Chrome。Opera 和 IE 目前尚不支援。
啟用中
啟用指標鎖定程序包含兩個步驟。首先,應用程式要求特定元素啟用指標鎖定,然後在使用者授予權限後立即觸發 pointerlockchange
事件。使用者隨時可以按下 Esc 鍵取消指標鎖定。應用程式也可以明顯結束指標鎖定。取消指標鎖定時,系統會觸發 pointerlockchange
事件。
element.requestPointerLock = element.requestPointerLock ||
element.mozRequestPointerLock ||
element.webkitRequestPointerLock;
// Ask the browser to lock the pointer
element.requestPointerLock();
// Ask the browser to release the pointer
document.exitPointerLock = document.exitPointerLock ||
document.mozExitPointerLock ||
document.webkitExitPointerLock;
document.exitPointerLock();
上述程式碼全都沒問題。瀏覽器鎖定指標時,系統會彈出說明圖示,讓使用者知道應用程式已鎖定指標,並指示使用者按下 Esc 鍵可取消該指標鍵。
事件處理
應用程式有兩個事件必須新增事件監聽器。第一項是 pointerlockchange
,每當指標鎖定狀態發生變更時就會觸發。第二個是 mousemove
,每當滑鼠移動時觸發。
// Hook pointer lock state change events
document.addEventListener('pointerlockchange', changeCallback, false);
document.addEventListener('mozpointerlockchange', changeCallback, false);
document.addEventListener('webkitpointerlockchange', changeCallback, false);
// Hook mouse move events
document.addEventListener("mousemove", this.moveCallback, false);
在 pointerlockchange
回呼中,您必須檢查指標是否已鎖定或解鎖。判斷指標鎖定是否已啟用非常簡單:檢查 document.pointerLockElement 是否等於要求指標鎖定的元素。如果是,表示您的應用程式已成功鎖定指標;如果不是,表示使用者或您的程式碼已解鎖指標。
if (document.pointerLockElement === requestedElement ||
document.mozPointerLockElement === requestedElement ||
document.webkitPointerLockElement === requestedElement) {
// Pointer was just locked
// Enable the mousemove listener
document.addEventListener("mousemove", this.moveCallback, false);
} else {
// Pointer was just unlocked
// Disable the mousemove listener
document.removeEventListener("mousemove", this.moveCallback, false);
this.unlockHook(this.element);
}
啟用指標鎖定時,clientX
、clientY
、screenX
和 screenY
都會維持不變。movementX
和 movementY
均更新為指標在上次提供事件後移動的像素數量。在虛擬程式碼中:
event.movementX = currentCursorPositionX - previousCursorPositionX;
event.movementY = currentCursorPositionY - previousCursorPositionY;
在 mousemove
回呼中,相對滑鼠動作資料可以從事件的 movementX
和 movementY
欄位擷取。
function moveCallback(e) {
var movementX = e.movementX ||
e.mozMovementX ||
e.webkitMovementX ||
0,
movementY = e.movementY ||
e.mozMovementY ||
e.webkitMovementY ||
0;
}
擷取錯誤
如果輸入或離開指標引發錯誤,會觸發 pointerlockerror
事件。這個活動未附加任何資料。
document.addEventListener('pointerlockerror', errorCallback, false);
document.addEventListener('mozpointerlockerror', errorCallback, false);
document.addEventListener('webkitpointerlockerror', errorCallback, false);
需要全螢幕嗎?
最初的指標鎖定功能和 FullScreen API 相連結。表示元素必須先進入全螢幕模式,才能鎖定該元素。這點不再是 True,而且應用程式中的任何元素都可使用指標鎖定 (不論是否以全螢幕顯示)。
第一人稱射擊控制項範例
現在,我們已啟用指標鎖定並接收事件,接著要參考實際範例。你是否想知道 Quake 的控制項如何運作?我正要透過程式碼說明他們吧!
第一人稱射擊遊戲的控制機制圍繞著四種核心機制:
- 在目前的外觀向量上前後移動
- 沿著目前的平流向量左右移動
- 旋轉視角 (左右)
- 旋轉視角 (向上和向下)
實作這個控製配置的遊戲只需要三種資料:相機位置、相機外觀向量和不斷上升的向量。上向量一律為 (0、1、0)。上述四項機制都是以不同的方式操控相機位置和相機外觀向量。
活動
第一是活動在下面的示範中,我們對應到標準的 W、A、S 和 D 按鍵。W 和 S 鍵可向前和向後推動相機。A 和 D 鍵可向左和向右移動攝影機。前後移動攝影機的方式非常簡單:
// Forward direction
var forwardDirection = vec3.create(cameraLookVector);
// Speed
var forwardSpeed = dt * cameraSpeed;
// Forward or backward depending on keys held
var forwardScale = 0.0;
forwardScale += keyState.W ? 1.0 : 0.0;
forwardScale -= keyState.S ? 1.0 : 0.0;
// Scale movement
vec3.scale(forwardDirection, forwardScale * forwardSpeed);
// Add scaled movement to camera position
vec3.add(cameraPosition, forwardDirection);
往左和右往左或往右移動需要小數點。可使用交叉乘積計算高度方向:
// Strafe direction
var strafeDirection = vec3.create();
vec3.cross(cameraLookVector, cameraUpVector, strafeDirection);
取得簡易方向後,實施輕微移動與向前或向後移動的效果相同。
接下來是旋轉視圖。
Yaw
相機檢視畫面的偏轉或水平旋轉,只會以固定向量為中心旋轉。下方是沿著任意軸旋轉相機外觀向量的一般程式碼。方法是建構代表 axis
周圍 deltaAngle
弧度的「四元組」,然後使用四元數旋轉相機外觀向量:
// Extract camera look vector
var frontDirection = vec3.create();
vec3.subtract(this.lookAtPoint, this.eyePoint, frontDirection);
vec3.normalize(frontDirection);
var q = quat4.create();
// Construct quaternion
quat4.fromAngleAxis(deltaAngle, axis, q);
// Rotate camera look vector
quat4.multiplyVec3(q, frontDirection);
// Update camera look vector
this.lookAtPoint = vec3.create(this.eyePoint);
vec3.add(this.lookAtPoint, frontDirection);
音調
為相機視角的垂直傾斜或垂直旋轉的做法與此相似,但並沒有針對上向量旋轉。第一步是計算特張向量,然後沿著該軸旋轉相機的視覺向量。
摘要
Pointer Lock API 可讓您控制滑鼠遊標。如果您要製作網頁遊戲,玩家會愛上遊戲,因為他們久未將滑鼠移到視窗外,遊戲也停止接收滑鼠更新。使用方式很簡單:
- 新增
pointerlockchange
事件監聽器,用於追蹤指標鎖定狀態 - 特定元素的要求指標鎖定
- 新增
mousemove
事件監聽器以取得更新資訊