iT邦幫忙

2022 iThome 鐵人賽

DAY 21
0
Modern Web

派對動物嗨起來!系列 第 21

D21 - 大海、浮冰、企鵝勒?:使用 babylon.js 打造 3D 遊戲

  • 分享至 

  • xImage
  •  

本系列文已改編成書「甚麼?網頁也可以做派對遊戲?使用 Vue 和 babylon.js 打造 3D 派對遊戲吧!」

書中不只重構了程式架構、改善了介面設計,還新增了 2 個新遊戲呦!ˋ( ° ▽、° )

新遊戲分別使用了陀螺儀與震動回饋,趕快買書來研究研究吧!ლ(╹∀╹ლ)

在此感謝深智數位的協助,歡迎大家前往購書,鱈魚感謝大家 (。・∀・)。

助教:「所以到底差在哪啊?沒圖沒真相,被你坑了都不知道。(´。_。`)」

鱈魚:「你對我是不是有甚麼很深的偏見啊 (っ °Д °;)っ,來人啊,上連結!」

Yes


讓我們利用 babylon.js 打造 3D 遊戲吧!◝( •ω• )◟

babylon.js 產生遊戲畫面需要以下幾個步驟。

  1. 取得 canvas DOM
  2. 建立 Engine
  3. 建立 Scene
  4. 建立至少一個光源
  5. 建立至少一個 camera

這樣才能產生一個看的到的畫面。

讓我們引入 babylon.js 並依序新增建立場景所需的 function 吧。

import { ArcRotateCamera, Engine, Scene, Vector3 } from '@babylonjs/core';
...
const canvas = ref<HTMLCanvasElement>();
let engine: Engine;
let scene: Scene;

function createEngine(canvas: HTMLCanvasElement) {
  const engine = new Engine(canvas, true);
  return engine;
}
function createScene(engine: Engine) {
  const scene = new Scene(engine);
  /** 使用預設光源 */
  scene.createDefaultLight();
  return scene;
}
function createCamera(scene: Scene) {
  const camera = new ArcRotateCamera(
    'camera',
    -Math.PI / 2,
    Math.PI / 4,
    34,
    new Vector3(0, 0, -2),
    scene
  );

  return camera;
}
  • 建立引擎基本上就是傳入 canvas DOM 與開啟反鋸齒,沒有其他特別參數。
  • 場景這裡力求簡單,我們直接使用預設光源
  • 相機部分,由於不會移動鏡頭,所以使用最簡單的 ArcRotateCamera

參考資料:

接著增加 init() 內容,開始建立場景。

function init() {
  if (!canvas.value) {
    console.error('無法取得 canvas DOM');
    return;
  }

  engine = createEngine(canvas.value);
  scene = createScene(engine);
  createCamera(scene);

  /** 反覆渲染場景,這樣畫面才會持續變化 */
  engine.runRenderLoop(() => {
    scene.render();
  });

  loading.hide();
}

現在讓我們在 onMounted 中呼叫 init() 吧。

<template>
...
</template>

<script setup lang="ts">
import { ArcRotateCamera, Engine, Scene, Vector3 } from '@babylonjs/core';
import { onMounted, ref } from 'vue';
... 
function createEngine(canvas: HTMLCanvasElement) { ... }
function createScene(engine: Engine) { ... }
function createCamera(scene: Scene) { ... }

function init() { ... }

onMounted(() => {
  init();
});
</script>

熟悉 Vue 的讀者們一定都知道會在 onMounted 中才初始化,是因為這樣才取得到 canvas DOM。

接著是當組件銷毀前,需要關閉引擎。

onBeforeUnmount(() => {
  engine.dispose();
});

再加入考慮畫面隨視窗自動縮放的功能。

onMounted(() => {
  init();
  window.addEventListener('resize', handleResize);
});

onBeforeUnmount(() => {
  engine.dispose();
  window.removeEventListener('resize', handleResize);
});

function handleResize() {
  engine.resize();
}

最後暫時取消 game-console 自動跳轉回首頁的限制,以免每次需要重新整理網頁的時候一直跳回首頁。

src\views\game-console.vue

...
<script setup lang="ts">
...
function init() {
  // 房間 ID 不存在,跳回首頁
  // if (!gameConsoleStore.roomId) {
  //   router.push({
  //     name: RouteName.HOME
  //   });
  //   loading.hide();
  //   return;
  // }
  ...

  // 跳轉至遊戲大通
  // router.push({
  //   name: RouteName.GAME_CONSOLE_LOBBY
  // });
}
init();
</script>

現在讓我們按下「開始遊戲」產生 3D 場景吧!

ezgif-1-2623af8a77.gif

鱈魚:「出現了!ᕕ( ゚ ∀。)ᕗ」

助教:「出個毛線!這坨深藍色我用 CSS 都能產生!⎝(° Д °⎝)」

鱈魚:「那是背景預設的顏色啦,讓我們慢慢來嘛。(´,,•ω•,,)」

組成一個完整 3D 物件最基本構成是 Mesh 與 Material,前者負責組成「骨架」,後者負責「皮膚」。

現在讓我們建立一片海洋(其實就是一片地板),過程如下:

  1. 建立海洋要用的網格

    這裡使用 MeshBuilder.CreateGround,可以產生一個不具厚度的網格,因為地板不需要厚度。

  2. 建立材質

    將顏色設定為藍色後附加於網格上。

參考資料:
Creating A Ground
Background Material

以上步驟便可以完成海洋地板了,現在建立新增海洋的 function。

...
<script setup lang="ts">
import { ArcRotateCamera, BackgroundMaterial, Color3, Engine, MeshBuilder, Scene, Vector3 } from '@babylonjs/core';
...
function createEngine(canvas: HTMLCanvasElement) { ... }
function createScene(engine: Engine) { ... }
function createCamera(scene: Scene) { ... }

function createSea(scene: Scene) {
  const sea = MeshBuilder.CreateGround('sea', { height: 1000, width: 1000 });

  const material = new BackgroundMaterial("seaMaterial", scene);
  material.useRGBColor = false;
  material.primaryColor = new Color3(0.57, 0.70, 0.83);

  sea.material = material;

  return sea;
}

function init() {
  ...
  engine = createEngine(canvas.value);
  scene = createScene(engine);
  createCamera(scene);

  createSea(scene);
  ...
}
...
</script>

Untitled

鱈魚:「現在是一片淺藍色了!◝( •ω• )◟」

助教:「所以我說那個 3D 呢?(○´・д・)ノ」

鱈魚:「那就讓我們建立浮冰吧!( •̀ ω •́ )✧」

...
<script setup lang="ts">
import {
  ArcRotateCamera, BackgroundMaterial, Color3,
  Engine, MeshBuilder, Scene,
  StandardMaterial, Vector3
} from '@babylonjs/core';
...

function createSea(scene: Scene) { ... }
function createIce(scene: Scene) {
  const ice = MeshBuilder.CreateBox('ice', {
    width: 30,
    depth: 30,
    height: 4,
  });
  ice.material = new StandardMaterial('iceMaterial', scene);

  return ice;
}

function init() {
  ...
  createSea(scene);
  createIce(scene);
  ...
}
...
</script>

冰塊出現了!

Untitled

鱈魚:「是不是和吃冰一樣簡單啊!♪( ◜ω◝و(و」

助教:「所以我說企鵝哩?(。_。)」

鱈魚:「…( ◜ω◝و(و」

總結

  • 成功使用 babylon.js 建立 3D 場景
  • 建立海洋地板
  • 建立冰塊物件

以上程式碼已同步至 GitLab,大家可以前往下載:

GitLab - D21


上一篇
D20 - I want to play a game
下一篇
D22 - 企鵝登場:建立企鵝 Class
系列文
派對動物嗨起來!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言