Try   HackMD

112-2 程式設計二 Final Project:互動式小說引擎

分組名單填寫(規則於表單內):
https://forms.gle/WC6mSPaQ9zsbpgVL8

簡介

今年的期末專題是 互動式小說引擎(Interactive Fiction Engine, IFE),這是一個讓使用者能夠遊玩他們自己的互動式小說遊戲的程式。

首先,你必須要定義一個人類可讀的文字劇本檔格式,允許遊戲創作者以結構化的方式編寫和組織故事情節、角色互動及場景變化。我們建議你基於 TOML 與 YAML 等格式設計(而非 JSON),因為其易於讀寫的特性非常適合用於故事和遊戲設定。在這個劇本中,每個場景、角色和物品都應有其對應的設定方式,用來定義他們的基本屬性(如名稱和外觀),也包含了互動的可能選項與結果(如對話選項和情節分支)。

接著實作能讀取不同劇本的遊戲引擎,這個引擎應支援圖片的顯示和處理,包括場景背景、角色立繪和頭像、物品圖標等,並根據劇本設定進行合適的疊加處理。此外,引擎應支援包括基本對話和多重結局選擇的互動式元素,也須支援角色的情感數值變化(例如好感度),這些數值將根據玩家的選擇和互動發生變化來影響故事的發展和結局。

你也需要提供一份遊戲劇本,讓大家可以玩。

See https://en.wikipedia.org/wiki/Interactive_fiction

實作方法與限制

你可以自由決定使用的工具與框架,唯以下事項需遵守:

  • 劇本檔的解析與遊戲核心機制(如角色狀態、玩家狀態之變更)需以 C 語言完成,運算完成之介面內容則可以不同方式呈現
  • 部署環境為以一般使用者身份執行的 Ubuntu 22.04,且無法使用 sudo 等方式安裝其他額外程式及檔案,但可以跟你的程式一起包起來帶來。若要當場下載及安裝額外程式或檔案,安裝時間會列入發表時間內。請考量師大的網路環境,建議還是和程式包起來帶來。(但 libncurses-dev 的 library 會由我們預先安裝)
  • 劇本檔格式與程式使用方式需於說明書(README)中詳細介紹到非資工領域的遊戲創作者能操作的地步

一個假設例子

你繳交的壓縮檔可能有以下內容:

.
├── Makefile
├── src/
│   ├── main.c
│   └── other codes...
├── third-party/
│   ├── llama.cpp/
│   └── other dependencies...
├── models/
│   └── model.gguf
├── example-game/
│   ├── script.toml
│   └── assets/
│       └── image, audio, etc...
└── README.md
...

使用 make 後產生 ./engine 的可執行檔

使用 ./engine ./example-game/ 即可開始遊玩範例遊戲

一些參考資料

核心

你沒得選擇核心的實作方式,一定需要用 C 語言完成。

介面

但對於介面,你有兩條路可以選:Terminal UI (TUI) 與 Graphical UI (GUI)

如果你選擇 TUI 的話:

  • 如果你想在 terminal 上以高一點解析度顯示圖片,可以使用 Sixel
  • 如果你想要一些好看一點的介面,可以看看 ncurses

如果你選擇 GUI 的話:

  • 如果你想要用 C 語言寫圖形化介面,可以試試 SDL
  • 如果你想要用網頁當前端介面,可以使用 SvelteKit 搭配 static-adapter

語言模型(Additional Features)

對於雲端 LLM API,有以下幾個可以選擇:

除了 Cloudflare Workers AI 提供開源模型以外,其他都是提供自己家的模型。除 Anthopic 與 MistralAI 以外都可以微調,其中 Cloudflare Workers AI 的微調需要自己帶 LoRA 上去,其他都是丟資料上去它幫你調。

你也可以選擇 llama.cpp(函式庫)或 ollama(服務)等本機執行的方式。(把整坨 pytorch 打包來似乎不是好主意)

其他

另外:

  • 如果你想參考其他互動式小說引擎怎麼實作的,可以看看 Monogatari

如果你有興趣,可以使用以下完全本機高移植性技術堆疊完成:

  • 核心以 C 語言實現,編譯成 WebAssembly (WASM) 模組
  • 介面以 SvelteKit 實現,透過將輸入事件傳入 WASM 模組中計算後將畫面物件回傳
  • Language Model 可以用 llama.cpp 的 WASM 跑

好好完成期末專題你會學到很多很多東西喔~

評分方式

  • 基本需求: 60 pts
  • 額外功能: 85 pts
  • 期末發表: 30 pts

分數上限為 130 分

基本需求 (60 pts)

實作缺失會斟酌扣分

劇本檔:

  • 至少支援場景、人物、物品三種實體
  • 至少支援場景背景、人物頭像、人物立繪、物品圖標等圖片素材
  • 支援對話選項與多支線劇情設定(使用者可以透過選擇物品或是對話改變結局)

遊戲引擎:

  • 能實現劇本檔中期望呈現之內容
  • 支援場景背景與人物立繪之疊加顯示
  • 玩家需要有角色設定、可以放物品的背包
  • 不能出現壞掉的排版(文字亂換行、介面太明顯凸出去)
  • 支援角色個人心情數值,可以是單一好感度,或是多個不同面向的數值

範例遊戲:

  • 至少要有三個角色
  • 至少要有三個場景
  • 至少要有兩個物品
  • 至少要有三個結局

README 說明書文件:

  • 讓非資工領域的遊戲創作者能依照格式製作遊戲的說明書
  • 引擎實作了哪些功能、已知問題、注意事項等資訊
  • 劇本檔格式、命名方式、存放地點等

Script

你需要自行實作劇本檔格式,並於 README 詳細說明。

範例 Script:

name = "Final Project"
author = "TA"

[player]
starter = "start"
inventory = [
    "vision-pro",
]

[scene.library]
name = "The School Library"
background = "assets/scene/library.bmp"

[scene.meeting-room]
name = "The Meeting Room"
background = "assets/scene/meeting-room.bmp"

[character.classmate]
name = "Alice (your classmate)"
avatar = "assets/character/alice/avatar.bmp"
tachie = "assets/character/alice/tachie.bmp"

[character.ta]
location = "meeting-room"
name = "Teaching Assistant"
avatar = "assets/character/ta/avatar.bmp"
tachie = "assets/character/ta/tachie.bmp"

[item.vision-pro]
name = "Vision Pro"
description = "A spatial computer"
icon = "assets/item/vision-pro/icon.bmp"

[event.start]
scene = "library"
dialogue = "hello"

[dialogue.hello]
character = "classmate"
text = "嗨!聽說今年的期末專題要做互動式小說引擎喔~"
[[dialogue.hello.options]]
text = "哇!太棒了!"
next = "teamup"
[[dialogue.hello.options]]
text = "那是啥鬼?"
next = "explanation"

[dialogue.teamup]
character = "classmate"
text = "好,那我們一組吧!想一起來討論看看嗎?"
[[dialogue.teamup.options]]
text = "OK,我們去會議室找助教討論吧!"
event = "change_scene_to_meeting_room"

[dialogue.explanation]
character = "classmate"
text = "就是一個讓你創建和玩你自己故事的遊戲平台。聽起來有點複雜,但應該蠻有趣的!"
[[dialogue.explanation.options]]
text = "聽起來不錯,告訴我更多!"
next = "teamup"
[[dialogue.explanation.options]]
text = "好吧,我可能會需要幫助。"
next = "teamup"

[event.change_scene_to_meeting_room]
scene = "meeting-room"
dialogue = "ta_intro"

[dialogue.ta_intro]
character = "ta"
text = "你好!來討論期末專題嗎?"
[dialogue.ta_intro.options]
text = "是的,我們有一些想法想要詢問。"
next = "ta_discuss"

[dialogue.ta_discuss]
character = "ta"
text = "太好了!請告訴我你們的想法。"
[[dialogue.ta_discuss.options]]
text = "我們想加入不同角色的情感變化,這樣會怎樣?"
next = "emotion_implementation"
[[dialogue.ta_discuss.options]]
text = "我們打算探索多重結局的設計。"
next = "multiple_endings"

[dialogue.emotion_implementation]
character = "ta"
text = "情感變化是一個很好的功能,可以讓遊戲更加引人入勝。你們可以設計一個情感計分系統,透過玩家的選擇來影響角色對玩家的感情。"
[[dialogue.emotion_implementation.options]]
text = "聽起來很棒,我們會試試看。"
next = "finalize_ideas"
[[dialogue.emotion_implementation.options]]
text = "這樣會不會太複雜了?"
next = "simplify_discussion"

[dialogue.multiple_endings]
character = "ta"
text = "多重結局是一個很好的方式來增加遊戲的重玩價值。你們應該考慮讓玩家的選擇導向不同的故事路線和結局。"
[[dialogue.multiple_endings.options]]
text = "這個主意很好,我們會加入這個功能。"
next = "finalize_ideas"
[[dialogue.multiple_endings.options]]
text = "可能需要一點時間來實現這個想法。"
next = "time_management"

[dialogue.finalize_ideas]
character = "ta"
text = "很好,你們似乎已經有了一個明確的方向。開始動手做吧,有任何問題可以隨時來找我討論。"
[[dialogue.finalize_ideas.options]]
text = "謝謝你的建議!我們會開始實作了。"
event = "project_start"

[dialogue.simplify_discussion]
character = "ta"
text = "沒問題,你們可以從基本的好感度系統開始,然後逐步增加更多的功能。"
[[dialogue.simplify_discussion.options]]
text = "好的,我們會從基本的開始。"
next = "finalize_ideas"

[dialogue.time_management]
character = "ta"
text = "合理的時間管理和階段性目標設定對於成功完成專案非常重要。建議你們制定一個時間表。"
[[dialogue.time_management.options]]
text = "謝謝提醒,我們會制定計劃的。"
next = "finalize_ideas"

[event.project_start]
scene = "library"
dialogue = "start_working"

...

額外功能 (85 pts)

最佳實踐 (5 pts)

  • 4 pts GitHub 使用 GitHub 開一個 Repository ,並定期 push 上去(每位組員)
    • extra 1 pts 在這份 GitHub Repository 的原始碼加上授權條款,無論是否開源

視覺小說 (35 pts)

  • 5 pts 場景動畫 場景變換時,帶有 1 秒以上的動畫效果
  • 5 pts 心情變換 在不同時機替換角色的頭像與立繪
  • 10 pts 遊戲存檔 可儲存完整遊玩狀態至檔案,並從檔案回復儲存的狀態
    • extra 5 pts 該遊戲狀態存擋為人類可讀,且可直接使用文字編輯器更改
  • 10 pts 音效播放 使用 OpenAL 等工具播放音樂或音效,至少有五種音樂或音效

LLM (35 pts)

  • 10 pts LLM 開放式對話 使用 GPT / LLaMa / Mistral / 等 LLM 模型,實現一個開放式對話系統,使玩家能夠與遊戲中的角色透過輸入文字進行深入交流,並透過至少三次來回對話獲取關鍵線索,推動遊戲劇情發展。

    • 5 pts 一個角色使用開放式對話
    • 5 pts 三個角色以上使用開放式對話
  • 25 pts LLM 生成劇情 新遊戲時依照 script 為藍圖(角色、場景、物品)透過 LLM 生成劇情結構與故事,也就是場景、物品、角色可以預先定義,再使用此定義生成完整的 script。以下皆須自動生成,不可以先使用 LLM 生成後寫死在檔案裡。

    • 3 pts 至少使用了三個角色
    • 3 pts 至少使用三個場景
    • 2 pts 至少使用兩個物品
    • 3 pts 至少生成三個結局
    • 5 pts 劇情完整流暢
    • 3 pts 角色(含圖片)皆為 LLM 生成
    • 3 pts 場景(含圖片)皆為 LLM 生成
    • 3 pts 物品(含圖片)皆為 LLM 生成

其他 (10 pts)

  • 10 pts 進階 Script 支援使用 Lua 動態的更新遊戲狀態

Feature proposal:

任何認為值得加分且想實作的組別可以將 Feature proposal 以 [FP] 寄信給助教,隨後會將申請通過的加分選項放在這裡。期限預計至第 14 週末止。

  • 劇本檔若支援抓取線上資源,如劇本、圖片、音樂、影片等,這樣能否加分
    • 必須通過 C 抓取圖片,不得以 html 直接連結網址
  • 若能夠提供使用者一個自訂物件style,如字體相關設定、物件位置或樣式相關設定等
    • 以 terminal 實現 +3,以網頁呈現 +2

執行環境沒有 sudo 權限喔

期末發表 (30 pts)

我們將在本學期末進行期末專題發表。每組應準備以下項目:

  1. 你們設計的簡要描述,需要包含 Script 的格式。
  2. 你們完成哪些額外功能。
  3. 遊戲 demo。
  4. 每位成員的工作分配。

每組將有 12 分鐘 的時間進行發表,包括簡報和遊戲 demo。
請準備好一份可以在時間內完成 demo 的 Script。

重要日程

  • 分組名單填寫截止:4/30(二) 23:59
  • Feature proposal 截止:5/26(日) 23:59
  • 繳交截止:6/16(日) 23:59
  • 專題發表:6/17(一) ~ 6/18(二)