Cocos實戰篇[3.4]——仿COC的一個小Demo總結

【嘮叨】

    今天結束了本學期任務最爲艱鉅的項目實訓課程,由於項目組裏其他成員基本都已經找到實習了,然後他們都去實習了。只留下我和一個小夥伴在一起搞項目實訓的小遊戲。經過一個月與小夥伴的配合開發,做了一個勉強可以玩的一個小遊戲demo,因爲平時其他課程也比較繁重,所以遊戲做得非常爛~(>_<)~。

    我們本來打算做一款類似COC、海盜奇兵、口袋侏羅紀、城堡爭霸的城戰類的單機Demo。結果……哎說多了都是淚啊,經驗不足,吸取教訓了。


【經驗教訓】

    由於時間比較緊張,加上自身也沒有大項目開發的經驗,所以一開始沒有太重視去考慮遊戲整體架構的問題,都是寫一點算一點,從而在開發到一半,發現很多代碼沒有做到複用,而是一直複製張貼的。然後後期也沒有時間去重構,結果導致代碼寫得比較凌亂不堪。

【收穫】

    雖然做的效果沒有達到預期,但是還是從項目實訓中有非常多的收穫的。

    1、再一次學習了一遍C++,對C++有了更深入的瞭解。

    2、提前學習了各種文件讀取解析的方式:JSON、XML、CSV、Sqlite。(最後我們採用了CSV來存儲靜態數據,用Sqlite來存儲玩家數據)。

    3、掌握了遊戲開發的一些基本流程。

    4、學習和掌握了cocos2d-x遊戲引擎,cocos studio界面編輯器。

    5、掌握了觀察者模式委託模式的運用。

    6、學習了遊戲的自動尋路的A*算法


【項目Demo】

    代碼寫的比較爛,但是我依然又放到了guthub上,只是爲了想要存儲我寫的每一份代碼。

    因爲放在本地硬盤,需要佔存儲空間的。~~~~(>_<)~~~~ 。

    代碼託管:https://github.com/shahdza/Cocos_Ring


【成果演示】

    做得挺爛的,大家看了不要噴。。。

    素材均來自《城堡爭霸》,本遊戲只做學習研究,切勿商用,以免侵權。。。

    遊戲概述:

        1、玩家城池:可以移動設施、升級設施、新建設施、管理士兵、管理英雄。

        2、關卡戰鬥:可以派出士兵自動尋路***,可以控制英雄移動,***指定建築,釋放技能。

        3、戰略地圖通過迷霧遮罩,升級雷達,可以擴大地圖的可視範圍。

    視頻鏈接:http://v.youku.com/v_show/id_XOTM0NzQ3NDQ4.html


【開發環境】

    Cocos2d-x 3.4

    Cocos Studio 1.6.0 (UI編輯器、動畫編輯器)




【一些重要的收穫】


1、分辨率適配問題

    由於地圖比較大,可以通過拖動來顯示地圖的其他區域部分,所以分辨率的適配比較簡單。只要寬度或高度適配即可。


2、地圖的移動與縮放

    可以參見這篇文章:http://cn.cocos2d-x.org/tutorial/show?id=1479

    根據手指觸摸的數量,來判斷是移動還是縮放。

    > 一根手指:移動地圖,實現比較簡單。

    > 兩根或多根手指:看做兩根手指,縮放地圖。需要通過一定的公式來計算,縮放前和縮放後的座標轉換。(具體參見上述文章)。

    對於手指滑動後,地圖又具有慣性地減速移動:可以根據手指滑動的速度快慢,計算出一個加速度(其實可以通過觸摸事件onTouchMoved中Touch的getDelta()函數獲得),然後通過在update函數中進行減速計算。

    縮放的前後座標計算,如下圖所示:

wKiom1UuVT6zaSwTAADJCSJ7bP4141.jpg

wKiom1UuVT6gVXN9AAERd-PyU80724.jpg


3、玩家城池中,建築的座標定位

    對於45°座標,可以參照這篇文章:http://blog.sina.com.cn/s/blog_6807f539010103ce.html

    由於城池中採用的是斜45°的2.5D視角,所以需要進行座標的轉換操作。

    先將城池地圖進行瓦片分割,分成一塊一塊區域。如下所示,其實可以看到地圖是一個個小方塊組成的。

wKioL1UuWEGTaNIIAAaR-b3RR_A526.jpg


4、關於建築的觸摸移動

    當建築需要移動它的位置的時候,需要屏蔽地圖層的移動和縮放,不然你回發現你的建築和地圖都在移動!!!

    做法是:觸摸到建築,進行移動時,其實cocos已經有了觸摸吞噬的函數

listener->setSwallowTouches(true);即可。

    當然還有一種比較好的做法是:定義一個專門處理觸摸事件的觸摸層,來管理場景中所有元素的觸摸事件,並按照觸摸的優先級進行排序,然後再按照優先級進行分發觸摸響應事件(因爲一般觸摸只會有一個事件作出響應,也就是說每次的觸摸只會有一個元素執行了觸摸事件)。


5、關於設施升級、時間點觸發某事件等一系列的響應事件

    在設施進行升級、或者當到大某一時間點時,可能需要觸發一些任務響應事件。可以通過委託模式來處理,即在做某一事件時,給該事件委託一個函數(可以通過函數指針來實現)。然後當某一事件完成後,調用該委託函數(可以不指定爲某一特定的函數,而是通過函數指針的形式來調用)。

    另一種做法是:通過觀察者模式,即一個事件對某一消息進行訂閱,然後另一個事件在執行完後,發佈該消息,然後第一個事件就接受到了消息,執行相應的處理函數。

    例如:士兵***建築時,士兵執行完***動作,然後建築需要作出“扣血”這一事件。就可以通過委託函數來完成,即實現不知道需要執行哪個建築的“扣血”事件。而是通過函數指針來調用對應士兵所***的那個建築的“扣血”事件處理函數。

    至於觀察者模式可參見:http://shahdza.blog.51cto.com/2410787/1611575


6、對於遊戲中時間控制的問題

    因爲是一個城戰類的遊戲,所以設施的升級是需要一定的時間的,比如升級需要10分鐘。還有採礦場每分鐘可以生產10個金幣等等,都是需要用到“時間”。

    做法是:拿設施的升級操作舉例,在點擊對設施進行升級時,可以記錄一個升級時的“時間戳”,並存儲到數據庫的該設施的一個字段中,然後再遊戲進行的過程中,只要不斷獲取當前時間的“時間戳”,然後減去之前記錄的點擊升級時的“時間戳”。差值即爲從升級到目前過去了多少時間,然後就可以做一些列的操作了。

    關於如何獲取時間戳,參見:

// 獲取時間戳
int GlobalManager::getTimeStamp()
{
    timeval tm;
    gettimeofday(&tm, NULL);
    return tm.tv_sec; // 返回當前時間對應的時間戳,單位:秒
}


7、戰鬥界面的AI(自動尋路、自動***)

    也可以參見:http://cn.cocos2d-x.org/tutorial/show?id=1638

    我的做法比較簡單,使用狀態機:移動、***、閒置、已陣亡然後每隔0.5秒執行一次狀態轉換的操作。

    首先將地圖分成一塊一塊,然後用二維bool矩陣來標記障礙物,然後控制士兵、英雄的移動。

    > 對於士兵:設置定時器,每隔0.5秒執行一次動作。若士兵還未鎖定***目標,則遍歷設施,找到最近的設施作爲目標。若士兵鎖定了***目標,則可以通過A*算法檢測上下左右、左上、右上、左下、右下八個方向的瓦片格子中,是空地,並且裏目標建築最近的,就將士兵往那個格子移動(至於距離:可以通過h函數來估計,我採用的是估計函數:曼哈頓距離,即x座標之差的絕對值 + y座標之差的絕對值),這樣士兵可以自動繞過障礙物。若目標設施在士兵的可***範圍內,則對設施進行***。

    我爲什麼要嘗試每隔一定時間,檢測士兵的八個方向,離目標最近,然後移動過去呢?是因爲如果士兵鎖定了目標後,然後執行完整的A*算法,計算出完整的移動路徑,這樣的操作是非常耗時的。對於很多個士兵同時執行完整的A*算法進行尋路,可能就會出現卡頓的現象。而我的做法正好避免了這樣的問題,將A*算法的每一步操作都均攤到每個0.5秒的時間。

    > 對於英雄:通過觸摸來控制移動,和***某一目標。觸摸地圖某一位置,英雄移動的操作與士兵的自動尋路和自動***思路類似。

    > 對於可***型建築:設施定時器,每個0.5秒執行一次。遍歷我方士兵、英雄。若有士兵在建築的可***範圍內,則***我方。


8、頭文件的管理

    由於類和類之間不是獨立存在的,必然會有頭文件的相互引用問題,所以我就額外將所有的類的頭文件都放到一個public.h文件中,那麼其他類只要引用"public.h"頭文件即可,而不需要考慮需要引用哪些哪些頭文件。

wKiom1UuZBHhmQQzAAHTU9MDijs760.jpg        wKioL1UuZWTTC5uMAAIZROlsClo435.jpg

    然後在 public.h文件開頭加上文件預編譯指令:這樣就可以保證頭文件不會被多次編譯。

#ifndef __Public_H__
#define __Public_H__

#endif


9、全局變量的管理

    也是當獨放到一個頭文件中進行管理的:包含了圖片資源的路徑、一些全局變量、數據文件的路徑等。

    

wKioL1UuZezAwGT2AALEUE42dU0006.jpg

wKiom1UuZJug3jSdAASN7zAMEcE983.jpg


10、CocosStudio的使用

    本遊戲用的時Cocos Studio 1.6.0版本。其實這個版本是已經非常強大了,不僅可以做界面UI,而已可以製作角色動畫。

    使用方法:到官網學習。


11、數據的管理

    寫了一個專門管理遊戲數據的單例類DataManager。用於數據的加載、獲取、更新等操作。

    對於表現層和控制層有哪些數據修改的請求操作,都通過DataManager進行管理,然後再重新繪製遊戲的UI。

wKioL1UuZw_wWdYVAALIo_YgQeQ850.jpg


12、一些全局的輔助函數的管理

    也是用了一個GlobalManager單例類來進行管理。提供遊戲中的相關的輔助函數。

    如:獲取最大最小值、地圖座標與瓦片座標的轉換、判斷一個點是否落在多邊形內、獲取時間戳、整形數據和字符串數據的轉換、場景的切換管理等功能。

wKioL1UuZ5bASndqAANMgh_AhnA323.jpg




【遇到的問題】


1、瓦片座標與地圖座標的轉換

    計算相應的轉換公式。


2、兩頭文件相互引用

    需要在類之前,對另一個類做類的聲明。


3、野指針問題

    當兩個建築都鎖定同一個士兵後,第一個建築執行完***動畫,然後讓該士兵作出扣血事件,正好士兵血沒了,就要從圖層中移除。可是呢?第二個建築也鎖定了該目標啊,執行玩***動畫後,調用該士兵的扣血事件,出現了異常。因爲該士兵已被釋放。。。

    解決方案:

    (1)一直保留士兵,陣亡後,不從圖層中移除,而是將士兵隱藏。

    (2)延遲士兵的移除操作。由於建築是每個0.5秒尋找一次目標,然後對其進行***。那麼我們只要在士兵陣亡後,用一個變量isDeath來標記士兵是否陣亡,然後建築在遍歷士兵時,跳過isDeath=true的士兵,那麼建築在下一個0.5秒就不會再指向該士兵。那麼士兵只要在陣亡後,標記isDeath=true,然後延遲1秒鐘後,調用remove()函數從圖層中移除,就不會出現野指針異常的問題。

    (3)同樣也可以通過觀察者模式,建築對士兵的陣亡消息進行訂閱,然後當士兵陣亡後,發佈陣亡消息。建築在接收到陣亡消息後,將鎖定的目標target指針置爲空NULL,即可。


4、中文亂碼問題

    使用UTF-8即可。


5、遊戲AI問題

    學習了A*算法。


6、還有其他一些小問題,已忘………………



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章