重慶分公司,新征程啟航
為企業提供網站建設、域名注冊、服務器等服務
為企業提供網站建設、域名注冊、服務器等服務
游戲開發的基本概念
若要進行游戲開發,首先要理解游戲的基本原理以及元素組成。在這一節中,我們將要介紹游戲的基本概念,包括游戲的流程控制,場景,層和精靈等。
場景與流程控制
游戲的主要流程
1.進入游戲,顯示游戲主菜單
2.選擇新游戲,開始教學任務或者第一個關卡
3.選擇載入游戲,繼續以前的游戲
4.選擇設置,調整游戲的聽覺或者視覺效果
通常,我們把內容相對不變的游戲元素集合稱做場景,而把場景之間的切換過程叫做流程控制
在Cocos2d-X中,場景的實現是CCScene.
層
層是屬于場景之下的游戲元素。通常,一個復雜場景會有很多個層,一個層會顯示一部分視覺元素,空白部分為透明或者半透明,以顯示多個層的重疊顯示。層與層之間按照順序疊加在一起,就組成了一個復雜的場景。也許,讀者接觸過Photoshop, 在這些編輯器中,也存在層的概念。在游戲設計中,層的概念與它們相似。
以捕魚游戲為例子,場景大致可以分為四層。
菜單層:懸浮于最上方的各種菜單項
觸摸層:處理在屏幕上的觸摸點擊時間
動作層:放置魚,×××,網等,并處理碰撞
背景層:背景圖片
精靈
層和場景是其他游戲的容器,如果沒有向它們添加可見的游戲元素,他們看起來就一直是透明的。精靈則與層或場景不同,它隸屬于層,是場景中可出現的可見
圖形。玩家控制的主角、AI控制的NPC,以及地圖上的寶箱、石塊,甚至游戲主菜單的背景圖片都是精靈。因此,可以這樣認為,玩家看到的一切都是精靈組成。
精靈不一定是靜態的。通常,一個精靈可以不斷變化,變化的方式包括:移動,縮放,旋轉,變形,顯示消失,動畫效果。精靈按照層次結合起來,并與玩家互動,
構成一個完整的游戲。
節點和渲染樹
回顧之前的介紹,我們已經知道了精靈、層和場景如何組成一個游戲的框架。精靈屬于層,層屬于場景,玩家和精靈互動,并導致游戲畫面在不同的場景中切換。
把每個環節拼接在一起,我們得到了完整的關系圖。
為了繪制場景,必須繪制層,為了繪制層,必須繪制精靈。因此,關系圖實質上安排了圖元的繪圖方式,關系圖中的每一個元素稱為節點,關系圖則稱為渲染樹。
渲染場景的過程就是遍歷渲染樹的過程。
一旦建立起渲染樹,組織復雜的場景就變得很簡單。我們賦予每個節點一系列屬性,包括節點相對于父節點的位置、旋轉角度、縮放比例、變形參數等。渲染樹的優勢在于,我們只需要考慮節點相對于父節點的屬性,就可以逐層創建復雜的對象或者動作。
動作與動畫
動作作用于游戲元素,可以使得游戲元素動起來。常見的動作有移動、閃動、消失等。動作分為瞬時動作和延時動作,持續性動作在一段時間內完成,瞬時動作在
瞬間完成。在Cocos2d-X中,動作由CCAction類實現,由CCAction類派生出來的持續性動作類CCActionInterval和CCActionInstant。所有的動作都派生自這兩個類
之一。
動畫animation是一種持續性動作,它只能應用于精靈上,用于實現幀動畫效果。如果電影膠片一樣,一個幀動畫由多張靜止的圖片不斷地切換形成。靜止的圖片叫做
幀(frame),幀的序列代表一個動畫效果。在Cocos2d-X中,我們可以使用多個幀創建幀動畫序列CCAnimation,并用幀動畫序列創建可以用于精靈的幀動畫CCAnimate
Cocos2d-X的代碼風格
命名空間與類名稱
Cocos2d-X的類都放置于Cocos2d命名空間下。以引擎目錄下的"actions/CCAction.h"為例子,我們可以看到文件的前面有兩個宏: NS_CC_Begin和NS_CC_END
類的命名與Cocos2d-iPhone一致,由類庫縮寫加上類名稱組成,其中類庫縮寫采用大寫,類名采用駝峰法。Cocos2d的縮寫是CC,所以Cocos2d-X的類都擁有CC
前綴,例如表示動作的類就叫做CCAction
構造函數與初始化
在Cocos2d-X中創建對象的方法和C++開發者的習慣迥乎不同.在C++中,我們只需要調用類的構造函數就可以創建一個對象,既可以直接創建一個棧上的值對象,
也可以使用new操作符創建一個指針,指向堆上的圖像。而在Cocos2d-X中,無論是創建對象的類型,還是創建對象的方法都與C++不同.
Cocos2d-X不使用傳統的值類型,所有的對象都創建在堆上,然后通過指針引用。創建Cocos2d-X對象通常有兩種方法:第一種是首先使用new操作符創建一個未初始化
對象,然后調用init系列方法來初始化;第二種是使用靜態的工廠方法直接創建一個對象。
在Object-C中并沒有構造函數,創建一個對象首先需要為對象分配內存,然后調用初始化方法來初始化對象,這個過程等價于C++中的構造函數.Cocos2d-X中的構造函數
并沒有參數,創建對象所需的參數通過init開頭的一系列初始化方法傳遞給對象。
初始化方法帶有一個bool值,表示是否成功初始化對象。比如一個從文件初始化精靈的例子
CCSprite* sprite = new CCSprite();
sprite->initWithFile("HelloWorld.png");
第二種方法則是使用類自帶的工廠方法來創建對象。在Cocos2d-X中,許多類會自帶一系列工廠方法,這些工廠方法是類提供的靜態函數。只要提供必要的參數,就會返回
一個完成了初始化的對象。通常init方法都有對應的工廠方法,它們參數一致,都可以用于創建對象。工廠的方法名稱統一為create,我們仍然以創建精靈為例子,
CCSprite * sprite2 = CCSprite::spriteWithFile("HelloWorld.png"); //舊版本方法
CCSprite * sprite3 = CCSprite::create("HelloWorld.png");
然而,在內存管理方面,還是有一點差異。使用構造函數創建的對象,所有權屬于創建者;而使用靜態工廠方法創建的對象并不屬于調用者。因此,使用構造函數創建的
對象需要調用者負責釋放,而工廠方法創建的對象則不需要。
在游戲中,我們需要不斷地創建新的游戲元素,通常采用的方法是從Cocos2d-X提供的游戲元素類派生出新的類,并在初始化方法中建立好我們所需的游戲元素.
比如在HelloWorld類中,我們從CCLayer派生出HelloWorld類,并重載了HelloWorld類的init方法,在這個方法中為HelloWorld類添加內容,為了保證初始化
方法可以被子類重載,需要確保初始化方法聲明為虛函數。
virtual bool init();
作為參數,我們提供一個典型的init方法框架
bool init()
{
if(CCLayer::init())
{
//此處添加初始化這個類所需的代碼
return true;
}
return false;
}
選擇器
在Object-C中,選擇器Selector是類似于C++中的類函數指針的機制。由于Cocos2d-X繼承了Cocos2d-iPhone的代碼風格,因此也提供了一系列類似于Object-C的
創建選擇器語法的宏,用來創建函數指針。這些宏只有一個參數SELECTOR,表示被指向的類方法。將這些宏列舉如下
schedule_selector( SELECTOR )
callfuncN_selector( SELECTOR )
callfuncND_selector( SELECTOR )
callfunc_selector( SELECTOR )
menu_selector( SELECTOR )
event_selector( SELECTOR )
compare_selector( SELECTOR )
下面我們來看HelloWorld例子,在這個例子中,我們在HelloWorld類的init方法中添加了一個菜單,當用戶點擊菜單時候,就會觸發此類中的menuCloseCallback()
方法。可以看到初始化菜單的后兩個參數分別是被調用對象與Cocos2d-X選擇器
CCMenuItemImage *pCloseItem = CCMenuItemImage:: create(
"CloseNormal.png", "CloseSelected.png", this, menu_selector(HelloWorld::menuCloseCallback));
屬性
C++的類成員只有方法與字段,沒有屬性和事件,這給開發者帶來不便。Cocos2d-X 使用get和set方法來模擬。
在Cocos2d-X中,CCNode包含大量屬性,比如給節點做標記的Tag屬性,它的訪問其分別是getTag()和setTag()
其實現原理大致如下:
int tag;
void getTag() { return tag; }
void setTag(int aTag) { tag = aTag; }
給每一個屬性編寫一個或者多個訪問器的方法是一項非常枯燥的任務,為了避免重復性的工作,Cocos2d-X提供了一系列宏來幫助我們方便地創建
屬性,他們定義在 "platform / CCPlatformMacros.h" 中。
CC_PROPERTY 定義了一個屬性及其訪問器,沒有實現。通常用于簡單的值類型
CC_PROPERTY_READONLY 定義了一個屬性,只包含get訪問器,沒有實現
CC_PROPERTY_PASS_BY_REF 定義了一個屬性,訪問器使用引用傳遞參數,沒有實現,通常用于結構體類型
CC_PROPERTY_READONLY_PASS_BY_REF 定義了一個屬性,只包含get訪問器,且使用引用類型傳遞參數,沒有實現
CC_SYNTHESIZE 同CC_PROPERTY, 實現了訪問器方法
CC_SYNTHESIZE_READONLY 同CC_PROPERTY_READONLY, 實現了訪問器方法
CC_SYNTHESIZE_PASS_BY_REF 同CC_PROPERTY_PASS_BY_REF,實現了訪問器方法
CC_SYNTHESIZE_READONLY_PASS_BY_REF 同CC_PROPERTY_READONLY_PASS_BY_REF,實現了訪問器方法
CC_SYNTHESIZE_RETAIN 同CC_PROPERTY, 實現了訪問器方法, 由于派生自CCObject類型,訪問器采取Cocos2d-X的內存管理機制自動維護對象的引用計數。
這些宏只要寫在類定義中就可以了。每個宏有三個參數,分別是:
@ varType 屬性類型,如果屬性類型是對象,需要寫成指針的形式
@ varName 屬性的私有字段名稱
@ funName 屬性的訪問器名稱,也就是緊接在get或者set前綴后的部分
利用Cocos2d-X提供的宏,CC_SYNTHESIZE(int, tag, Tag)
就實現了
int tag;
int getTag( ) { return tag; }
void setTag( int aTag ) { tag = aTag; }
確實很方便
單例
單例模式保證了全局有且只有一個對象,保證自動初始化該對象,使得程序在任何時候都可以訪問,獲取該對象。比如CCDirector:
CCDirector:: sharedDirector()->replaceScene( newScene );
這條語句利用CCDirector:: sharedDirector( ) 獲取CCDirector的唯一實例,然后調用replaceScene來切換場景
內存管理
暫時跳過
工廠方法
基類中只定義創建對象的接口,將實際的實現推遲到子類。在這里,我們對它稍加推廣,泛指一切生成并返回一個對象的靜態函數。
CCObject * factoryMethod( )
{
CCObject *ret = new CCObject( );
// 在這里對ret對象進行必要的初始化操作
ret->autorelease( );
return ret;
}
對象傳值
將一個對象賦值給某一個指針作為引用的時候,為了遵循內存管理的原則,我們需要獲得新對象的引用權,釋放舊對象的引用權。此時,
release() 和 retain() 的順序就非常重要。
看下面一段代碼
void SomeClass::setObject(CCObject * other)
{
this->object->release();
other->retain();
this->object = other;
}
這里存在的隱患在于,當other和other實際指向同一對象的時候,第一個release()可能會觸發該對象的回收,這顯然不是我們想看到的局面,
所以應該先執行retain()來保證other對象有效,然后再釋放舊對象。
void SomeClass::setObject(CCObject * other)
{
other->retain();
this->object->release();
this->object = other;
}
其他可行的方法也還有很多,比如使用autorelease()方法來代替release(),或者在賦值之前判斷兩個對象是否相等。在Object-C編程規范中,
推薦使用autorelease()方法代替release()方法。
release( ) 還是 autorelease( ) ?
容器
CCArray & CCDictionary Object-C 風格
Cocos2d-X 引擎為我們提供了CCArray, CCDictionary 等Object-C風格的容器。
使用這些容器的一個重要原因在于Cocos2d-X的內存管理。
class CC_DLL CCAray: public CCObject
{
public:
~CCArray();
bool initWithObjects(CCObject *pObject, ...);
}
我們應該盡量使用Cocos2d-X提供的容器類.
相關輔助宏
引用計數很奇妙也很方便,但是大部分處理過程涉及到指針,難免比較繁瑣,也容易出錯。針對這個問題,Cocos2d-X為我們準備了一系列輔助宏來簡化代碼,
這些宏的頭文件包含在"CCPlatformMacro.h"中。下面列出了和內存管理相關的宏。
CC_SAFE_DELETE(p) delete p
CC_SAFE_DELETE_ARRAY(p) delete [] p
CC_SAFE_FREE(p) free p
CC_SAFE_RELEASE(p) release( )方法釋放
CC_SAFE_RELEASE_NULL(p) release( ) + p = null
CC_SAFE_RETAIN(p) p->retain( ) 如果p為null, 則不操作
Cocos2d-X 的內存管理原則
程序段必須成對執行retain()和release()或者執行autorelease()來聲明和結束對象的引用。
工廠方法返回前,應該通過autorelease()結束該對象的引用
對象傳值時候,應該考慮新舊對象相同的特殊情況
盡量使用release()而不是autorelease()來釋放對象引用,以確保性能最優秀
保存CCObject子對象時候,應該嚴格使用Cocos2d-X提供的容器,避免使用STL容器,對象必須以指針形式傳入
另外有需要云服務器可以了解下創新互聯scvps.cn,海內外云服務器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務器、裸金屬服務器、高防服務器、香港服務器、美國服務器、虛擬主機、免備案服務器”等云主機租用服務以及企業上云的綜合解決方案,具有“安全穩定、簡單易用、服務可用性高、性價比高”等特點與優勢,專為企業上云打造定制,能夠滿足用戶豐富、多元化的應用場景需求。