日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

如何建立一个完整的游戏AI

發(fā)布時(shí)間:2023/12/13 综合教程 29 生活家
生活随笔 收集整理的這篇文章主要介紹了 如何建立一个完整的游戏AI 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

http://blog.friskit.me/2012/04/how-to-build-a-perfect-game-ai/

人工智能(Artificial Intelligence)在游戲中使用已經(jīng)很多年了,并且到現(xiàn)在越來越完善。如果你不在你的游戲中加入完善的游戲智能,那么別人就認(rèn)為你的游戲缺少可玩性。
在游戲中,AI并不一定要包括神經(jīng)網(wǎng)絡(luò),學(xué)習(xí)系統(tǒng)和復(fù)雜的數(shù)學(xué)結(jié)構(gòu),游戲AI只是游戲中一個(gè)重要部分,它是活動(dòng)的,并不是科學(xué)性質(zhì)的。
我認(rèn)為如何建立一個(gè)游戲AI,最主要的就是要明白你想在游戲中實(shí)現(xiàn)什么效果,就是你想讓玩家看見什么;如果游戲中什么也沒有發(fā)生,那你的游戲AI什么都沒有做。
在本篇中,我們將討論一個(gè)實(shí)時(shí)策略游戲(RTS)中游戲AI,不管怎樣這些理論都可以很好地移植到其它的系統(tǒng)當(dāng)中,所有的代碼全部用c語言寫成。

狀態(tài)機(jī)

有限狀態(tài)機(jī)

有限狀態(tài)機(jī)(FSM)是一個(gè)只有有限的幾個(gè)狀態(tài)的系統(tǒng)。在一個(gè)實(shí)際的例子當(dāng)中,狀態(tài)的觸發(fā)是通過一個(gè)擁有開或關(guān)狀態(tài)的開關(guān),或通過一個(gè)鬧鐘來調(diào)用時(shí)間決定的。通過有限狀態(tài)機(jī),我們可以在游戲中定義一些事件,然后由玩家在游戲中游動(dòng)時(shí),通過觸發(fā)來實(shí)現(xiàn)某些事件。

有限狀態(tài)機(jī)是游戲中最常用的游戲AI。下面,我們將講解如何在游戲中使用有限狀態(tài)機(jī)。

使用有限狀態(tài)機(jī)

在游戲中,我們最常用的就是用有限狀態(tài)機(jī)來模擬人的某些智能行為。比如,當(dāng)一個(gè)NPC受到攻擊時(shí),它應(yīng)該怎么辦,當(dāng)發(fā)現(xiàn)敵人時(shí),它應(yīng)該實(shí)行哪些行為,當(dāng)敵多我寡時(shí),應(yīng)該實(shí)行哪些行為,等等。都可以用有限狀態(tài)機(jī)來解決。
你可以在游戲中,將你的游戲AI設(shè)計(jì)的完美無疵,它可以萬全模擬一個(gè)人的思維,能夠自我思考,自我學(xué)習(xí),但你要記住一點(diǎn),在游戲中,我們應(yīng)盡量將AI簡單化,不要太科學(xué)化。
并不要以為,我們在這里反對神經(jīng)網(wǎng)絡(luò),遺傳算法等等,你要在游戲中使用哪種算法,完全由你自己根據(jù)你在游戲中要實(shí)現(xiàn)一個(gè)什么效果,完成一個(gè)什么目標(biāo)來決定。相反,我們在這里最主要就是講解如何在游戲中使用有限狀態(tài)機(jī)。

游戲狀態(tài)機(jī)

要在游戲中實(shí)現(xiàn)一些動(dòng)作行為,你必須考慮很多方面,比如你就不能從你自身的角度來考慮問題,你就得從玩家的角度來考慮,玩家他到底要在游戲中干什么?要想達(dá)到玩家的想法,你就不得不在游戲中反復(fù)測試,以便于達(dá)到玩家想要的效果。
在一個(gè)實(shí)際的游戲當(dāng)中,一般存在兩種狀態(tài)機(jī):
第一種狀態(tài)機(jī)主要就是完成游戲界面的轉(zhuǎn)換,比如,玩家在游戲中暫停,應(yīng)該顯示什么界面,游戲中哪些UI應(yīng)該讓玩家可見,哪些又應(yīng)該隱藏。
第二個(gè)狀態(tài)機(jī)主要就是改變當(dāng)前運(yùn)行時(shí)的環(huán)境,比如當(dāng)前玩家處于哪個(gè)游戲地圖,關(guān)卡中NPC的出現(xiàn),玩家任務(wù)完成的狀態(tài):成功或失敗。還有就是我們可能在游戲中要引導(dǎo)玩家的一些參數(shù)或變量。
你可能需要一個(gè)描述NPC的系統(tǒng),這個(gè)系統(tǒng)主要就是用于判斷如果玩家點(diǎn)擊NPC或者向NPC開火,NPC應(yīng)該怎么辦,我們完全可以用下面的結(jié)構(gòu)來表示:

struct GameLevelState{
	int alert; //NPC的當(dāng)前狀態(tài)
	struct Positionshot; //玩家向NPC開火的位置
	int shotTime; //子彈發(fā)射出去后的游戲循環(huán)
	int hostage; //誰需要幫助
	int explosives; //子彈是否爆炸
	int tank; //自身是否受到破壞
	int dialogue; //對話參數(shù)
	int compete; //任務(wù)是否完成
};

擴(kuò)展性

保證你的AI擁有良好的擴(kuò)展性是重要的。在編程的時(shí)候,你要能夠使你的AI最重要的部分能夠很容易的擴(kuò)展。因?yàn)槟阋靼子螒駻I的設(shè)計(jì)是一個(gè)迭代的過程,你需要不斷地去測試它,完善它。

群體動(dòng)作

在游戲中,是由一個(gè)玩家來控制群體,什么是群體動(dòng)作呢?比如,在中,玩家選中一群士兵,然后然它們朝一個(gè)目的地前進(jìn),如果沒有良好的群體控制,那么這些士兵可能就會越走越散。這樣就完全不符合玩家的思想。

解剖101

下面,我們來詳細(xì)地看一下一個(gè)角色的數(shù)據(jù)結(jié)構(gòu):

struct Character{
	struct Positionpos; //玩家所在的地圖位置
	int screenX,screenY; //玩家所在的屏幕位置
	int animDir, animaction, animNum; //動(dòng)畫信息,角色動(dòng)作和動(dòng)畫幀數(shù)
	int rank; //軍銜
	int health; //生命值
	int num; //在當(dāng)前群體中有多少人
	int group; //部隊(duì)編號
	int style; //部隊(duì)的性質(zhì)(步兵,騎兵等)
	struct AnimationObject animObj; //復(fù)雜動(dòng)畫的動(dòng)畫對象
};

現(xiàn)在,我們來詳細(xì)講解每一個(gè)參數(shù):
pos參數(shù)用于決定部隊(duì)在屏幕和游戲世界中的位置,這樣是為了便于我們在屏幕的相應(yīng)位置播放精靈動(dòng)畫,顯示精靈信息等等。
AnimDir,animaction,animnum是用于決定我們當(dāng)前應(yīng)該在屏幕上顯示哪段精靈動(dòng)畫。
Rank ,health 就不用說了。
Num 參數(shù)用于決定該角色在部隊(duì)中的ID號。
Group參數(shù)用于決定該角色所在部隊(duì)在所有部隊(duì)中的編號。
Style,animobj參數(shù)用于決定部隊(duì)的圖像在屏幕上的顯示。

建立過去基本

一旦你利用前面的方法建立了一個(gè)初始化部隊(duì)的函數(shù),那么現(xiàn)在就需要你對這些部隊(duì)賦予生命。
這時(shí)候,你就需要思考你想讓你的部隊(duì)擁有什么樣的動(dòng)作,有什么樣的反應(yīng)。你需要思考,你的部隊(duì)是否感情用事?是否像一個(gè)瘋子?是否需要被凍結(jié)?
要做到這些,你就必須首先思考當(dāng)人遇到某某事情時(shí),他應(yīng)該怎樣做,然后再把你的思考變成代碼,觀看其效果,不對就再修改。

群組

群組或者非群組

如果你是制作第一人稱射擊游戲,你就不用考慮群組的問題了,因?yàn)榫椭挥心阋粋€(gè)。但當(dāng)你想建立一個(gè)RTS類形的游戲,你想同時(shí)控制很多人的動(dòng)作,那你就不得不考慮下面的問題:
我是否需要我的部隊(duì)按照一種比較協(xié)調(diào)的方式行進(jìn)?
如果回答是“是”,那么恭喜你,群組適合你。

群組的優(yōu)點(diǎn)

1. 部隊(duì)能夠按照一個(gè)主要的移動(dòng)信息列表前進(jìn)。這樣做的好處就是群組中的任何一個(gè)單元當(dāng)受到其他信息,比如目標(biāo)的改變等,其它成員還是可以按照先定的移動(dòng)信息前進(jìn)。
2. 多個(gè)成員自我調(diào)節(jié)行為。 比如,我們控制一個(gè)部隊(duì)包圍一個(gè)建筑物,部隊(duì)中的成員能夠相互協(xié)作完成對建筑物的包圍。
3. 群組能夠自動(dòng)保持他們的結(jié)構(gòu),這樣,當(dāng)一個(gè)部隊(duì)遇到一些不明情況時(shí),他能夠自適應(yīng)的告訴部隊(duì)中的每個(gè)成員該干什么。比如,行進(jìn)當(dāng)中要注意保持對形,先頭部隊(duì)首先遭遇敵人,應(yīng)奮起阻擊。
4. 依賴于群組的構(gòu)成,你可以直接控制群組來控制群組中的其他成員,這樣就簡化了找路徑等問題的麻煩程度。

大圖片

如果你想在游戲AI中判斷你所有部隊(duì)的動(dòng)作,你就不得不把這些部隊(duì)的信息全部群組起來。一個(gè)好注意就是建立一個(gè)地方,用于共享所有部隊(duì)的信息。
根據(jù)我的經(jīng)練,這個(gè)部分應(yīng)該分兩步完成:第一部分就是將群組中的每個(gè)成員應(yīng)該做什么事存儲在每個(gè)成員自己的數(shù)據(jù)結(jié)構(gòu)中,而其他需要組織和共享的信息,比如移動(dòng),行動(dòng)等動(dòng)作,應(yīng)存儲在群組數(shù)據(jù)結(jié)構(gòu)中。
這意味著部隊(duì)不擁有移動(dòng)的信息,他們總是在群組的權(quán)利范圍之下做出決策。如果硬要說每個(gè)部隊(duì)都是獨(dú)立的,那他們也只是在群組下獨(dú)立。

許多中的一個(gè)

當(dāng)我們?yōu)榱诉m應(yīng)系統(tǒng)的變化時(shí),尋找一個(gè)群組去行動(dòng),那系統(tǒng)將建立一個(gè)單獨(dú)的部分,并且最重要的是保持每個(gè)部隊(duì)的行動(dòng)信息。這樣做的目的是便于我們打亂我們的結(jié)構(gòu)然后完成一些特殊的任務(wù)。這樣的數(shù)據(jù)結(jié)構(gòu)如下:

struct GroupUnit{
	int unitNum; //角色I(xiàn)D
	struct Unit *unit; //部隊(duì)角色數(shù)據(jù)
	struct Positionwaypoint[50]; //所有部隊(duì)的路徑
	int action[50]; //部隊(duì)在路徑上應(yīng)該的動(dòng)作
	int stepX,stepY; //各別部隊(duì)的步驟
	int run,walk,sneak,fire,hurt,sprint,crawl; //行動(dòng)
	int target; //所有部隊(duì)的目標(biāo)
	struct Position targetPos; //目標(biāo)位置
};

下面,我們來具體描述這些參數(shù):

unitNum是部隊(duì)在群組中的ID。如果群組容納的最大部隊(duì)數(shù)是10,那么最小的部隊(duì)編號是0,最大的是9。
Unit 是一個(gè)指向部隊(duì)角色數(shù)據(jù)的指針,它存儲了包括角色當(dāng)前的位置,生命值和其它相關(guān)信息。
Waypoint 包含了一個(gè)部隊(duì)可以去的所有地方。所有行動(dòng)和位置信息是包含在GroupUnit結(jié)構(gòu)中,如果群組不是在一個(gè)結(jié)構(gòu)中,那么部隊(duì)中的所有成員將按照它們自己的方式移動(dòng)。
Action數(shù)組包含了移動(dòng)到目標(biāo)的所有動(dòng)作。這允許你建立一個(gè)詳細(xì)的動(dòng)作鏈,以便于玩家控制部隊(duì)在森林里潛行,然后匍匐著靠近目標(biāo)。
StepX ,stepY用于存儲簡單的速度信息;因?yàn)槊總€(gè)兵種,它們的移動(dòng)速度都是不一樣的,總不可能步兵的移動(dòng)速度比火箭飛行兵快吧。
Target ,targetpos參數(shù)用于存儲當(dāng)我們選中了一個(gè)敵人部隊(duì)時(shí),敵人部隊(duì)的編號和位置。關(guān)于敵人的其它信息,我們可以通過每次的游戲循環(huán)來找出。

群體心理

我們還需要一個(gè)中央集權(quán)的群組來管理我們所有的群組,下面,我們來看一下一個(gè)簡單的結(jié)構(gòu)。

struct Group{
	int numUnits; //群組中的部隊(duì)數(shù)
	struct GroupUnit unit[4]; //部隊(duì)信息
	int formation; //部隊(duì)和群組的結(jié)構(gòu)信息
	struct Position destPos; //目標(biāo)
	int destPX,destPY; //目標(biāo)屏幕坐標(biāo)
	struct Postion wayX[50]; //群組的所有可去的目標(biāo)點(diǎn)
	float formstepX,formstepY; //群組移動(dòng)的速度
	int formed; //如果這個(gè)值為真,那么部隊(duì)獨(dú)立行動(dòng),否則按照群組的規(guī)則移動(dòng)
	int action,plan; //群組行動(dòng)和計(jì)劃
	int run,walk ,sneak,sprint,crawl,sniper; //具體動(dòng)作
	struct Position spotPos; //攻擊地點(diǎn)
	int strategyMode; //群組的戰(zhàn)越模式
	int orders[5]; //群組的順序
	int goals[5]; //群組的目標(biāo)
	int leader; //群組的領(lǐng)導(dǎo)者
	struct SentryInfo sentry; //哨兵列表
	struct AIState aiState; //Ai狀態(tài)
};

numUnits是指在群組中有多少部隊(duì),部隊(duì)數(shù)組存儲在GroupUnit結(jié)構(gòu)中,在本例中,我們存儲的最大數(shù)量是4.
Formation標(biāo)志決定了群組是采用了什么隊(duì)形,它們可以根據(jù)自身的狀況分別采用柱,楔和三角等隊(duì)形。
DestPos,destPX,destPY描述了群組在趕往目的地中途的什么地方。Waypoints,steps以相同的方式工作,它們都是描述了部隊(duì)行進(jìn)的速度。在這里,并不需要部隊(duì)中每個(gè)成員來設(shè)置自己的速度,這個(gè)事完全由群組決定。
Formed 是最為重要的參數(shù)之一,它決定了部隊(duì)是否按照對形行進(jìn)或單獨(dú)行進(jìn)。如果那個(gè)群組被設(shè)置成按對形行進(jìn),那么群組中所有的部隊(duì)就必須按照群組設(shè)置的對形行進(jìn),但是當(dāng)遇到某些特殊的原因,比如遭受攻擊或?qū)π卧獾搅似茐模敲床筷?duì)就按照他們自己的思路前進(jìn)。
Actions參數(shù)就是表示部隊(duì)在到達(dá)目的地中間的動(dòng)作,比如跑,走,潛行等等,完全由玩家決定。
Strategymode 決定了當(dāng)部隊(duì)遇到敵人后應(yīng)該怎么辦,部隊(duì)是反抗還是逃跑?
Orders,goals數(shù)組是為了便于群組之間的消息傳輸。
Sentry , aiState存儲了哨兵信息和更為詳細(xì)的AI信息,這些信息是為了更詳細(xì)的模型匹配。

把它放在一起

到現(xiàn)在,關(guān)于我們的群組,我們已經(jīng)有了一些結(jié)構(gòu)。然后我們應(yīng)該做什么呢?下一步就是找出我們在游戲中如何用編程來實(shí)現(xiàn)這些信息。
值得注意一點(diǎn)的就是,盡量將你的AI程序模塊化,這樣做的好處就是便于以后更好地?cái)U(kuò)充它們。詳細(xì)一點(diǎn)就是說,你在編寫函數(shù)時(shí),盡量做到一個(gè)函數(shù)只做一件事情。

關(guān)鍵部分

在你準(zhǔn)備寫你的游戲之前,請不斷的學(xué)習(xí)一些基本的東西,如果你的游戲需要一些功能函數(shù),那么就為這些功能編寫相應(yīng)的函數(shù)。
不要學(xué)習(xí)某些高手用一個(gè)函數(shù)完成所有的功能,可能一個(gè)函數(shù)對他很管用,但對你就不那么行的通。
你要不斷的創(chuàng)新,不斷的挑戰(zhàn)傳統(tǒng),不要看一些看似經(jīng)典的程序你需要自己創(chuàng)造。如果你寫的東西,它能正常工作,那么用它。在游戲編程中有一句經(jīng)典的話是這樣說的:“如果你覺得它是對的,它就是對的”。
不要被其它的思想絆住了腳,因?yàn)槲覀兿嘈拍闶亲顝?qiáng)的。

其實(shí),AI的意思就是如何讓決策變得更聰明,在我們這篇文章中,就是要讓玩家感覺游戲中的人物像真的一樣。
在一個(gè)RTS(實(shí)時(shí)策略游戲)游戲中,我們所謂的動(dòng)作包括移動(dòng),巡邏,避開障礙物,打擊敵人和追趕它們。讓我們來看一下每個(gè)動(dòng)作的詳細(xì)內(nèi)容。

移動(dòng)

移動(dòng),最簡單的一種形式就是,在某一段時(shí)間之內(nèi)從一個(gè)點(diǎn)到達(dá)另一個(gè)點(diǎn)。這個(gè)很容易實(shí)現(xiàn),你能通過找一個(gè)距離向量,然后乘以這個(gè)部隊(duì)移動(dòng)的速度和所用的時(shí)間,就可以得到移動(dòng)的位置。
因?yàn)槲覀兊挠螒蚴峭ㄟ^鼠標(biāo)來驅(qū)動(dòng)的,所以,我們并不能期望用戶通過游戲桿之內(nèi)的東西來驅(qū)動(dòng)游戲人物前進(jìn)時(shí)繞開障礙物,首先,你要明白一點(diǎn),我們這里說的并不是第一人稱射擊類游戲。
我們應(yīng)該怎樣做呢?比如,玩家在一棵大樹旁點(diǎn)擊了鼠標(biāo),我們首先必須建立一個(gè)動(dòng)作隊(duì)列保存這個(gè)角色行動(dòng)的路徑,但是當(dāng)角色到達(dá)大樹時(shí),他不可能穿墻而過吧。這個(gè)時(shí)候,我們就必須為角色添加一個(gè)動(dòng)作,以便于角色繞過大樹。

巡邏

巡邏是一個(gè)特別的移動(dòng),因?yàn)樗艘幌盗蓄A(yù)設(shè)的坐標(biāo)。在移動(dòng)中,一個(gè)部隊(duì)它走到一個(gè)目標(biāo)以后,它就不會走了,但巡邏不一樣,當(dāng)部隊(duì)完成一個(gè)目標(biāo)以后,他就會從自身的巡邏列表中抽出下一個(gè)坐標(biāo),然后又朝下一個(gè)坐標(biāo)前進(jìn)。
在我們這個(gè)實(shí)例當(dāng)中,盡量不要讓部隊(duì)一直站立或等待,因?yàn)槲覀冞@個(gè)游戲是RTS游戲,如果一直站立或等待就不能突出游戲的戰(zhàn)爭氣氛。

避開障礙物

避開障礙物的算法首先要看你的地圖是如何工作的,還有就是你的部隊(duì)在移動(dòng)時(shí)應(yīng)該讓他們?nèi)绾蜗嗷ソ换ァT诒纠校覀兪褂玫氖且粋€(gè)擁有很多小的建筑物和物體的室外環(huán)境。在這個(gè)游戲中,你不能進(jìn)入建筑物,這些建筑物都是用一個(gè)凸出的擁有4個(gè)頂點(diǎn)的多邊形表示。

在下面這個(gè)例子當(dāng)中,部隊(duì)和目標(biāo)并不是成直線時(shí)。首先,我們先移動(dòng)到和目標(biāo)最近的一個(gè)坐標(biāo),這個(gè)坐標(biāo)盡量和目標(biāo)呈直角。然后再從這個(gè)點(diǎn)移動(dòng)到目標(biāo)。這樣做的好處就是留下了很大的緩沖空間讓我們繞過障礙物。
說白了,障礙物避開算法是由你將遇到的障礙物決定的。如果你想了解一些更好的路徑尋找算法,我建議你看一下A*算法。A*算法是一個(gè)非常流行的最短路徑尋找算法。

打擊敵人

和其它部隊(duì)作戰(zhàn)通常依賴于你想你的玩家在游戲中能干什么。你可能想你的玩家的部隊(duì)在見到敵人時(shí)能夠自動(dòng)開火,以便于玩家能夠?qū)⒆⒁饬Ψ旁谡麄€(gè)戰(zhàn)場上。你可能還想你的部隊(duì)能夠監(jiān)視周圍的環(huán)境,如果出現(xiàn)敵人就馬上開火。
比如,一個(gè)角色站在一個(gè)坐標(biāo)上,可以將它的四周分為8個(gè)部分,這8個(gè)部分分別代表了角色的8個(gè)視域,當(dāng)然你也可以設(shè)置這些視域的距離,也就是角色所能看到的距離。然后就循環(huán)監(jiān)測這些視域中是否有敵人。當(dāng)然,也有一種特殊情況,比如,敵人和障礙物同時(shí)出現(xiàn)在你的視域中,障礙物在前,敵人在后,你總不可能也看見敵人了吧!關(guān)于這個(gè)問題,我將在另一篇文章中講解。

追趕

當(dāng)一個(gè)敵人發(fā)現(xiàn)了一個(gè)獵物,也就是它自身的視域中出現(xiàn)了一個(gè)角色,這時(shí)候,它就要判斷,這個(gè)角色是自己人嗎?如果是,就不干什么。如果是獵物,就要檢測它是否在視域內(nèi),如果是,就開槍射擊。如果不是在視域內(nèi)呢?那么就需要追蹤它。
那將如何實(shí)現(xiàn)呢?首先,你需要保存獵物最后的一個(gè)坐標(biāo),然后將這個(gè)坐標(biāo)設(shè)置成你的第一個(gè)移動(dòng)目標(biāo),到達(dá)目標(biāo)后,你就需要檢測獵物是否還在視域范圍內(nèi),如果在,就開槍射擊。如果不在,就按照獵物的方向隨機(jī)移動(dòng)一個(gè)距離,然后繼續(xù)檢測。
在本篇的例子當(dāng)中,我們假設(shè)角色能夠在第一次移動(dòng)過后找到獵物。但如果他移動(dòng)后沒有發(fā)現(xiàn)獵物,那么我們就將他的狀態(tài)設(shè)置成巡邏狀態(tài),然后朝我們第一次得到的獵物的方向移動(dòng)一個(gè)隨機(jī)的距離。

總結(jié)

當(dāng)你看懂了這篇文章,并且在程序中將它實(shí)現(xiàn)以后,你就會發(fā)現(xiàn),其實(shí)游戲AI也沒那么神秘,不是挺簡單的嗎?

總結(jié)

以上是生活随笔為你收集整理的如何建立一个完整的游戏AI的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。