iT邦幫忙

2025 iThome 鐵人賽

DAY 7
1

昨天,我們介紹了 Graphics 類別,學會了如何用程式碼畫出各種形狀,甚至還挑戰了一個會動的紅綠燈。今天,我們將介紹另一個遊戲中不可或缺的元素:文字

Text 是 PixiJS 中最基礎的文字顯示物件,它讓我們可以輕鬆地在畫面上顯示訊息、分數或任何需要用文字表達的內容。

▸ 開始動手

首先,將你的 app.ts 程式碼清空,並貼上以下程式碼:

import pixi = CG.Pixi.pixi;

export async function start() {

    // 初始化 Pixi
    await pixi.initialize({ stageWidth: 960, stageHeight: 540 });

    // 創建一個 Text 物件
    const text = new PIXI.Text({
        text: 'Hello CG!\nHello PixiJS!\nHello iThome!',
        style: {
            fill: 0xFFFFFF,
            fontSize: 100
        },
        anchor: 0.5,
        position: { x: pixi.stageWidth * 0.5, y: pixi.stageHeight * 0.5 }
    } as PIXI.TextOptions);

    // 將 Text 物件加入舞台
    pixi.root.addChild(text);
}

start();

貼上程式碼後,點擊「試玩遊戲」,你應該會看到畫面上出現三行大大的文字:

Pixi Text 預覽

▸ 拆解程式碼

1. 創建 Text 物件

創建 Text 物件的方法非常簡單,只需要傳入一個帶有 text 屬性的物件,就可以創建一個最基本的文字物件。

const text = new PIXI.Text({
    text: 'Hello CG!\nHello PixiJS!\nHello iThome!',
    style: {
        fill: 0xFFFFFF,
        fontSize: 100
    },
    anchor: 0.5,
    position: { x: pixi.stageWidth * 0.5, y: pixi.stageHeight * 0.5 }
} as PIXI.TextOptions);

除了 text 屬性用來設定文字內容外,這裡我們還看到了其他屬性,像是 styleanchorposition。這些都是 PixiJS v8 新增的特性,允許我們在創建物件時就直接設定它的樣式、錨點和位置,讓程式碼更簡潔。

如果你想要在之後更新文字物件內顯示的文字內容,可以這麼做:
text.text = "更新後的文字";
直接設定文字物件的 text 屬性即可更新顯示的文字。

2. 加入舞台

這一步驟和我們前面介紹的 SpriteContainerGraphics 完全一樣。我們可以使用 addChild() 將文字物件加入到舞台或容器中。

// 將 Text 物件加入舞台
pixi.root.addChild(text);

▸ 文字樣式 PIXI.TextStyle

如果覺得預設的文字太單調,Text 物件還提供了許多屬性讓我們自訂樣式,例如字型、大小、顏色、對齊方式等等。

讓我們將 start() 函數內的程式碼,改成以下這樣:

// 初始化 Pixi,設定背景顏色為 0x2BC5F9(淺藍色)
await pixi.initialize({ stageWidth: 960, stageHeight: 540, backgroundColor: 0x2BC5F9 });

// 創建文字樣式物件
const style = new PIXI.TextStyle({
    fontFamily: 'Arial', // 字體字型
    fontSize: 90,        // 字體大小
    fontWeight: "bold",  // 字體寬度(粗體字)
    fontStyle: "italic", // 字體風格(斜體字)
    fill: 0xFFFFFF,      // 字體顏色
    stroke: { // 描邊設定
        color: 0x0E50E2, // 描邊顏色
        width: 7         // 描邊寬度
    } as PIXI.StrokeStyle,
    dropShadow: { // 陰影設定
        color: 0x000000,     // 顏色
        angle: Math.PI / 6,  // 角度(單位弧度)
        distance: 6,         // 距離
        alpha: 0.5,          // 不透明度
        blur: 4              // 模糊度
    }
});

// 創建文字物件
const text = new PIXI.Text({
    text: '2025 iThome 鐵人賽',
    style: style, // 使用上方的字體樣式
    anchor: 0.5,
    position: { x: pixi.stageWidth * 0.5, y: pixi.stageHeight * 0.5 }
} as PIXI.TextOptions);

pixi.root.addChild(text);

貼上程式碼後,你應該會看到畫面中央出現令人熟悉的文字。

Pixi Text 樣式預覽

常用樣式屬性

  • fontFamily:字體字型,可以是字串或陣列(多個字體)。
  • fontSize:字體大小。
  • fontWeight:文字粗細,如 "bold""lighter" 等。
  • fontStyle:文字風格,如 "italic""oblique" 等。
  • fill:填充顏色,可以接受十六進制顏色碼或 CSS 顏色字串。
  • stroke:邊框樣式。
  • dropShadow:陰影樣式。
  • align:對齊方式,例如 "left""center""right"

更多樣式設定,推薦可以去 PIXI.TextStyle Editor 玩玩看,有介面可以直接改變、預覽字體樣式,雖然目前該工具僅支援 PixiJS v7 版本,但大體上差不多。或是直接查看官方 API

▸ 使用資源管理載入自訂字體

除了使用系統內建字體,PixiJS 也支援載入自訂字體。這對於遊戲的美術風格來說非常重要,因為很多遊戲會使用獨特的像素字體或藝術字體。

1. 於資源管理載入字體

這裡會用到 Day 03 介紹過的資源載入方式,來將字體資源載入到專案中,你可以自行上傳,也可以使用其他人上傳的字體。

這次我同樣使用其他人上傳的字型資源,於搜尋關鍵字內輸入 Cubic11,應該會找到一個由 Nyuightq 上傳的 Cubic11.ttf,點擊「加載資源」將該字型載入至專案中即可。

俐方體11號/Cubic 11:https://github.com/ACh-K/Cubic-11

CG 並不會審核創作者們自行上傳的資源,上傳前應確保資源的版權問題,若非無版權、開源,或是自行生產的資源,應在上傳時將「公開資源」的選項取消選取,以保護自身以及資源作者的權益。

2. 使用自訂字體

有了字型資源之後,我們同樣要使用 pixi.assets,在程式執行的一開始將該資源加載至遊戲中,才可以在後續使用。

同樣修改 start() 函數內的程式碼:

// 從專案載入字體(記得將資源別名修改成你自己專案的資源別名喔!)
await pixi.assets.add("ironman2025_cook.字型.Cubic11").load();

await pixi.initialize({ stageWidth: 960, stageHeight: 540 });

// 創建文字物件
const text1 = new PIXI.Text({
    text: "這是...像素字體!!",
    style: {
        fontFamily: "Cubic 11", // 字體字型(填寫字體名稱,而非資源別名)
        fontSize: 60,
        fill: 0xffffff,
    },
    anchor: 0.5,
    position: { x: pixi.stageWidth * 0.5, y: pixi.stageHeight * 0.5 }
} as PIXI.TextOptions);

pixi.root.addChild(text1);

Pixi Text 像素字體字型

這裡要注意的是,fontFamily 的值要輸入的是字體檔案內的字體名稱,而不是字型資源的別名,字體名稱可以在字型資源的詳細資料內找到,屬性為 fontName,如下圖。

CG 資源管理 字體名稱位置

▸ 文字解析度 resolution

Text 物件的 resolution 屬性是一個非常實用的優化工具,它影響著文字的清晰度和效能。

簡單來說,resolution 決定了 PixiJS 內部用多大的紋理(Texture)來渲染我們的文字。

  • resolution: 1 (預設):每個像素都對應一個螢幕像素,渲染速度最快,但如果放大會變模糊。
  • resolution > 1 (例如 24):使用更高解析度的紋理來渲染,讓文字更清晰,但會佔用更多記憶體。
  • resolution < 1 (例如 0.5):使用較低解析度的紋理,犧牲清晰度來換取效能。

讓我們看一個例子,感受一下不同 resolution 帶來的差異:

await pixi.initialize({ stageWidth: 960, stageHeight: 540 });

// 創建文字樣式物件
const style = new PIXI.TextStyle({
    fontSize: 60,   // 文字大小
    fill: 0xffffff, // 文字顏色
});

// 創建文字物件
const text1 = new PIXI.Text({
    text: "人在江糊,身不由己",
    style: style,
    anchor: 0.5,
    position: { x: pixi.stageWidth * 0.5, y: pixi.stageHeight * 0.25 },
    resolution: 0.5 // 設定解析度為 0.5
} as PIXI.TextOptions);

const text2 = new PIXI.Text({
    text: "江湖就是這樣,既不糊也不清",
    style: style,
    anchor: 0.5,
    position: { x: pixi.stageWidth * 0.5, y: pixi.stageHeight * 0.5 },
    // 若沒設定,解析度預設為 1
} as PIXI.TextOptions);

const text3 = new PIXI.Text({
    text: "高清無碼,限時解鎖",
    style: style,
    anchor: 0.5,
    position: { x: pixi.stageWidth * 0.5, y: pixi.stageHeight * 0.75 },
    resolution: 2 // 設定解析度為 2
} as PIXI.TextOptions);

pixi.root.addChild(text1);
pixi.root.addChild(text2);
pixi.root.addChild(text3);

Pixi Text 解析度對比

點我查看範例程式碼

▸ Bonus 關卡:打字機動畫

了解了 Text 基本的運作原理後,為了延續昨天的傳統,今天也有 Bonus 關卡!我們來做一個讓文字逐個顯示的動畫效果。

在偷看答案之前,各位可以先想想看如果是自己的話,會怎麼實現這個效果呢?

小提示:在 CG 的 async 函數中,你可以這樣來等待指定時間 await CG.Base2.wait(50); // 等待 50 毫秒

// 從專案載入字體(記得將資源別名修改成你自己專案的資源別名喔!)
await pixi.assets.add("ironman2025_cook.字型.Cubic11").load();

// 初始化 Pixi
await pixi.initialize({ stageWidth: 960, stageHeight: 540 });

// 創建一個文字物件
const text = new PIXI.Text({
    text: "Text",
    style: {
        fontFamily: "Cubic 11",
        fill: 0xFFFFFF,
        fontSize: 50,
        align: "center" // 置中對齊
    },
    anchor: 0.5,
    position: { x: pixi.stageWidth * 0.5, y: pixi.stageHeight * 0.5 }
} as PIXI.TextOptions);
pixi.root.addChild(text);

// 定義要顯示的文字字串陣列
const messages = [
    "很久很久以前......",
    "一名旅者來到了深山深處",
    "他遇到了一位老頭",
    "老頭意味深長的看著他",
    "隨即開口說道..."
];

// 執行下方的函數播放動畫
playAnimation();

// 定義一個播放動畫的函數
async function playAnimation() {
    for (const msg of messages) { // 將文字一個個從 messages 裡面拿出來
        text.text = "";           // 清除目前顯示的文字
        for (let i = 0; i < msg.length; ++i) {
            text.text += msg[i];     // 將一個字元加入正在顯示的文字物件內
            await CG.Base2.wait(50); // 等待 50 毫秒
        }
        await CG.Base2.wait(1500); // 等待 1500 毫秒
    }
    playAnimation(); // 再執行一次播放動畫的函數,直到天花地老...
}

將上方的程式碼放進 start() 內即可,你就可以看到如下方 GIF 顯示的動畫效果。怎麼樣?是不是很像一般像素遊戲中間的過場動畫阿!

詳細的運作原理,同樣就交給各位自行去鑽研啦~

Pixi Text 逐字顯示

點我查看範例程式碼

▸ 總結

今天我們介紹了 Text,它是 PixiJS 中用來顯示文字的基礎類別。

  • 你可以使用 new PIXI.Text() 來創建文字物件。
  • text 屬性用來設定文字內容,支援換行符號 \n
  • style 屬性可以傳入一個 PIXI.TextStyle 物件來客製化文字樣式。
  • Text 也具備 positionanchoralpha 等所有顯示物件的通用屬性。
  • 透過 assets 載入自訂字體,讓你的遊戲更有個性。
  • 使用 resolution 屬性來控制文字的清晰度與效能。

明天,我們將會介紹如何監聽使用者的滑鼠點擊或觸控事件,讓你的遊戲能夠與玩家進行互動,敬請期待!


上一篇
Day 06:繪製你的第一個形狀 - Graphics
下一篇
Day 08:讓物件可以互動:滑鼠與觸控事件
系列文
用 PixiJS 寫遊戲!告別繁瑣設定,在 Code.Gamelet 打造你的第一個遊戲8
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

1
小哈片刻
iT邦研究生 3 級 ‧ 2025-09-21 20:11:27

打字機動畫很帥~~~

酷可 iT邦新手 3 級 ‧ 2025-09-22 11:36:00 檢舉

帥吧!我也是這麼覺得~

我要留言

立即登入留言