無聊寫的小東西 是以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);
}
//------------------------------------------------------------------------------------------------------------//