Jan 22 2009
遊戲開發日誌:水晶守護者

《Crystal Guardian》Design Draft
這是《Crystal Guardian》的遊戲設計草稿。
其實大約在四個月前,我就已經完成了遊戲的基礎設計,本來想要在 NDS 平台上嘗試製作這款小小的遊戲原型,不過後來因為被其他有趣的事情吸引,再加上我一直找不到能夠在 Homebrew 套件上執行 Lua 的方法,所以也就沒有往 NDS 的方向繼續發展下去了。直到兩個月前,在玩過「咕世界」並且讀了「How to Prototype a Game in Under 7 Days」一文之後,內心深處那股「無論如何都想要做遊戲」的雄雄烈火,又再度燃燒了起來!
一開始在做遊戲設計的靈感發想時,對於目前網路上各種動作過關類型的小遊戲,可以看到大多數作品都是以「攻擊」、「毀滅」或者「破壞」當作遊戲的主要題材與樂趣元素。而我想要嘗試的,則是完全相反的方向。我反問自己:「有沒有可能以『保護』或者『防衛』的概念,做為遊戲的主要機制?」
當然,現在有許許多多 Tower Defence 類型的遊戲,但是我想做的並不是這種玩法的遊戲。我想做的遊戲,設計概念與核心機制的出發點在於「防護」(Defence),或許是保護金銀財寶、捍衛重要的東西或者心愛的人,無論那是什麼,我認為世界上總有些值得我們守護的人、事、物以及價值。而至於遊戲的操作方式,我想嘗試的方向,是一個不用動腦思考,只需要不停移動並且點擊滑鼠就能夠進行的遊戲。
按照遊戲原型開發文章裡的做法,我原先預估的開發時程為 10 天整。直到正式開始動工之後,馬上就發現每天的開發時間,實在是超級無敵不夠用,才剛做出了點東西就花費掉一整個晚上,依照這樣的進度,10 天左右肯定無法完成遊戲,於是決定將開發時程延長為 14 天。結果,最終在燃燒小宇宙與睡眠時間的狂暴化狀態下,還是延遲了 2 天,整整用了 16 天才完成這款小遊戲。
雖然遊戲的核心機制很早就已經建立完畢,但是 Game Theme(遊戲題材)卻一直處於懸而未決的狀態。原因是「遊戲題材」與「遊戲素材」具有非常高的相依性,在找不到美術設計者合作,我自己也不會畫圖的情形下,想要對遊戲題材拍板定案,實在是一項相當困難而又不切實際的想法。
以後見之明來看,如果當初能夠使用 Flash 做為製作工具的話,應該可以節省不少開發基礎遊戲元件所花費的時間。但是我對 Flash 的熟悉度,差不多停留在讓矩形移動與變大變小的程度而已,所以最終還是毫無懸念地決定使用我最熟悉的 C++ 與 Lua 製作遊戲。
而這次開發的成果,並不是完全從零到有產生出來的。我原先已經有一個小小的遊戲程式框架 (Framework),曾用來製作過一個 2D 遊戲的半成品,其中的功能只有非常基本的 Graphics、Audio、Input、Script 與 Debug 功能。於是我就以這個 Framework 做為出發點,義無反顧地展開了這趟遊戲開發的奇妙旅程。
過程中,我將每一天的進度都大致記錄了下來。以下就是這段時間裡,每天所做的開發日誌筆記:
Day 1
- 簡單扼要地在 Lua 端確立了程式的主流程。當程式啟動初始化完畢後,程式的控制權,包含 Update、Render 以及偵測視窗訊息與鍵盤滑鼠狀態在內,全權交由 Lua 端掌控。只要控制權一回到 C++ 端,就要清理資源然後準備結束程式了。
- 在既有的程式碼中,只能夠顯示單一的 Sprite 物件,這樣可不行哪。以 Sprite 為基礎,開始打造 CompositeSprite,可以組合任意多個 Sprite 做為一個完整的物件個體。(結果最後並沒有使用到這個功能)
- 原先在 Framework 中的 Input 系統只有二元狀態 On 或 Off 的 Polling 模式,對於開發除錯來說實在很不方便,所以決定先在 Lua 裡弄個簡易的 Event-based 模式,讓我在每次按下鍵盤或滑鼠按鈕時,只會送出一次事件訊息。
- 在網路上亂逛,意外找到《太空戰士》系列作品的 Sprite Sheet,品質看起來很不錯,是不是可以考慮拿來做為遊戲的素材?
Day 2
- 製作 Animation 系統。以前有使用 Lua 寫過相同的東西,所以翻出舊作的 Source 來看。「寫得真糟,當初怎麼會這樣想又這樣寫呢?」費了些功夫,翻修製作出新的 AnimatedSprite 元件。當然動畫資料的定義,也全部都使用 Lua 完成。
- 現在可以載入多張獨立的圖片播放動畫,但是網路上找到的 Sprite Sheet 通常都是一整張圖片的連續畫格,如果還得自己動手裁切,未免也太費力了點。所以只好再製作 AnimatedSprite 的第二種模式,讓它能夠讀入單張圖片來播放動畫。
- 套用《太空戰士》的 Sprite Sheet,測試 AnimatedSprite 元件的功能無誤。好,就決定偷這些圖來用!
- 重新組織 Lua 端的檔案結構。
Day 3
- 給點回應吧!實現簡單的矩形與圓形碰撞檢測。有了 Pick 元件後,才能夠知道滑鼠到底有沒有點選到 Sprite。
- 創造簡易的 State Machine 元件來搭配角色的 Animation 系統,目前只有 idle 與 move 兩種狀態。
- 放上數個不同圖片的角色,於遊戲視窗中隨機遊走。顯示結果怎麼全部的角色圖片都相同?
- 第一次臭蟲大魔頭來襲:是之前的 AnimatedSprite 功能有誤嗎?還是哪個部分的功能有所疏忽?經過了一番奮戰並且用掉好幾罐「補血瓶(小)」之後,才發現原來我誤用了 Lua 物件導向設計的觀念!
下列程式碼是錯誤的用法:
local o = self:Instance();
o.m_Transform = transform;
o.m_Texture = texture;
o.m_Sprite = sprite;
下列程式碼才是正確的版本:
local o = self:Instance
{
o.m_Transform = transform,
o.m_Texture = texture,
o.m_Sprite = sprite,
};
修改完成後,終於還給每個角色他們原來的真面目了!
Day 4
- 開始加入先前已設計完成的 Game Level 結構,可使用 Lua 檔案很便利地定義每一個關卡敵人的出現時間、類型、數量與方位。
- 簡便地使用 function 與 if-else 切換不同的 Game Stage。目前初步規劃,共有 Initialize、In Game、Between Level 與 Game Set 四個 Stage。(決策錯誤)
Day 5
- 建立玩家角色的各種狀態:idle、move、attack、powerup 以及 dead。滑鼠點擊後,玩家角色會移動至滑鼠位置,如果角色正在進行攻擊動作則無法移動。過程很順利。
- 創建敵人的 dead 與 dig(偷取水晶)狀態,包含先前的 idle 與 move 在內,終於完成了第一個完整的 AI 流程。不過敵人還是只會在場景上到處亂逛。
Day 6
- 開始著手製作原先規劃的數種 AI 型態:預設的一路走到底 AI、亂亂走 AI,還有走一走會停下來的 AI。
Day 7
- 為了讓 Release Build 的建置程序更加自動化與直覺化(簡單說就是我懶得做一大堆複製貼上的動作),所以用 Lua 弄了個 Prebuild 程序。將指定的純文字格式 Lua 檔案,全部寫入一個新的檔案中,完畢之後執行 luac 編譯成 binary 格式。最後,把執行命令加在 Project 的 Post-Build Event 中,搞定!
Day 8
- 開始寫 Gameplay 流程的部分,包括 Stage 與 Stage 之間的銜接,Game Over 與全破關的條件判斷。程式碼逐漸有越來越混亂的感覺……
Day 9
- 到目前為止,遊戲中還沒有出現任何文字。所幸 Framework 中已有繪製 TrueType Font 的功能,直接拉進 Lua 使用。測試無誤。
Day 10
- 到 POPcade 的音樂音效素材區搜尋資料,找到一個日本的網站 Propan_Mode,裡頭滿滿的都是 MP3 格式的高品質音效與音樂,真是太棒太讚太感動啦!(不過一直沒有找到合適的攻擊音效,囧)
- 加入播放音樂與音效的功能。製作一個 Radio 元件,用來做為遊戲中的 BGM Player,可把使用者提供的播放清單,依序、隨機或者循環播放。
Day 11
- 在 Google 打上「Free Font」,從成千上萬個 Font 裡找到幾個還算合用的字型。
- 用網路上搜尋到的免費軟體,將 MP3 轉換為檔案容量較小的 OGG 格式,將播放音效的程序加入遊戲。
Day 12
- 用 Photoshop 幫角色圖片進行去背程序。讚!終於不用帶著白色的框框在場景上行走啦。
- 再度修改 Animation 系統與 AnimatedSprite 元件,現在可以指定動畫中每個畫格的起始位置了。
- 產出遊戲角色以及水晶的動畫定義檔,對每一個動作的每一個畫格(還好數量很少),Pixel by Pixel 逐一進行微調。
Day 13
- 測試 AI 系統裡最複雜的「閃避」程序。果然有不少問題,經過整修後得出一個還算可接受的成果。
- 修改 Framework 的 Debug 功能,可將 Lua 的錯誤訊息以 MessageBox 秀出來並且記錄在 Log 檔中。(為什麼這麼晚才想到可以這樣做? =_=)
Day 14
- 實作 AI 的 Perk 程序,敵人「格檔」時會無視玩家的攻擊,「反制」時會使玩家在三秒內無法動作。掛上一個額外的盾牌與雙劍小圖示。
- 加入分數計算以及 Combo 連擊加成的程序。
- 從以前的作品素材中,拉來幾張背景圖。場景畫面終於脫離了單調無趣的背景色!
Day 15
- 開始正式製作遊戲關卡。試玩,微調,微調,微調。
- 找了台沒有安裝 MSVC 的電腦測試,確認遊戲執行檔沒有 DLL 相依性的問題。
- 第二次臭蟲大魔頭來襲:正當我以為遊戲已經逼近完成之時,突然發現了嚴重的邏輯與流程問題。當敵人奪取水晶之後再被玩家擊倒,敵人的 AI 會產生異常狀態。然後過關條件的判斷也不正確,水晶都被幹光了竟然沒有切換到 Game Over 的 Stage,到底是怎麼回事?
Day 16
- 重新大整修:首先是敵人連結水晶的部分,寫的方式含糊不清又太多假設條件,造成不正確的執行結果。接著再重新思考敵人的 State 轉換,將原先散落在各個 State 中的邏輯判斷,提煉出來做為獨立的 function。最後,加入一個新的「準備階段」Stage,大幅簡化 Stage 與 Stage 之間的切換流程。
- 重新調整關卡難度。調整。測試。調整。測試。完成!
- 打包壓縮,撰寫文章,發佈。(靈魂飄走)
以上就是 16 天以來的開發流程。
雖然我使用 Lua 已經有一段不算短的時間了,但這還是我第一次以 Lua 完成所有的 Gameplay 程式碼。在遊戲的開發流程中,相關於程式設計的部分,只有使用了 5% 左右的時間在修改及新增 C++ 端 Framework 的功能上,其餘 95% 的時間全投注於 Lua 的環境下撰寫程式碼。再者,為了使這些以 Lua 撰寫的遊戲元件能夠繼續在未來的遊戲作品中使用,所以也耗費了不少時間在考量 Reusability(可復用性)的議題。最終,順利地把 Lua 端的程式碼,分成了「遊戲元件」(可復用)以及「Gameplay 相關」(不可復用)兩種不同的用途。
使用 Lua 編寫 Gameplay 程式邏輯的主要優勢在於「速度」。修改,存檔,然後執行,一氣呵成!再也不必因為一點小小的修改,而必須等待漫長的程式碼編譯與函式庫連結時間。但是使用 Lua 也並非全無缺點;在程式碼編輯工具的選擇上,我使用的是 Lua for Windows 套件中的 SciTE 編輯器,雖然 SciTE 具備有基本的編譯與除錯功能,但無法與 C++ 端的程式碼相互連結,所以在 Gameplay 的除錯程序上比較麻煩,還是必須執行 C++ 端的程式執行檔,才能夠找出 Lua 端的錯誤與問題點。
另外在撰寫程式的過程中,我有點太過於小看 Stage 切換邏輯判斷的複雜度。一開始在撰寫 Stage 相關的部分時,並沒有設想太多,只使用了最簡單的 function 與 if-else 敘述句來切換不同的 Stage,結果到了最後反而造成不少問題。還是應該打從一開始就把 Stage 的架構與流程控制,寫成一個獨立可重複利用的元件才正確。
而在所有的程式系統與遊戲邏輯中,最複雜的部分應該就是敵人的 AI 程序了。我想達到的目標,是多變且具有擴充性的 AI 模組。為了達成多樣化的 AI 行為,如果只是單純地將 AI 程序分成「直線型」、「隨機型」與「格檔型」等等,其實無法發揮良好的綜效。所以後來我想到了一個做法,就是將 AI 處理程序拆解成三種獨立的邏輯程序,分別是 Path Planner、Tactic Thinker 以及 Perk(特技):
Path Planner
- 直線
- 隨機
Tactic Thinker
- 無
- 暫停
- 閃避
Perk
- 無
- 格檔
- 反制
分成三種獨立程序之後,我就可以在設計各關卡的敵人類型時,任意組合上述三種 AI 邏輯程序,然後再加上敵人外觀與生命數值的設定,製作出豐富而多樣化的敵人軍團。
在這 16 天的遊戲開發過程中,排除之前預先完成的遊戲設計層面,以程式設計、素材生產與關卡設計三個面向進行評估,程式設計約略佔了 80% 左右的開發時間,而素材生產與關卡設計加起來卻只佔用了 20% 左右的時間。用在關卡設計與素材製作面向上的心力,實在太少太少啦!
總結來說,下一款遊戲作品的改善目標為:
- 先搞定 Stage 架構與流程控制元件。
- 美術!我需要找到能夠共同合作的美術成員,或者是可以見人的 Better Programmer Art。
- 花費更少的時間寫程式碼,把更多時間心力投注在關卡設計與素材製作上。
- 遊戲必須要更有趣,更具有可玩性。
在遊戲設計的層面上,我還是個十足的嫩咖,但是只要過程好玩,我就會一直一直玩下去! :D
你可能不知道的小秘辛:遊戲本來想取名為 Crystal Defender,後來發現 Square Enix 在 iPhone 上有發佈一款同名作品,所以只好更換名稱為 Crystal Guardian。 XD
你不可不知道的小秘技:如果覺得遊戲太刁難或是滑鼠不夠滑而過不了關,請打開遊戲資料夾中的 GameEnemy.lua 與 GameLevel.lua 檔案,相信各位一定能夠發現戰勝遊戲的很黑暗的招。 :P

看了真是令我振奮精神
很厲害喔
我之前也常嘗試著自己開發
只是都死在美術素材不足
加油吧
真精采的筆記~~ “我認為世界上總有些值得我們守護的人、事、物以及價值”,不確定半路有沒有看過我以前做的小遊戲,有類似的理念耶,而且也一樣是一直點滑鼠就行。用Flash做小遊戲真的快很多!
http://blog.xuite.net/laishiekai/Dairy/7617714
有想過要做2.0版,像是有的牛奶會讓寶寶跑速上升一段時間啦、增加爸爸的招數啦… 可是那個寶寶從遊戲來到我們的真實生活後,我就沒力氣去動flash了… = =
看這份開發筆記就知道開發過程會發生多少奇奇怪怪的事…如果是合作的話,我想這份筆記應該會再增加個一兩千字吧XD
不過,我一直以為自製遊戲最缺乏的應該是程式呢…因為我自己是美術,總覺得程式反而難找,可見專業領域的生活圈都挺狹小的,不太認識其它領域的人。
AI的部份,之前在企劃製作一款梭哈遊戲時遇到了很大的瓶頸,也是一年來第一次接觸實際的AI,所以一整個不曉得怎麼辦…過去都是用簡單的判斷式,但是以博奕來說,這樣又缺乏變化性,所以最後沒有完成Orz
我欣賞遊戲的構思和實作的完整程度。雖然說是Prototype,郤做得像成品。要學習。
人家是七整天做一個遊戲吧,十六天工餘時間也不容易,再次佩服半路的勤奮。
不知道這遊戲大約需要多少行 Lua 代碼實現呢?Framework又有多大呢? 想參考一下。
一樣身為遊戲人的我
對你記欣賞又佩服,還有些羨慕,
目前在公司做一款算是自己喜歡的專案,
但在公司限制與怪意見就是多…,
而且還有搞死人不償命的公司文化!
自己出來搞遊戲的念頭從來沒段過,
不過我是企劃…自己搞必須有錢..
不然就是有夥伴>”<
在不然就是自己要會程式….(自修自修)
一起加油吧
哪個筆記很讚,我手邊也有很多這種類似sketch的東西,不過礙於領人薪水,就不能亂分享了~
很多人想看遊戲製作的過程,這算是一個不錯的小原型:)
恩,很喜欢game-dev story呢.
十六天工餘時間就能完成一個可玩的遊戲
很厲害!
看到能做到這樣實在佩服。改天再好好請教如何使用Lua。
@Rich:
所以說,跟美術做好朋友真的是很重要的事啊。 Q_Q
等等,不對啊,你明明自己就會畫圖,而且還畫得很好。我想應該是分身乏術而不是素材不足的原因吧? XD
@lsk:
有!很久之前在逛你們家部落格的時候,就有玩過《爸爸寶衛戰》,現在才知道原來你們也有類似的想法概念,真是太巧啦~
「可是那個寶寶從遊戲來到我們的真實生活後,我就沒力氣去動flash了… = =」哈哈哈哈哈,我大笑了。不過我覺得要照顧真實生活中的寶寶,可遠比製作遊戲來得困難太多啦。 ^^
@Azusa:
沒錯,如果和其他人合作的話,這份開發日誌應該會更加精彩。你提到了一項事實:「專業領域的生活圈都挺狹小。」我覺得真是一點也沒錯,可能我自己就是這樣吧,實在需要設法改進才行。 Orz
如果只使用 if-else 或者 switch-case 做 AI 判斷,只要遇到比較複雜的邏輯判斷與狀態變換,寫到最後一定會炸掉。 (無誤)
@Milo Yip:
對了,我原來就想寫出來,結果寫著寫著就忘記了。感謝提醒! = =
@橘子:
謝謝,可以做自己喜歡的專案是很幸福的事情,無論如何也要堅持下去!
在自己搞之前,我想與其一開始就花錢,倒不如先找到可以一起合作的好麻吉好伙伴才是正途啊~
@梅添涼:
公司的東西當然不能分享,不過阿涼應該有一些私人的設計草稿吧?嘿嘿嘿,或許可以考慮拿出來當作教材喔。 = =+
@zii:
謝謝,希望能多交流分享。 ^^
@Percy:
謝謝,不過只是可玩還不夠好玩,還得繼續加強才行。 ^^
@Wallace:
我覺得 Lua 實在是越用越有滋味。別說請教,就相互交流討論吧! :D
非常感謝各位的熱烈迴響,接下來我要準備好好去度個假了,期望自己過完年回來之後,已經重新補滿了體力與能量。在此先預祝各位牛年快樂,在新的一年裡,每個人都能夠成為工作與專業領域上的牛人! ^_^
美術啊……,去開拓動漫祭找一個吧
我在WKY做的dawn2程式目前還是基礎建設的階段,那位美術兼劇本現在也非常沒空,何時能完成很難說
最近找到了可能合作的作曲者,就等那位夥伴抽空找他們談了
我覺得自製遊戲最容易缺的是作曲,「四季樂章」這個俱備程式、美術、音樂人才的團隊是很有潛力的
水晶守護者看了不太有興趣玩,等比較完整的版本出來再看看吧
@Azusa:
「可見專業領域的生活圈都挺狹小的」
頗有同感,學問往往鑽得越深範圍越窄,一些大師的論點通常只在他那個圈子裡有用,拿到其他地方就用不著,所以我不會盡信大師。我比較敬佩能實際做出東西的人
看到這裡再一次慶幸自己是從遊戲fan site和同人場起家而不是一開始就鑽研技術,不會有鑽牛角尖或領域過窄的問題
http://gnn.gamer.com.tw/1/34741.html
早上看到這篇新聞嚇一跳,以為半路大大這麼快就跨足Wii了XD
話說小弟以前曾立志要成為3D美術…結果現在變成程式員了=.=v-~
@Shark:
有自信是好事,希望你們的作品早日問世。
@southp:
你好,
真是有夠巧的巧啊~ 現在想起來,還好我當初沒有打算做 Tower Defence 類型的遊戲。 XD
懂 3D 美術又會程式設計很好!如果可以成為 Technical Artist 就更讚啦(招手)。請不用加大大,稱呼我半路就可以了,謝謝。 ^^
作得很好呢!!
只是我沒有滑鼠用筆電玩不了T_T
GOOD GAME
不過很好奇是純用win32 api進行貼圖跟撥放音樂
還是有使用什麼套件??
@shell:
沒有滑鼠呀……用觸控板玩的話,大概會玩到想翻桌。 XD
底層是用 DirectDraw 和 DirectSound 來畫圖片和放音樂的。
感謝支持。 ^^
看了此篇,也想自己做做看,不過C++不熟。於是再找找Lua是否可以做,還真的找到。Lua SDL(Simple DirectMedia Layer)套件就是開發小遊戲用,但沒有在Lua for Windows套件中。
另一套LuaAIO(Lua all in one)中有含SDL,這套的函式庫更多,但無editor及debug界面。但對Lua進階user已是夠用。
看來應是有機會全用Lua來實現類似的小遊戲。
@Wallace:
SDL 簡單易用,很適合做中小型遊戲!而且有了 Lua binding 會更加便於撰寫 Gameplay 的相關程式碼,我覺得你可以盡量嘗試看看喔~ :D
我覺得光是能將一款遊戲完成,這本身就是值得喝采的一件事了。
感覺您也是對遊戲製作很有興趣的人,有空我們可以多交流交流:)
http://yokotachaos.styletw.com/
@yokotachaos:
原來你是多媒體領域的創作者啊~ 或許以後我們有機會可以合作唷!
我逛了一下你的網站,提供一點小建議:在任何有背景音樂的 Flash 頁面中,如果能夠提供「開啟或關閉音樂」的選項,以及「調整音量」的選項,對使用者來說會更加易於親近喔。
謝謝你的來訪。 ^^
介面做得不錯了耶
Hey~你在台灣嗎?
我也對遊戲開發很有興趣,雖然暫時還不能拿來賺錢吃飯
因為平常很忙,之前只有用Irrlicht做Tetris的經驗
之後沒做因為找人不收錢做美工很難,而且構想的遊戲要一個人完成可以能好幾年
這樣太沒意思了,所以到處找人一起做沒錢收的遊戲開發
我相信集合大家的力量才是王道,如果不嫌棄一起做的話就email給我吧
@Maxi:
你好,
我人在台灣沒錯。不過最近我正陷於水深火熱的生活和工作 schedule 中,所以目前沒辦法在工作之外花很長的時間去製作遊戲。要憑一己之力開發遊戲真的十分困難,我想我們可以先聊一聊,交個朋友! :D
我會再寄信給你,謝謝你的來訪。 :)
您好:)
我是來自大陸的開發者,您的blog寫的非常有”活力”,難怪有如此多的fans XD
看到此篇文章標題的Crystal Defence,我的第一反應就是SE iphone上的那款遊戲 囧
很期待您的下一篇文章 :D
@九思:
你好,
謝謝你的讚賞!我想這裡的讀者應該說不上是 fans 吧。而且比起所謂的擁護者,我更希望能夠聽到各種對於文章內容的討論與感想哩! = =+
嗯,這款遊戲和 SE 社的 Crystal Defenders 完全沒有關連性喔~ XD