用 2D 物理引擎 Matterjs 製作經典馬力歐 1-1
tags: JavaScript
, Matterjs
, Mario
嗨~大家好,我是 Johnny,最近台灣本土疫情稍為刺激,週末待在家閒著無聊,剛好前陣子學了一款 2D 物理引擎Matterjs 想說來試著用它做點東西。(其實是公司內居然提問可不可能製作一款類似馬力歐遊戲的需求,雖然快被嚇死,內心卻備受衝擊想著:靠北!我做不出來!!趕緊來試著做看看)
今天這篇是一個實作紀錄,主要紀錄如何使用 Matterjs 製作一個橫向捲軸式遊戲~
因為馬力歐算是這種遊戲的經典款,網路上相關資源也蠻多,就決定是馬力歐拉,礙於篇幅會過長,本篇只會聚焦在開發想法上面喔
製作完的成品在這,歡迎前往玩看看喔~
技術選擇
首先要製作一個 2D 網頁遊戲最重要的就是技術選擇,因為這次是以練習 Matterjs 及原生手做能力為主,所以沒有過多的考慮,平常如果要開發遊戲的話,可以選擇像是 Phaserjs 這種遊戲框架會方便很多~
前置思考
製作前需要先確定一下哪先部分可以交給 Matterjs,哪些部分需要我們自己手動完成
Matterjs 代勞
- 物件渲染(Body)
- 物理特性(位置、速度、重力、碰撞)
手動
- 動畫渲染(Animation)
- 流程、機制控制(Trigger)
- 操控事件(Controller)
- 素材載入(Loader)
- 音效處理(Howler)
實作過程
實作過程中主要碰到了以下幾個困難
素材在多個地方分開載入
這個問題其實就是製作一個素材 Loader,統一在一個地方載入素材後,其他地方只需要調用這個 Loader 返回的結果就行了
const loader = new Loader();
loader.add('mario', '/cdn/mario.png');
(async () => {
// 等待素材載入(Promise.all)
await loader.load();
// 開始遊戲
startGame();
})();
創建動畫
Matterjs 主要只負責物理特性部分,動畫部分可以透過抽象將邏輯拆出去,由外部注入函數來創建動畫對象,並且添加 Matterjs 的 render events "afterRender" 內進行渲染
Events.on(render, 'afterRender', () => {
// ... dome some animation
});
同一物件多種動畫
這個可以透過在物件中添加 status 來控制,每當切換狀態時執行不同的動畫即可
同類型物件歸類
物件之間彼此或多或少都會有關聯,比如蘑菇、烏龜都是「敵人」,此時可以創建 Matterjs 的 group 來分類,這樣在後續判定 Collision 碰撞時可以提升效率,否則每個物件都必須寫一次碰撞就比較繁瑣了
橫向捲軸跟隨
橫向捲軸有兩種,一種是 loop 類型也就是 Camera 固定,背景持續重複,而馬力歐屬於第二類,背景為長條狀,Camera 跟隨人物移動,製作上可以添加 bounds 邊界概念,而使用 Matterjs 則可以用 Bounds 內建模組將 render.bounds 進行移動來達成
function checkBounds() {
const { position, velocity: vel } = this.body;
const { min, max } = render.bounds;
if (vel.x < 0 && min.x < 0) {
// no move
} else if (vel.x > 0 && max.x > config.mapWidth) {
// no move
} else if (position.x > min.x+config.width * 1 / 2 && vel.x > 0) {
Bounds.translate(render.bounds, {
x: vel.x,
y: 0,
});
} else if (position.x < min.x+config.width * 1 / 2 && vel.x < 0) {
Bounds.translate(render.bounds, {
x: vel.x,
y: 0,
});
}
}
結論
必須說,真的是術業有專攻,製作遊戲真的是異常辛苦,希望大家平日玩遊戲遇到 bug 時都能冷靜一點哈哈哈,因為真的是非常非常辛苦,製作難免會有一些缺漏或不完美,透過親身製作一次真的可以體會...
今天就介紹到這拉~感謝大家觀看 =V=!!
源碼放在這,有興趣的朋友可以參觀看看摟,對於遊戲我認為寫的還有待加強,請大佬見諒哈哈