教你如何製作怪物智慧AI(轉)
轉自:http://cocos2d.9tech.cn/news/2013/1112/38577.html
談到怪物AI,我覺得就比較話多了,首先理解一下(Artificial Intelligence人工智慧),人工智慧是電腦科學的一個分支,人工智慧是計算機科學技術的前沿科技領域。人工智慧與計算機軟體有密切的關係。各種人工智慧應用系統都要用計算機軟體去實現,許多聰明的計算機軟體也應用了人工智慧的理論方法和技術。
總而言之,言而總之,我理解的AI就是:用人類自己的思考模式去賦予遊戲中角色判斷的能力,來進行某些特定的行為!
下面具體圖文介紹一下,我在遊戲中一些實用的AI製作思路。
這是這個思路就可以讓怪物捕獲玩家,並且追蹤玩家攻擊的一個圖示!這個思路是基本,最終決策怪物是否去執行這個行為的操作演算法又是一個AI智慧,所以咱們又可以分為:
決策AI:可以根據怪物等級,怪物的型別(BOSS),怪物技能型別等很多決策和根本屬性相連所起作用的操作,都可以做成決策AI;
行為AI:追蹤玩家,攻擊玩家,給玩家加血(如同伴),逃跑等這些行為動作操作;
OK,下面大家應該瞭解AI的基本思路了,那我們直接貼程式碼了;
我直接把AI寫在了地圖層裡面了,因為之前我框架的設計,是有一個地圖base,而所有的怪物,主角色,NPC都屬於地圖層,因為要做很多遍歷操作,所以在地圖base中寫上智慧AI演算法,然後再繼承拓展下來。
首先先製造一群怪物!並且讓怪物在設定的Rect內隨機移動!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/********************************************
註釋:
makenum 最大怪物數量
monsteridtags 怪物起始標籤
randomrange 配置怪圈大小(只能填正整數)
monster_model 怪物資料
yinzihigth 影子的距離
fristpoint 怪物初始設定的怪圈點
*********************************************/
void Maps_Diyu::makemonster(int makenum,int monsteridtags,CCPoint randomrange,MainRoledata monster_model,int yinzihigth,CCPoint fristpoint) {
for (int i = 0; i < makenum; i++)
{
int add_x = (int)(CCRANDOM_MINUS1_1()*randomrange.x);
int add_y =(int)(CCRANDOM_MINUS1_1()*randomrange.y);
monster_model.tags=monsteridtags+i;
monster_model.nowpoint= CCPointMake(nowmap->getContentSize().width/2+fristpoint.x+add_x,nowmap->getContentSize().height/2+fristpoint.y+add_y);
SpiritsMonster* newmonster = new SpiritsMonster(monster_model,1,yinzihigth);
nowmap->addChild(newmonster->monster, 1,monsteridtags+i);
}
}
|
然後處理怪物的行為AI:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
/********************************************
註釋:
monsternum 最大怪物數量
monsteridtags 怪物起始標籤
monster_model 怪物資料
reatR 怪物仇恨視角的範圍值(通常200左右)
attck_reatR 怪物可攻擊範圍值(遠端怪和物理怪物)
playerpoint 主角座標
randomrange 怪物預設隨機移動範圍
fristpoint 怪物初始設定的怪圈點
*********************************************/
void Maps_Diyu::attact_todo(int monsternum,int monsteridtags ,MainRoledata monster_model,int reatR,int attck_reatR,CCPoint playerpoint,CCPoint randomrange,CCPoint fristpoint)
{
for (int i = 0; i < monsternum; i++)
{
CCRect* attck_rect = new CCRectMake( this ->getChildByTag(monsteridtags+i)->getPosition().x-attck_reatR/2, this ->getChildByTag(monsteridtags+i)->getPosition().y-attck_reatR/2,attck_reatR,attck_reatR);
if (attck_rect->containsPoint(playerpoint)== true )
{
//執行怪物攻擊主角
CCLog(FontChina::G2U( "進入怪物可攻擊範圍" ));
//攻擊時改變方向
SpiritsMonster::attackTomainRole_dir(ccp((int)playerpoint.x,(int)playerpoint.y),(CCSprite*)( this ->getChildByTag(monsteridtags+i)),monster_model);
//釋放技能動畫
int add_x = (int)(CCRANDOM_MINUS1_1()*8);
int add_y =(int)(CCRANDOM_MINUS1_1()*8);
SkillEffects* skill = new SkillEffects(ccp((int)playerpoint.x+add_x,(int)playerpoint.y+add_y),monster_model,(0.2f+CCRANDOM_0_1()),8,3,1000);
this ->addChild(skill->effects_main,1000,50);
}
else
{
CCRect* track_rect = new CCRectMake( this ->getChildByTag(monsteridtags+i)->getPosition().x-reatR/2, this ->getChildByTag(monsteridtags+i)->getPosition().y-reatR/2,reatR,reatR);
if (track_rect->containsPoint(playerpoint)== true )
{
//執行移動,不停追殺主角
CCLog(FontChina::G2U( "進入怪物仇恨視野區域" ));
//防止靠近主角,保持一定距離!主要為了好看和處理被攻擊效果。
int add_x = (int)(CCRANDOM_MINUS1_1()*25);
int add_y =(int)(CCRANDOM_MINUS1_1()*25);
//移動時改變方向
SpiritsMonster::moveTomap_dir(ccp((int)playerpoint.x,(int)playerpoint.y),(CCSprite*)( this ->getChildByTag(monsteridtags+i)),monster_model);
CCArray* callbackArray = CCArray::create();
int nowtags = monsteridtags+i;
char strs[64];
sprintf(strs, "%d" ,nowtags);
CCString* ccnowtags = CCString::create(strs);
callbackArray->addObject(ccnowtags);
callbackArray->addObject(monster_model.spiritname);
char dir_x[64];
sprintf(dir_x, "%d" ,(int) this ->getChildByTag(nowtags)->getPositionX());
char dir_y[64];
sprintf(dir_y, "%d" ,(int) this ->getChildByTag(nowtags)->getPositionY());
CCString* d_x = CCString::create(dir_x);
CCString* d_y = CCString::create(dir_y);
callbackArray->addObject(d_x);
callbackArray->addObject(d_y);
CCFiniteTimeAction *actbackfun = CCCallFuncO::create( this , callfuncO_selector(Maps_Diyu::moveoverCallBack),callbackArray);
CCActionInterval* act_movexixue = CCMoveTo::create(3+CCRANDOM_MINUS1_1(),ccp((int)playerpoint.x+add_x,(int)playerpoint.y+add_y));
this ->getChildByTag(nowtags)->runAction(CCSequence::create(act_movexixue,actbackfun,NULL));
}
else
{
//脫離仇恨時,隨機定點周圍移動
int stopandrun = (int)(CCRANDOM_MINUS1_1()*10);
if (stopandrun>=1)
{
//脫離仇恨
int add_x = (int)(CCRANDOM_MINUS1_1()*randomrange.x);
int add_y =(int)(CCRANDOM_MINUS1_1()*randomrange.y);
CCPoint move_dir = ccp( this ->getContentSize().width/2+fristpoint.x+add_x, this ->getContentSize().height/2+fristpoint.y+add_y);
SpiritsMonster::moveTomap_dir(ccp((int)move_dir.x,(int)move_dir.y),(CCSprite*)( this ->getChildByTag(monsteridtags+i)),monster_model);
CCArray* callbackArray = CCArray::create();
int nowtags = monsteridtags+i;
char strs[64];
sprintf(strs, "%d" ,nowtags);
CCString* ccnowtags = CCString::create(strs);
callbackArray->addObject(ccnowtags);
callbackArray->addObject(monster_model.spiritname);
char dir_x[64];
sprintf(dir_x, "%d" ,(int) this ->getChildByTag(nowtags)->getPositionX());
char dir_y[64];
sprintf(dir_y, "%d" ,(int) this ->getChildByTag(nowtags)->getPositionY());
CCString* d_x = CCString::create(dir_x);
CCString* d_y = CCString::create(dir_y);
callbackArray->addObject(d_x);
callbackArray->addObject(d_y);
CCFiniteTimeAction *actbackfun = CCCallFuncO::create( this , callfuncO_selector(Maps_Diyu::moveoverCallBack),callbackArray);
CCActionInterval* act_movexixue = CCMoveTo::create(3+CCRANDOM_MINUS1_1(),ccp(move_dir.x,move_dir.y));
this ->getChildByTag(nowtags)->runAction(CCSequence::create(act_movexixue,actbackfun,NULL));
}
}
}
}
}
|
這段邏輯包括了,如果玩家進入怪物的仇恨區域,那麼怪物會先移動到玩家附近的點(此時玩家移動開,怪物會根據定時器去判斷下一步如何操作:如1,玩家移動後還在仇恨區域,那麼繼續追蹤玩家;2,如果玩家脫離仇恨,那麼怪物執行回到初始座標點的操作,然後繼續原地巡邏!),如果此時玩家已經在怪物的攻擊範圍內了,那麼怪物會直接選擇攻擊!這樣怪物就會變得貌似有了思想一樣,他會去考慮判斷各種行為,那個區域我該做什麼?不該做什麼?
有了這個邏輯,我們還要賦予怪物迴圈思考的能力!
1 2 |
//啟動所有怪物智慧AI監聽器
nowmap->schedule(schedule_selector(Maps_Diyu::makemonsterAttack), (3.0f));
|
我們根據定時器去每隔3秒內去監控行為AI!
整個行為AI已經完畢!就可以實現比較智慧的怪物追殺主角了!這也就牽扯到了遊戲難度怪物難度的問題了,往往好玩的遊戲智慧AI都佔用了程式一半以上時間去處理;怪物並不是血多,防禦高他就是一個BOSS,如果BOSS他會滿地圖追著玩家打,會自己加血,逃跑,那這樣的BOSS我們作為玩家來說,打起來也比較刺激有意思,有挑戰!
來自:cnblogs