創作內容

3 GP

[程式設計] 戰鬥流程管理設計 for 多陣營

作者:夜下月│2013-03-11 18:26:29│巴幣:6│人氣:506
無聊寫的小東西  是以c/c++寫出來的演算法設計
有興趣的看完可以討論

以大型MMORPG來說好了  
一張地圖通常就是一個地圖伺服器  通常需要同時管理上千個單位的行動

假設目前有RED, YELLOW, BLUE  3種陣營
陣營之間會有不同的關係
(ex: R<->R 友好,  R<->Y  敵隊,  R<->B  中立)
這樣的多陣營設計 最常在RPG遊戲中出現
所以通常會有一張陣營表去紀錄 陣營之間的關係

而在搜敵的過程中, 因為遇到的對象無法預期
所以自然也不會知道 對方的陣營是什麼
因此只能一個一個作陣營關係比較

所以在搜敵時就要比較N次  所以N越大 花費的時間就越多

//-----------------------------------------------------define -----------------------------------------------//

enum CampType  //定義有哪些陣營
{
        CAMP_RED = 0,
        CAMP_YELLOW,
        CAMP_BLUE,

        CAMP_TYPE
}

enum Relationship //定義有哪些關係
{
        FRIENDLY = 0,   //友善
        NEUTRAL,          //中立
        HOSTILITY,         //敵對
        
        CAMP_COUNT
}

//設定 陣營關係  並且定為常數 避免被修改
const Relationship vCampResult[CAMP_TYPE][CAMP_TYPE] =   {
        {  FRIENDLY, HOSTILITY, NEUTRAL  },  //紅隊的陣營關係
        {  FRIENDLY, HOSTILITY, HOSTILITY  },  //黃隊的陣營關係
        {  FRIENDLY, FRIENDLY, FRIENDLY  },  //藍隊的陣營關係
};

//----------------------------------------------------------------------------------------------------------//

srand (time(NULL));  //依當前時間設定亂數種子
vector<Unit*> vUnitGroup; //建立1個容器 管理所有單位

for(int i = 0; i<3000; i++)
{
        //產生隨機陣營的單位  並加入排程管理中
        vUnitGroup.push_back( &Unit( rand()%CAMP_COUNT ) );  
}

while(true)
{
        vector<Unit*>::iterater iter;
        for(iter = vUnitGroup.begin(); iter != vUnitGroup.end(); ++iter)
        {
                Unit* pUnit = *iter;
                if( pUnit->isDead() )//掛了
                {
                        vUnitGroup.earse( iter );  //掛了就從排程中移除
                        //多陣營 通常不會有勝負結果   排程要永久執行
                        iter--;
                }
                else  //還活著
                {
                        if( pUnit->isAttack() )  //戰鬥中
                        {
                                pUnit->attackTarget();//攻擊當前目標
                        }
                        else
                        {
                                float fEnemyDis(-1);  //單位與敵方的距離
                                Unit* pTarget(NULL), pEnemy(NULL);

                                //取得單位鎖敵範圍
                                float fSearchRange = pUnit->getSearchRange();
                                
                                //與雙陣營的判斷差異  要從整個排程中撈資料作比對
                                vector<Unit*>::iterater tmp_iter;
                                for( tmp_iter = vUnitGroup.begin();
                                        tmp_iter != vUnitGroup.end(); ++tmp_iter)
                                {
                                        pTarget = *tmp_iter;
                                        //指標存在 且 對象不等於自己 且兩者關係是敵對的
                                        if( pTarget != NULL && pTarget  != pUnit  
                                                && pUnit->getRelationship( pTarget ) == HOSTILITY )  
                                        {
                                                float tmpDis = pUnit->getDis( pTarget  );  //取得兩者距離
                                                if( tmpDis <= fSearchRange ) //目標在鎖敵範圍內
                                                {
                                                        //尋找最近距離最近的
                                                        if( fEnemyDis < 0 || tmpDis < fEnemyDis )                                                                          {
                                                                fEnemyDis = tmpDis;
                                                                pEnemy = pTarget;
                                                        }
                                                }
                                        }
                                }  //end 敵人搜尋

                                if(pEnemy )//有攻擊目標
                                {
                                        pUnit->setAttackTarget(pEnemy);//設定攻擊目標
                                }
                                else
                                {
                                        pUnit->move();//沒事 自己走自己
                                }
                        }//end 非戰鬥
                }//end 還活著
        }//end  排程管理

        sleep(1000);
}

//---------------------------------------------------------------------------------------------------------------//

為了改善上面遇到的問題
可以導入另一個設計概念
將地圖作區域劃分

假設天堂1(Lineage)  整個遊戲單位都在同一個server中
但server依照區域 將單位另外管理 分配到對應的區域中
(ex: 古魯丁村, 風木沙漠, 奇岩城...etc )
所以在作搜敵比較時  自然就會比較有效率
因為通常不會所有的單位 都在同一個區域內

以下這邊直接將上面的程式碼作改寫

//--------------------------------------------------------------------------------------------------------------//

enum Zone  //增加區域的列舉
{
        ZONE_Talking_Island = 0,  //說話之島
        ZONE_Gludio,             //古魯丁村
        ZONE_Kent_Castle,          //肯特城
        ZONE_Windawood,          //風木

        ZONE_COUNT
}

typedef std::vector<Unit*> VP_UNIT;  //透過typedef 將型別名稱 縮短

srand (time(NULL));  //依當前時間設定亂數種子
VP_UNIT vUnitGroup; //建立一個vector 管理所有單位
map<Zone, VP_UNIT> mapZoneGroup;  //建立一個map 管理區域單位數量

for(int i = 0; i<3000; i++)
{
        Unit tmp = Unit ( rand()%CAMP_COUNT ); //產生隨機陣營的單位
        vUnitGroup.push_back( &tmp );  //產生隨機陣營的單位  並加入排程管理中
        mapZoneGroup[ rand()%ZONE_COUNT ].push_back( &tmp ); //將單位丟到隨機區域內
}

while(true)
{
        VP_UNIT::iterater iter;
        for(iter = vUnitGroup.begin(); iter != vUnitGroup.end(); ++iter )
        {
                Unit* pUnit = *iter;
                if( pUnit->isDead() )//掛了
                {
                        vUnitGroup.earse( iter );  //掛了就從排程中移除
                        //多陣營 通常不會有勝負結果   排程要永久執行
                        iter--;
                }
                else  //還活著
                {
                        if( pUnit->isAttack() )  //戰鬥中
                        {
                                pUnit->attackTarget();//攻擊當前目標
                        }
                        else
                        {
                                float fEnemyDis(-1);  //單位與敵方的距離
                                Unit* pTarget(NULL), pEnemy(NULL);

                                //取得單位鎖敵範圍
                                float fSearchRange = pUnit->getSearchRange();
                                
                                //與雙陣營的判斷差異  要從整個排程中撈資料作比對
                               VP_UNIT::iterater tmp_iter;
                               Zone zoneID = pUnit->getZoneID();

                               //取得自己所在的區域ID 並透過區域ID 取得所在區域的所有單位
                               for( tmp_iter = mapZoneGroup[zoneID].begin();
                                        tmp_iter != mapZoneGroup[zoneID].end(); ++tmp_iter )  
                                {
                                        pTarget = *tmp_iter;
                                        //指標存在 且 對象不等於自己 且兩者關係是敵對的
                                        if( pTarget != NULL && pTarget  != pUnit  
                                                && pUnit->getRelationship( pTarget ) == HOSTILITY )
                                        {
                                                float tmpDis = pUnit->getDis( pTarget  );  //取得兩者距離
                                                if( tmpDis <= fSearchRange ) //目標在鎖敵範圍內
                                                {
                                                        //尋找最近距離最近的
                                                        if( fEnemyDis < 0 || tmpDis < fEnemyDis )
                                                        {
                                                                fEnemyDis = tmpDis;
                                                                pEnemy = pTarget;
                                                        }
                                                }
                                        }
                                }  //end 敵人搜尋

                                if(pEnemy )//有攻擊目標
                                {
                                        pUnit->setAttackTarget(pEnemy);//設定攻擊目標
                                }
                                else
                                {
                                        pUnit->move();//沒事 自己走自己
                                }
                        }//end 非戰鬥
                }//end 還活著
        }//end  排程管理

        sleep(1000);
}

//------------------------------------------------------------------------------------------------------------//
引用網址:https://home.gamer.com.tw/TrackBack.php?sn=1931946
All rights reserved. 版權所有,保留一切權利

相關創作

同標籤作品搜尋:程式設計|C++|c/c++

留言共 1 篇留言

StillDream
雖然不是很了解c++,也有點看不懂,不過這部份滿實用的…

03-17 23:57

夜下月
這講的是設計結構 所以不限定用C/C++寫 用JAVA一樣可以做到03-18 03:00
我要留言提醒:您尚未登入,請先登入再留言

3喜歡★ponderzs 可決定是否刪除您的留言,請勿發表違反站規文字。

前一篇:[遊戲] 模擬城市5 購... 後一篇:[程式設計] Recou...

追蹤私訊切換新版閱覽

作品資料夾

Waterfall10絕大部份巴友
金庸武俠穿越同人《何妨吟嘯且徐行》,逍遙二仙少年時的歷險,歡迎到我的小屋瀏覽 ~看更多我要大聲說昨天20:21


face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情⋯ 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】