最近有許多人問我怎樣去開發一款遊戲,網上並沒有關於這個話題的文章,我就決定寫一些東西來分享一下我的經驗,關於遊戲開發的整個過程。記住這隻是一個概要,並且會因項目的不同而改變。
步驟一.選擇你的遊戲庫
除非你想寫自己的遊戲庫,包括那些麻煩的圖形和聲音編程模你應該需要一個開源的遊戲庫,他們都提供了相同的準系統。
任何一款優秀的遊戲庫所需具備的特徵:
載入和播放聲音;
載入和顯示映像;
基礎的映像操作(旋轉縮放等);
原始圖形繪製方法(點,線,矩形等);
顯示文字的方法;
多線程支援;
基本的計時器功能。
一些遊戲引擎:
Simple Fast Multi-Media Library (SFML): http://www.sfml-dev.org/
Simple DirectMedia Layer (SDL): http://www.libsdl.org/
Allegro: http://www.allegro.cc/
penGL (GFX only, however, there are wrapper libs like AllegroGL): http://www.opengl.org/
DirectX (Windows only): http://msdn.microsoft.com/en-us/directx/
Irrlicht (3d lib): http://irrlicht.sourceforge.net/
步驟二.確定好劇本
所有遊戲都從這裡開始,想法來自大腦。
首先,想出一個遊戲的點子,一旦你有了一個簡單的點子,就去擴充它。例如,一個棋盤遊戲,主題是什麼,勝利條件是什麼,規則又怎樣。如果一個遊戲有人物或故事,就去創造他們。一定要保證當你的遊戲完成時,你對你的遊戲將要成為什麼樣非常清楚。遊戲越是複雜,在開始之前你就越需要花時間來計劃,這樣當你在編碼的時候就不用去擔心這些問題了。記住,你的遊戲會像你當初建立它的樣子。
步驟三.定製你的引擎
到這一步,你需要計划出你的遊戲引擎所需的各個組件,並且能夠讓它們融合在一起,根據你項目的複雜程度,你也許不需要這個步驟,這也是檢驗你遊戲引擎哥哥部分正常工作的好時機,確保他們在放到實際項目之前是正常工作的。同時,你也因該開始設計你項目中的類(如果你使用OOP的話)。記住,已經有一些現成的引擎,並且適用大部分的項目。
步驟四.編寫你的引擎(如果你要自己動手的話)
現在可以正式開始編寫遊戲引擎了,這裡不是說開始寫遊戲,而是核心渲染,物理,檔案管理等等。用引擎裡的類和方法來構建你的遊戲。根據遊戲的複雜度,引擎的代碼可能與遊戲的代碼類似。
對於一個很複雜的遊戲,可能還需要一個資源管理員,一個資源管理員所做的就像它的名字那樣,管理資源(映像,音樂,聲音等等),它可以保持代碼整潔,並協助你避免記憶體流失。可以參考一個優秀的資源管理員Xander314.盡量讓你的代碼嚴謹,介面簡單,這樣做之後,當你在寫遊戲的時候就不需要去查看原始碼,找函數名了。一種好的編程方式就是OOP。
//put related components into classesclass collisions { bool check_col(obj1*, obj2*); //you should have a base object class that all void handle_col(obj1*, obj2*); //game objects are derived from, for easy passing to functions public: void handle_all(); //handles EVERYTHING collision related }Collision;class rendering { void bots(); void bullets(); void players(); public: void draw_all(); //calls other functions for rendering }Renderer;//this allows collision management and rendering in your game loop to be as simple as:Renderer.draw_all();Collision.handle_all();
Resource Manager by Xander314
/* ResourceManagerB.hpp - Generic template resource manager (C) Alexander Thorne (SFML Coder) 2011 <a href="http://sfmlcoder.wordpress.com/">http://sfmlcoder.wordpress.com/</a> Manages loading and unloading of a resource type specified by a template argument.****************************************************************/#include <map>#include <string>#include <exception>typedef const std::string URI;// exceptionsnamespace Exceptions {// thrown if user requests a resource URI not present in the manager's listclass URINotFound : public std::runtime_error { public: URINotFound(const std::string& Message = "The specified URI was not found in the resource index."): runtime_error(Message) { } };// thrown if a resource allocation failsclass BadResourceAllocation : public std::runtime_error {public: BadResourceAllocation(const std::string& Message = "Failed to allocate memory for resource."): runtime_error(Message) {}};}template <class Resource> class ResourceManagerB {typedef std::pair<URI, Resource*> ResourcePair;typedef std::map<URI, Resource*> ResourceList;// the list of the manager's resourcesResourceList Resources;public:~ResourceManagerB() { UnloadAll(); }// Load a resource with the specified URI// the URI could represent, e.g, a filenameURI& Load(URI& Uri);// unload a resource with the specified URIvoid Unload(URI& Uri);// unload all resourcesvoid UnloadAll();// get a pointer to a resourceResource* GetPtr(URI& Uri);// get a reference to a resourceResource& Get(URI& Uri);};template <class Resource>URI& ResourceManagerB<Resource>::Load(URI& Uri){// check if resource URI is already in list// and if it is, we do no moreif (Resources.find(Uri) == Resources.end()){// try to allocate the resource// NB: if the Resource template argument does not have a// constructor accepting a const std::std::string, then this// line will cause a compiler errorResource* temp = new (std::nothrow) Resource(Uri);// check if the resource failed to be allocated// std::nothrow means that if allocation failed// temp will be 0if (!temp)throw Exceptions::BadResourceAllocation();// add the resource and it's URI to the manager's listResources.insert(ResourcePair(Uri, temp));}return Uri;}template <class Resource>void ResourceManagerB<Resource>::Unload(URI& Uri){// try to find the specified URI in the listResourceList::const_iterator itr = Resources.find(Uri);// if it is found...if (itr != Resources.end()){// ... deallocate itdelete itr->second;// then remove it from the listResources.erase(Uri);}}template <class Resource>void ResourceManagerB<Resource>::UnloadAll(){// iterate through every element of the resource listResourceList::iterator itr;for (itr = Resources.begin(); itr != Resources.end(); itr++)// delete each resourcedelete itr->second;// finally, clear the listResources.clear();}template <class Resource>Resource* ResourceManagerB<Resource>::GetPtr(URI& Uri){// find the specified URI in the listResourceList::const_iterator itr;// if it is there...if ((itr = Resources.find(Uri)) != Resources.end())// ... return a pointer to the corresponding resourcereturn itr->second;// ... else return 0return 0;}template <class Resource>Resource& ResourceManagerB<Resource>::Get(URI& Uri){// get a pointer to the resourceResource* temp = GetPtr(Uri);// if the resource was found...if (temp)// ... dereference the pointer to return a reference// to the resourcereturn *temp;else// ... else throw an exception to notify the caller that// the resource was not foundthrow Exceptions::URINotFound();}
步驟五.映像和聲音
基於你的遊戲的觀點,開始建立你的圖形和聲音特效。當你開始深入開發的時候,你可能需要去創造更大的GFX和SFX,還會刪除掉那些不需要的資源,這個過程可能會貫穿整個過程。
步驟六.寫遊戲
當你完成了你的遊戲引擎之後,你可以開始寫遊戲了。這包含了很多東西,包括規則,故事,遊戲的主迴圈也會在這裡建立。這個迴圈會一遍遍地跑,並且會更新遊戲中的所有事物。
看下面的例子,如果你編寫的引擎是正確的,這將比編寫引擎更容易一些,也更有趣。當你在某個地方加入一些音效的時候,也會很棒。當舞台搭建完畢,你應該儲存一份能偶跑起來的代碼,確定你看到的是你所預期的。
//your loop will probaly be very different from this, especially for board games//but this is the basic structurewhile (!Game.lost()) //or whatever your condition is (esc key not pressed, etc){ Game.handle_input(); //get user input AI.update_bots(); //let your bots move Collision.handle_col(); //check for collisions Game.check_win(); //see if the player won or lost Renderer.draw_all(); //draw everything Game.sleep(); //pause so your game doesn't run too fast //your game lib of choice will have a function for this}
步驟七.最佳化
遊戲能夠跑起來並不意味著就完成了,除了添加最後一點劇情,你還可以對代碼進行最佳化,包括記憶體使用量(不要使用全域變數,檢查記憶體配置等等),遊戲提速(保證你的代碼不會太慢,並且不是在任何時候都在大量地消耗CPU)。測試也可以放到這一步。
步驟八.打包發布
現在你的遊戲完成了,你需要將其打包,然後發布。對於打包,盡量保持有調理,並把最終產品放進一個單檔案中(安裝檔案,zip等),讓發布變得更加簡單。
提示
我至今已經學了很多關於遊戲製作的知識,有些東西真的很難。
下面的事情你應該做好:
首先保持有條理。你應該對每一件事都有一個很好的整理,你的代碼,你的圖片,你的音效等等。我建議你把代碼根據用途放到不同的檔案中,比如說碰撞檢測放到一個檔案,資源管理放到另一個檔案,AI放到另一個檔案中......這樣做的話,如果你需要跟蹤一個bug,你會很容易找到對應的方法,還可能直接找到bug本身。保持代碼的了好結構同理(不同的類處理不同的事,渲染,AI,碰撞檢測等,而不是一口氣在一個類裡面寫上上百個方法)。
同時,努力讓代碼保持整潔和高效,儘可能重用變數,避免使用全域變數,檢查記憶體流失,不要一次性地載入所有的圖形和聲音等。
不要寫入程式碼資料到遊戲中,而是實現一個資料檔案載入系統,這將保持代碼的可維護行,並且當你想要升級的時候,不需要去編譯所有的檔案,
Chrisname的一些新手建議
你沒必要工作得那麼拚命,你需要做的是學習一套邊吃的教程。不要在一天之內做太多的東西,否則就會厭倦或者沒有動力。不要按時間設定目標,那沒用的。如果你在學習中半途而廢,你會忘掉你學的打部分的東西。把這個網址 ( http://cplusplus.com/doc/tutorial/ )上的教程都過一遍。目標是每天兩篇。不要在中途停下來(除非是確實需要休息一下),不要一次性做太多,否則你會記不住,我建議你仔細閱讀,並且去敲每一個例子(不是複製和粘貼,是自己親手敲進去,這會協助你瞭解代碼的含義),編譯並執行,看看發生了什麼變化,修改一下代碼,看看又有什麼改變。我還建議你看一下別人的優秀的代碼。當你在學習教程的時候,記住一件事-如果不能親口解釋清楚,就不算理解。
一旦你開始學習這篇教程或者其他的教程(我曾閱讀過同一主題的三篇教程,因為用不同的方式表述同一件事對理解和記憶都很有協助),你可以閱讀一下SFML的教程(http://sfml-dev.org/tutorials/1.6/),學習SFML將會教你如何做2d遊戲,我同樣推薦你學習SDL(http://lazyfoo.net/SDL_tutorials/index.php ),因為很多遊戲都用到了它,你最終也很可能完成。
之後,如果你想製作3D遊戲,你應當學習OpenGL,SFML把這變得十分簡單,SFML的教程中包含了使用OpenGL的教程,對於OpenGL或許這裡的其他人能給你推薦一些書或教程。
在整個過程中,你應該記住,掌握好自己的節奏很重要,不要一口氣吃成胖子,消化不了,第二天有考試的話,不要熬夜到半夜三點。
為了讓開發變得簡單,讓遊戲開發更加有效,你需要做的還有許多,但是這些是最重要的。
原文連結:http://www.cplusplus.com/articles/1w6AC542/