遊戲人的心得錦集


下面收集職業、業餘遊戲開發者的心路歷程,國內唯一以心得出一本書的遊戲人大概就只有半路了,下面這份名單會不定期更新。

最後一次更新2015-10-21


猴子靈藥的中肯入行忠告
前進遊戲界:給大學生的行前準備建議

"前進天空樹"的製作人
給想全職做遊戲的你

雖然不是出自遊戲開發者之手,但是非常適合有興趣的學生
給大學生的忠告:把興趣當工作,不會帶給你快樂

NDark在元智大學的演講稿
遊戲製程心得二三事

Chris Crawford所寫的
頂級遊戲設計大師談如何成為一名遊戲設計師

興趣跟工作兩者之間本來就有著截然不同的性質,但是對社會新鮮人而言,常常覺得做自己喜歡做的工作才是理想目標,不希望將青春花在不喜愛的事物上,不希望為了賺錢而賺錢,希望往自己的興趣發展也能闖出一片天。


這沒什麼不好,親自去試過才會知道自己是怎樣的人,才會知道自己究竟能不能忍受逐夢的辛苦,究竟是不是真的不在乎薪水,這原本是畢業之前就該搞懂的事,不過長輩大多在你求學期間只會跟你說「先把書讀好」、「考到一所好學校再說」之類的,也許連這些出社會的大人們也不清楚自己的目標,如果沒搞清楚自己的方向,跑再遠都是白搭。


想要找適合自己的道路就必須先好好的認識自己,先尋找自己的起點才不會迷失方向。

我自訂的設計模式


2016/08/10
這篇提到的做法已經被我捨棄了,物件之間有依賴關係時,使用 std::shared_ptr 處理就已經很理想了。



在開發ToyBox途中,我設計了一個簡單的設計模式,用來解決我擔心的某種資源洩漏狀況。



很多情況下,兩個物件可能在資源上有依賴關係,需要互相保持聯絡,注意對方手上的資源是否還存在,當其中一方被銷毀或者打算切斷關係時,有必要通知對方一聲,讓對方可以處理一下(不要說一直到打了電話才知道這個人已經切斷關係),這可以避免許多記憶體問題,算是一種制式化的觀察者模式,只觀察對方是否打算斷絕聯絡,彼此互相觀察。


實作上就只是互相記住對方的指標,然後準備好一個callback function,上面紀錄當對方斷線時該如何應對,當對方斷線時就會由對方呼叫這個callback function。


實作寫在 ToyBox/include/toy/Link.hpp,大概要用一段時間才知道這作法的優缺點,有可能到頭來我只發現這作法是多此一舉也說不定,如果你對這個模式有什麼更好的建議,歡迎留言或來信告知。


#include <stdio.h> #include "toy/Link.hpp" //當 obj_B 主動絕交時會呼叫這個 obj_A 預先準備的行為 void obj_A_reaction() { printf("goodbye obj_B\n"); } //這範例是 obj_A 先斷交的,所以只有執行這個 void obj_B_reaction() { printf("goodbye obj_A\n"); } int main() { toy::Link obj_A; toy::Link obj_B; obj_A.SetReaction(&obj_A_reaction); obj_B.SetReaction(&obj_B_reaction); obj_A.Connect(obj_B); //兩者連結上了 obj_A.Disconnect(); //由obj_A主動斷交,此時只會呼叫obj_B_reaction() return 0; }

成員函式的callback function


C語言的callback function做法只能用函式指標去儲存全域函式,在C++中要用同一招會顯的很不自然,因為全域函式無法封裝到類別當中,而member function則無法直接傳遞函式指標,因為沒連帶物件指標一起傳是沒用的。



於是boost用樣板技巧創造出可以呼叫成員函式的「仿函式」,它將成員函式跟物件的指標封裝在一起,呼叫的人並不需要知道這boost::function的內容物是哪裡來的,裝的是全域函式還是成員函式也不用知道,甚至連這函式實際上到底需要多少個參數也不知道,非常全面的取代了 C語言的 callback function,你只要知道它可以取代函式指標,尤其想實現成員函式的callback function只剩這條路可選。


不過需要注意「仿函式」是用樣板實現的,而樣板魔法只能實作在標頭檔上面,這也不算什麼缺點,跟它帶來的好處相比實在太划算了。


仿函式歷經長時間的演化,已經成為了非常強大的好用工具,在C++11裡面已經成為標準庫成員了。


我的專案裡有個山寨版的仿函式實作,大多功能都有實現了,內容會比boost的原作好懂許多
,還滿有趣的,尤其bind的實作手法相當精彩,運用了繼承、樣板偏特化、多載,感謝boost高手們的貢獻,如果看不懂實作的話無所謂,畢竟那些樣板技巧很少用到。


#include <stdio.h> #include <functional.hpp> void MyFunction(int a) { printf("%d\n",a); } int main() { using namespace std::placeholders; // for std::placeholders::_1 std::function<void(int)> func=std::bind(&MyFunction,_1); func(5); return 0; }

lua與C++之間的互動:如何在lua裡面建立C++的物件


首先lua並不支援你將Class傳到script這邊,lua只支援將一個C風格的全域函式指標傳過去,因此一切行動都是從全域函式開始的。

基本概念就是將C++的一組全域函式傳到lua這邊,然後用lua的table將它們包裝的像個物件一樣,table會內含一個物件指標,這就是大致上的實作方向了。


首先在C++這裡寫個全域函式負責動態配置物件,將它的函式指標傳到lua之後會扮演建構子的角色,產生的物件指標會用lua的userdata來儲存。


另外再寫幾個全域函式來負責操作物件指標,它們的函式指標傳到lua之後會扮演成員函式的角色。

將上面這些函式裝到lua的table上面就可以直覺的使用C++的物件了。


解構子則不需要以上做法,在儲存物件指標的userdata上面就可以指定解構行為了。這裡需要注意一點,lua的解構時間點跟C++不同,因為lua的垃圾收集機制不是當變數無人使用時就會去清理,所以不要以為區域物件在離開該區域時就會當場解構,而且由於指標的size太小,lua根本不知道指標背後咬了多大一塊記憶體,可能會累積超多物件才解構,你最好自己親自呼叫"__gc"來解構,或者用collectgarbage("collect")強制要求立刻清理。


要傳給lua使用的全域函式有固定的格式(lua_CFunction),而且從lua取得參數以及送回傳值給lua都需要呼叫lua介面來執行,你可以看到網路上有很多教學是自己寫個Wrapper類別來當中間層,然後為類別量身打造一系列全域函式,這樣寫起來會很累,而且不能封裝的全域函式會破壞OO架構,程式碼不會好看到哪去。


幸虧C++還有樣版這樣的特別武器,可將上述手續給包裝起來,真的輕鬆超多的,我的luapp專案就是在做這件事,luapp已經將這份工作包裝的很舒服了。


當然檯面上還有其他更成熟的專案提供更全面的功能,不過以我的需求來說,自製的luapp已經堪用了。

CMake指令



CMake的組態檔總是命名為"CMakeLists.txt"
CMake的語法是由一堆函式構成
不管做什麼都是在呼叫函式
以下列出比較常用的


project(專案名稱)
你的專案檔生出來就會用這個名字

cmake_minimum_required(VERSION 2.8)
確認該環境的CMake版本符合你的要求,CMake會強迫要求你在主專案加上這行,子專案就沒關係

add_subdirectory(子資料夾)
進入指定資料夾然後執行裡頭的組態檔"CMakeLists.txt",這設計讓你很容易增加子專案

include_directories("路徑")
告訴CMake該去哪裡尋找標頭檔

link_directories("路徑")
告訴CMake該去哪裡尋找函式庫

add_executable("執行檔名字" main.cpp main2.cpp main3.cpp)
決定要編譯哪些程式碼,然後產生程式

set(EXECUTABLE_OUTPUT_PATH "路徑")
決定編譯出來的執行檔要放哪裡

add_library(函式庫名稱 STATIC main.cpp main2.cpp main3.cpp)
決定要編譯哪些程式碼,然後產生函式庫,STATIC表示你要編譯成靜態函式庫,動態要寫SHARED

set(LIBRARY_OUTPUT_PATH "路徑")
決定編譯出來的函式庫要放哪裡

target_link_libraries(函式庫/執行檔名稱 需連結的函式庫名稱)
決定要連結的函式庫,執行檔跟函式庫都用這個設定

message("想傳達的訊息")
CMake允許你在生成專案檔的過程印出一些訊息