昨天,介紹完與滑鼠、觸控相關的輸入互動後,今天就要來介紹怎麼在 CG 上偵測玩家的鍵盤輸入啦~
首先,PixiJS 做為一個 2D 繪圖引擎,並不包含偵測鍵盤輸入的功能,所以正常情況下我們必須依賴瀏覽器本身的 API 來偵測鍵盤輸入。但好家在這裡是 Code.Gamelet,CG 已經幫我們把這件事情簡化了,並且結合了我們昨天介紹過的 EventEmitter
,使鍵盤的偵測方式變得和滑鼠的偵測方式相似,統一的結構在程式碼的閱覽上也會更加易讀。
Keyboard
類別Keyboard
是 CG 的核心模組 Base2 內建的類別,在開發時,我們不需要自己創建它,因為 Base2 已經幫我們把它創建好,並儲存在 keyboard
這個全域常數裡面了,我們只要從 Base2 拿出來就可以開始使用裡面的功能。
Keyboard
提供了兩個核心功能:
on()
和 off()
函數來監聽按鍵事件,這和昨天的滑鼠、觸控事件非常相似。import keyboard = CG.Base2.keyboard;
import Keyboard = CG.Base2.keyboards.Keyboard;
import KeyCode = CG.Base2.keyboards.KeyCode;
import Key = CG.Base2.keyboards.Key;
在使用 Keyboard
的時候,原則上最頂層都會有這幾個 import
,沒意外的話,在我們使用Keyboard
時,CG 就會自動幫我們把這幾行寫好了,因此這邊只是稍微提一下,待會會個別介紹它們。
但如果 CG 真的沒有幫你寫好,你可以對著你使用的物件、類別按下滑鼠右鍵打開選單,選擇「CG自動導入」即可。
監聽按鍵事件
首先,讓我們用最簡單的方式來監聽按鍵被按下的事件:
import pixi = CG.Pixi.pixi;
import keyboard = CG.Base2.keyboard;
import Keyboard = CG.Base2.keyboards.Keyboard;
import KeyCode = CG.Base2.keyboards.KeyCode;
async function start() {
// 初始化 Pixi
await pixi.initialize({ stageWidth: 960, stageHeight: 540 });
// 建立文字物件
const text = new PIXI.Text({
text: "試著按點什麼",
style: { fill: 0xFFFFFF, fontSize: 100, align: "center" },
anchor: 0.5,
position: { x: pixi.stageWidth * 0.5, y: pixi.stageHeight * 0.5 }
} as PIXI.TextOptions);
// 將文字物件加入舞台
pixi.root.addChild(text);
// 監聽鍵盤事件
keyboard.on(Keyboard.EVENT.PRESSED, (key: KeyCode, event: KeyboardEvent) => {
text.text = `按下了 ${event.code}`;
});
}
start();
這段程式碼使用 keyboard.on()
來監聽 Keyboard.EVENT.PRESSED
這個事件。當任何按鍵被按下時,它就會觸發函數,並將按鍵的相關資訊傳遞給我們,讓我們可以根據 event.code
顯示按下的鍵名。
你也可以用 switch
語法來處理不同的按鍵,例如:
// 在 keyboard.on() 內添加,其他保持不變...
switch (key) {
case Key.Z:
text.text += "\\n發射了導向飛彈";
break;
case Key.X:
text.text += "\\n埋了高性能地雷";
break;
case Key.C:
text.text += "\\n發射了迫擊砲";
break;
case Key.V:
text.text += "\\n發射了雷射砲";
break;
}
值得注意的是,keyboard.on()
會丟出兩個參數:key
和 event
。
key
是一個 KeyCode
物件,這是由 Base2 預先定義好的標準按鍵代碼,它提供了一個簡潔、統一的方式來代表按鍵(例如 Key.Z
)。event
則是瀏覽器原生的 KeyboardEvent
物件,它包含了更底層的資訊,例如 event.code
(按鍵在鍵盤上的物理位置代碼)。通常在遊戲實作上,我們只會需要用到 key
,但若你有其他更複雜的需求,就可以自己利用 event
來處理。偵測按鍵狀態:isDown()
事件監聽器對於一次性的按鍵事件(例如發射子彈)非常有用。但是,如果你想讓角色在玩家按住按鍵時持續移動,單靠 on()
事件就不夠了。
這時,我們需要使用 keyboard.isDown()
這個函數。它會回傳一個布林值(true
或 false
),告訴我們某個按鍵是否處於被按下的狀態。
// 在 start() 內添加,其他保持不變...
// 定義移動速度
const moveSpeed = 5;
// 設置一個循環更新函數
CG.Base2.addUpdateFunction(() => {
// 根據指定按鍵的狀態,改變 text 的座標位置
if (keyboard.isDown(Key.W)) text.y -= moveSpeed; // 向上移動
if (keyboard.isDown(Key.S)) text.y += moveSpeed; // 向下移動
if (keyboard.isDown(Key.A)) text.x -= moveSpeed; // 向左移動
if (keyboard.isDown(Key.D)) text.x += moveSpeed; // 向右移動
});
這裡我們使用了 CG.Base2.addUpdateFunction
,它會讓程式碼在每一幀(Frame)都被執行。當我們在其中檢查 keyboard.isDown()
的狀態時,只要指定的按鍵被按住,程式碼就會在每一幀持續執行,從而實現了平滑、持續的移動。
今天我們介紹了如何在 CG 上處理鍵盤輸入:
keyboard.on()
來監聽一次性的按鍵事件,適合處理發射技能或切換裝備等單次動作。keyboard.isDown()
來偵測按鍵的即時狀態,並搭配遊戲的更新函數,實現玩家角色持續性的移動等遊戲邏輯。這兩種方式各有用途,而 isDown()
與循環更新的結合,正是所有遊戲實現即時控制的關鍵。
明天,我們將會更深入的介紹 CG.Base2.addUpdateFunction
這個東西,雖然之前在 Day 04 介紹了它會不斷執行的功能,但還有許多細節沒有提到,像是不同設備之間的畫面更新率(FPS)不同,更新的頻率不同,該如何同步之類的,不過這些就等到明天再說吧!