精華區beta StarCraft 關於我們 聯絡資訊
上篇我們已經把最簡單的東西看過一遍了!現在來看看怎樣寫個神族假一波流AI !(之所以是假一波流,第一是因為不知道怎樣用技能,不會超時空加速、哨兵也不 會開盾,當然連變傳送門變空間之門也不會。第二是我也還沒研究完整的一波流流程 ,所以沒最佳化,兵種也只是看來那麼樣子而已XD) 如果你只是想看Stupid AI有多Stupid,直接看文章最末的載點跟使用說明吧! 首先,你要找到的是解開後的Protoss0.galaxy,把它用任何文字編輯器打開, 找到這個function: void ProtossOpenGnd0 (int player) { 大括號裡面就是可以寫AI的部分了。事實上,下面還有: static void ProtossMidGndA (int player) { 之類的,它是為了分出前中後期不同任務之類的,用一些function去切換。但是 反正我們是要寫假前期一波流,所以管它的都塞ProtossOpenGnd0裡面就好了! 接下來一段一段看下去: int nProbe = AITechCount(player, c_PU_Probe, c_techCountInProgressOrBetter); int nZealot = AITechCount(player, c_PU_Zealot, c_techCountInProgressOrBetter); int nStalker = AITechCount(player, c_PU_Stalker, c_techCountInProgressOrBetter); int nDisruptor = AITechCount(player, c_PU_Disruptor, c_techCountInProgressOrBetter); int nPylon = AITechCount(player, c_PB_Pylon, c_techCountInProgressOrBetter); int nGateway = AITechCount(player, c_PB_Gateway, c_techCountInProgressOrBetter); int nCyberneticsCore = AITechCount(player, c_PB_CyberneticsCore, c_techCountInProgressOrBetter); 很簡單就是把會用到的各種兵種/建築數量存起來,以供後面參考及印出Debug 訊息之用。注意這裡是用c_techCountInProgressOrBetter,也就是正做到一半還沒 做完的那一個也算在內。 TriggerDebugOutput(1, StringToText(IntToString(nProbe) + " Probe " + IntToString(nZealot) + " Zealot " + IntToString(nStalker) + " Stalker " + IntToString(nDisruptor) + " Disruptor " + IntToString(nPylon) + " Pylon " + IntToString(nGateway) + " Gateway " + IntToString(nCyberneticsCore) + " CyberneticsCore "), true); 上一篇介紹過了,就是洗螢幕用的資訊表。 AIClearStock(player); AISetStock(player, 1, c_PB_Nexus); AISetStock(player, 8, c_PU_Probe); AISetStock(player, 1, c_PB_Pylon); 然後先用AIClearStock跟AI說我要重設工作了,洗乾淨雙耳給我聽清楚吧。接著 是最基本一定會做的東西:1個bn、8隻Probe、1個be。這裡講到AISetStock的特性一 ,就是已有的也算在內,所以你這邊說要1個bn,那因為你原本就有了,所以它不會 去多做一個。之所以還要寫只是很無聊的,萬一你把它bn全爆了而它還有400元,它 就會重蓋(應該吧,沒測過XD)。 同樣的,這裡我們讓它做到8隻Probe就停,存錢直接be! if(nPylon >= 1) { AISetStock(player, 11, c_PU_Probe); AISetStock(player, 1, c_PB_Gateway); AISetStock(player, 1, c_PU_Zealot); 接著,第一行說如果第一個be至少已經蓋下去了,那我們才給它以下大括號內的 工作。這是為了要表現出8隻Probe後停生存錢be這個動作。我去翻一些別人寫的AI發 現他們直接這樣把流程寫下去: AISetStock( player, 1, c_PB_Nexus ); AISetStock( player, 9, c_PU_Probe ); AISetStock( player, 1, c_PB_Pylon ); AISetStock( player, 11, c_PU_Probe ); AISetStock( player, 1, c_PB_Gateway ); AISetStock( player, 14, c_PU_Probe ); AISetStock( player, 3, c_PB_Pylon ); 我也懷疑過是不是這樣照順序寫就好了。後來我實測發現這是錯的!AISetStock 似乎沒有嚴謹的順序關係!我的測試是這個: AISetStock( player, 1, c_PB_Nexus ); AISetStock( player, 8, c_PU_Probe ); AISetStock( player, 1, c_PB_Pylon ); AISetStock( player, 1, c_PB_Gateway ); AISetStock( player, 2, c_PB_Pylon ); 如果按照美好的順序,它應該做到第8隻Probe後存錢蓋下第1個be,然後存150蓋 bg,再補到第2個be。結果我實測的結果是,它居然第2個be比bg還早一點點蓋下去! 因為bg比較貴,很明顯如果照寫AI順序的話,第2個be應該要被bg卡住晚蓋的。所以 我想直接列下來的順序是沒有意義的,而且同樣針對be的寫兩行也只會取大的,有錢 就會一起蓋下去。所以回到我們的AI: if(nPylon >= 1) { AISetStock(player, 11, c_PU_Probe); AISetStock(player, 1, c_PB_Gateway); AISetStock(player, 1, c_PU_Zealot); 這裡就需要用if來做流程的控制,要在確定了第一個be蓋下去的情況才開始補到 11隻Probe,並造bg然後先做一隻Zealot。 if(nGateway >= 1) { AISetGasPeonCountOverride(player, c_townMain, 3); if(AIGetBuildingCountInTown(player, c_townMain, c_PB_Assimilator, c_techCountCompleteOnly) > 1) { AISetGasPeonCountOverride(player, c_townMain, 6); } AISetStock(player, 2, c_PB_Pylon); AISetStock(player, 19, c_PU_Probe); AISetStock(player, 1, c_PB_Assimilator); AISetStock(player, 2, c_PB_Gateway); AISetStock(player, 3, c_PU_Zealot); AISetStock(player, 1, c_PB_CyberneticsCore); 同樣的技倆,我們在11隻Probe時又讓它停生,逼它bg要蓋下去了我們才開始堆 後面的工作給它。首先我們要準備採瓦斯了,所以先設定一下3隻去採。但是接著加 個但書,如果後來我們蓋了第二個ba,那就要變6隻去採。 然後我們就堆一堆工作給它:補第2個be、Probe以19隻(礦16隻加上單ba的3隻 )為目標、蓋個ba、補到2bg、Zealot補到3隻、還要蓋個by。 if(nCyberneticsCore >= 1) { AISetStock(player, 22, c_PU_Probe); AISetStock(player, 2, c_PB_Assimilator); AISetStock(player, 4, c_PB_Pylon); AISetStock(player, 4, c_PU_Zealot); AISetStock(player, 2, c_PU_Stalker); AISetStock(player, 1, c_PU_Disruptor); 同樣的,by要蓋下去了我們才又增改新工作。Probe補滿到22隻因為我們要2ba了 。Zealot做到第4隻,而且可以開始做2隻追獵跟1個哨兵了。 if(nDisruptor >= 1) { AISetStock(player, 6, c_PB_Pylon); AISetStock(player, 6, c_PU_Stalker); AISetStock(player, 6, c_PU_Zealot); AISetStock(player, 3, c_PB_Gateway); AISetStock(player, 2, c_PU_Disruptor); } } } } AIEnableStock(player); 再進一步,哨兵第1隻完成的話,我們就做最後一堆工作。be補到6個,然後以狂 戰、追獵各6而哨兵2的目標去補,同時補下3bg。到最後,用AIEnableStock告訴它你 這AI的生產工作就很笨的到此為止了! if(AITechCount(player, c_PU_Stalker, c_techCountCompleteOnly) >= 4) { AIWaveMerge(player, c_waveMain, c_waveAttack); AISetAttackState(player, e_attackState_Attack); } } 但如果只堆生產工作給它,它就真的會很笨的只生東西然後就發呆了!要讓它看 起來笨得可愛,你至少要叫它送兵過來死吧!所以在這最後,我們叫它算一下追獵有 沒有4隻做完的了(注意這裡我們用c_techCountCompleteOnly,不然在bg裡正在做的 它也算了),有的話就叫它把目前的兵力主隊改編進攻擊隊去,然後給它放手送死的 指令!這樣整個假一波流就完成了! 我把這樣編出來的Base.SC2Data.my檔(自己照之前改AI的要領,把這檔改名成 Base.SC2Data去替換原檔就好)以及有AI改寫內容的Protoss0.galaxy都放到下面這 裡了,可以自行下載!千萬不要期待強度! http://www.badongo.com/file/21145938 Have fun! 對了補充一下我忘了講,這當然只有電腦是用到P才有效喔。如果你沒看到洗螢 幕,那電腦就不是P,F10 r r重來吧XD 如果被洗到眼都花了,可以自己嘗試照前幾篇有人提過的做法,把我這篇提到顯 示訊息的那段拔掉再包回去! 我還是補個不洗螢幕版好了: http://www.badongo.com/file/21146635 另外裡面附了一個星際大腳(我目前是1.012)用的選單表,你可以把兩個檔完 全不改名直接copy到 星際大腳目錄\bfmods\Liberty.SC2Mod下面,就可以在星際大 腳的單機AI選單看到Stupid AI了! -- 「珍貴的回憶?還不是跟夢一樣虛幻不實的東西?你想要什麼樣的回憶,我幫你 做出來啦!」 --艾蜜思,謊言事務所實現使者 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 114.36.175.240
mantohu:推推 03/11 12:42
gmoz:感謝教學XD! 03/11 12:43
※ 編輯: ddavid 來自: 114.36.175.240 (03/11 12:46)
ddavid:靠,我剛剛想用差不多的流程跟Stupid AI硬剛,結果我先開個 03/11 12:58
ddavid:二礦就被幹掉,我比我AI還笨了orz 03/11 12:59
※ 編輯: ddavid 來自: 114.36.175.240 (03/11 13:14)
H45:推 03/11 13:19
※ 編輯: ddavid 來自: 114.36.175.240 (03/11 13:22)
THD:看來以後要變成AI大戰了 03/11 13:59
ddavid:結果不開二礦就沒事了,這個AI因為我只寫到這裡,所以它就 03/11 14:19
ddavid:算錢超多也只能做出設定的上限兵力XD 03/11 14:20
a7891:跟象棋圍棋一樣 以後寫幾個AI出來比賽看看誰是AI中的霸主 03/11 14:30
Kendai:那上次的隱飛甩尾應該是相當的犀利! 03/11 14:35
mantohu:SC2的StarCraft AI Competition應該會更精彩 03/11 14:55
ileadu:挖瓦斯四隻比較剛好囉.. 03/11 16:01
animad:三隻就飽和...四農民採氣到底是誰發表的啊... 03/11 16:05
ddavid:連Blizzard原本的AI都直接寫三隻六隻的XD 03/11 16:07
animad:SC1四農民採氣才有意義,SC2實測過根本沒差 03/11 16:08
rexrainbow:有下有推, 期待後續報導~ 03/12 19:31