|
AI基础教程--建立一个基础的对战AI
这个教程将会一步一步的教你如何去编写一个基础的.ai型的对战AI脚本。如果你以为这个教程可以让你做出比AMAI更强大的AI的话,那么你得重新考虑下是不是还要看这个了。本教程仅仅能教会你基础的JASS,内置本地函数以及你要成为一个对战AI脚本程序员而必须知道的一些概念。
------------------------------------------
目前的内容:
1.Hello World!
2.采集资源
3.训练更多的农民
4.建造农场来支持更多的农民
5.一些JASS理论:主函数,变量和类型
6.建造一个兵营并且训练士兵
7.更多的JASS理论:流控制,条件和循环
8.函数:目前为止我们所用到的
9.何时该建造何物
10.建立和使用函数
即将更新的内容:
1.本地函数总浏览
2.语法检查器
3.MF(Creeping)
4.你们所希望增加的内容或许也会贴出来
-----------------------------
已经发现和修正的BUG:
变量后缀:local已经在声明中添加进去了。
==============================================================
Hello World!
让我们从编写和运行一个简单的Hello World脚本开始吧!
function main takes nothing returns nothing
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Hello World!" ) // 按F12看看呢?
endfunction
将以上代码粘贴到一个名为human.ai的文件中去(建立一个文本文件然后改名为human.ai)
运行地图编辑器
打开你最爱的对战地图,将它以另外一个名字保存(最好放在另外一个文件夹里面)
按F12(或者点Modules(模块)菜单,然后选择Import manager(输入管理器))
在Import manager(输入管理器)中选择File ->Import file (文件 -> 输入文件)
选择刚刚建立好的human.ai.
鼠标右击已经导入的文件,选择Modify file properties(修改文件属性)
将文件位置设置为\Scripts\human.ai
保存地图(顺便把地图关上)
运行魔兽争霸III,选择单人游戏->自定义游戏->你刚刚保存的地图。
将电脑的种族设置为人类
将地图设置为完全可见
游戏开始后在屏幕上寻找Hello World!字样(它在屏幕上一闪而过)
如果你认为它消失的太快了或者你不确定是否看到了那么试试下面的代码:
function main takes nothing returns nothing
call Sleep( 2 ) // <--- 用来确认游戏已经准备好记录这条问候了。
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0.0, 0.0, 3600, "Hello World!" )
endfunction
如果你离开了你的电脑超过了1个小时而没看到这段话的话请按F12 =)
==============================================================
采集资源
地球人都知道在魔兽里采集资源是非常重要的...那么我们来看看一个采集资源的AI脚本该如何编写吧
function main takes nothing returns nothing
call Sleep( 1.0 ) // 休眠1秒
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Script started" )
loop // 开始永恒循环
call ClearHarvestAI() // 首先重置采集管理器并且
call HarvestGold( 0, 4 ) // 告诉电脑用4个农民采集金矿
call HarvestWood( 0, 1 ) // 和1个农民采集木头
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Harvesting" )
call Sleep( 1.0 ) //有时候如果不进行休眠引擎就会自动将这个进程关掉
endloop
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Script exiting" )
endfunction
用试验Hello World!脚本的方法试一下上面这段代码。只需要把以前导入的文件删掉换上新的就行了。你也可以在Import Manager(输入管理器)中右击以前导入的文件然后选择replace(替换)。
不要忘了在高级地图设置中将地图设置为始终可见,不然你在开始就看不到电脑的行动了。
为什么我们总是要重置和再分配采集管理器呢?试想,如果不这么做,当一个农民在采木头的时候被杀死会怎么样?很简单,永远不会有另外一个农民来接替他的工作。
==============================================================
训练更多的农民
用5个农民不知道要花多长时间才能采集够建立一支军队的资源,所以我们需要训练更多的农民来保证资源供给。
function main takes nothing returns nothing
call Sleep( 1.0 ) // 休眠1秒
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Script started" )
loop // 开始永恒循环
call ClearHarvestAI() // 首先重置采集管理器并且
call HarvestGold( 0, 4 ) // 告诉电脑用4个农民采集金矿
call HarvestWood( 0, GetUnitCountDone('hpea')-4 ) // 和1个农民采集木头
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Harvesting" )
call SetProduce(1, 'hpea', 0) // 试着训练一个农民
call Sleep( 3.0 ) // 有时候如果不进行休眠引擎就会自动将这个进程关掉
endloop
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Script exiting" )
endfunction
调用GetUnitCountDone('hpea')可以清点这个玩家拥有多少的人类农民。这用来计算有多少农民没有在采金子从而让他们去采集木头。看看电脑是怎么样建造成堆的农民的...= )
启动地图的另一个更加方便我们观察所创建的AI玩家行为方法:建立一个局域网游戏,在地图高级设置中选择观察者模式,将你自己设置成观察者,这样你在游戏中就可以点击电脑的单位或者建筑来观察他采集了多少资源。
感到厌烦了吗?它是否只在不停的造农民?不?它是需要更多的人口么?那么让我们来教他怎么多造点农场吧! =P
==============================================================
建造农场来支持更多的农民
让我们建造更多的农场,训练更多的农民,采集更多的资源吧!= )
假设我们在还剩余3个额外人口的时候就建造一个新的农场。
function main takes nothing returns nothing
call Sleep( 1.0 ) // 休眠1秒
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Script started" )
loop
call ClearHarvestAI()
call HarvestGold( 0, 4 )
call HarvestWood( 0, GetUnitCountDone( 'hpea' )-4 )
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Harvesting" )
// 如果我们正在训练一个农民那么下面的SetProduce就会失效
call SetProduce( 1, 'hpea', 0 ) // 训练人类农民
// 我们的基地可以提供12个人并且每个基地分配6个人
// 比较目前人口上限和单位所占人口数量来决定
// 是否需要建造一个新的人类农场
if ( 12 + 6 * GetUnitCount('hhou') - GetUnitCount('hpea') < 3 ) then
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Trying to build a house" )
call SetProduce( 1, 'hhou', 0 ) // 建造一个人类农场
endif
call Sleep( 3.0 )
endloop
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Script exiting" )
endfunction
这样我们就有许多的工人和许多的资源啦!但是我们是不是该把这些资源花掉呢?我们是不是要建造更多的房子来会帮助我们训练军队呢?请注意下面关于建筑的部分啦~
==============================================================
一些JASS理论:主函数,变量和类型
呵呵。抱歉了,我们在看建造建筑前要打断一下了~我觉得在其之前有必要想想JASS了.不过如果你对JASS已经很熟悉了就可以跳过这一段啦。好了~准备好来学习JASS吧!
主函数main
function main takes nothing returns nothing
// 许多的代码
endfunction
所有在AI脚本中的动作都会在游戏引擎调用main函数的时候开始。
main函数必须像上面的那样,不然脚本就无法执行。
变量
通常它被用来记录一些东东非常好使。在JASS中你必须用变量来保存值。不同类型的变量可以用来保存不同类型的值。
function main takes nothing returns nothing
local integer number // 告诉(声明)引擎我们要储存一个数字(声明)
local integer anotherNumber // 并且(声明)另外一个数字
local float decimalNumber // 还有(声明)一个十进制数
local string someText // 以及(声明)一些文本
set number = 42
set anotherNumber = 6 * 9
set decimalNumber = 3.14
set someText = "Is this to easy for you? ;-)"
endfunction
实现同样功能的另外一种方法是:
function main takes nothing returns nothing
local integer number = 42 // 声明的同时赋值给它,一行用起来比两行清楚多了~
local integer anotherNumber = 6 * 9
local float decimalNumber = 3.14
local string someText = "Is this to easy for you? ;-)"
endfunction
另外需要注意的是在函数开始的时候我们必须声明(告诉引擎)所有我们将在这个函数里使用的变量。下面的例子是不合法的。
function main takes nothing returns nothing
local integer number = 42 // 声明的同时赋值给它,一行用起来比两行清楚多了~
local integer anotherNumber = 6 * 9
local float decimalNumber = 3.14
set anotherNumber = number // 不合法
local string someText = "Is this to easy for you? ;-)"
set anotherNumber = number // 不过在这个地方倒是合法的
endfunction
我们在声明一个变量前总是要加上local字样。Local意味着这个变量只在这个函数中有效。这个并不是必须的,稍后我们会看到如何使用全局变量。
现在深呼吸,然后跟我说:“变量是我们的朋友~ = D ”。
好了~~这个理论部分比我预想的要长呢。或许我们应该接着造建筑了~或许我们会建造一个兵营,或者训练一个士兵?我们自己的士兵(或者说是AI的=))
==============================================================
建造一个兵营并且训练士兵
现在我们就开始建造一支无所不摧的军队的第一步吧!扼,先从训练步兵开始吧 =P
function main takes nothing returns nothing
call Sleep( 1.0 )
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Script started" )
loop
call ClearHarvestAI()
call HarvestGold( 0, 4 )
call HarvestWood( 0, GetUnitCountDone( 'hpea' )-4 )
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Harvesting" )
call SetProduce( 1, 'hpea', 0 ) // 训练人族农民
// 判断何时建造农场
if ( 12 + 6 * GetUnitCount('hhou') - GetUnitCount('hpea') < 3 ) then
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Trying to build a house" )
call SetProduce( 1, 'hhou', 0 )
endif
if ( GetUnitCount( 'hbar' ) < 1 ) then // 我们已经有人类的兵营了吗?
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Trying to build a barrack" )
call SetProduce( 1, 'hbar', 0 ) // 在0号基地中建立一个人类兵营
else
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Trying to train a footman" )
call SetProduce( 1, 'hfoo', 0 ) // 在0号基地中训练步兵
endif
call Sleep( 3.0 )
endloop
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Script exiting" )
endfunction
或许你已经注意到了在建造农场和训练单位间停顿了一小会。你知道是为什么吗?是我们没有足够多的农场吗?或许我们正被计算目前正在使用多少人口困扰。或者你会在我公布答案前自己试着修复这个问题.(提示:在条件(conditon)中有个地方错了)
在我们扩展代码前,像是建造不同的建筑,训练不同的兵种或者是让士兵去战斗。不过那对这个基础教程来说偏难了。呵呵。
在指出为什么它会比较难之前我们又需要学习更多的JASS了~现在到了学习使用更多更加有用的函数的时候了~现在甚至是我们学习所有这些函数的来源和工作原理的时候了!不要走开哦!
==============================================================
更多的JASS理论:流控制,条件和循环
流控制是关于如何实现在一个程序中使用不同的方法的内容。JASS中用if语句和循环结构来支持它。让我们看看吧。
if
通常我们会遇到在不同的情况下执行不同的操作的问题。最基础的方法就是当某事为真的时候我们就做什么,否则我们就做另外的什么事(或者什么事也不做)
if condition then
doSomething
doSomethingMore
endif
if GetUnitCount( 'hpea' ) < 12 then // 如果我们的农民少于12个
call setProduce( 1, 'hpea', 0) // 在我们的起始基地中建造一个农民
endif
嘿!我们如果我们农民足够的时候该做什么呢?
if condition then
doSomething
else
doSomethingElse
endif
if GetUnitCount( 'hpea' ) < 12 then //如果我们的农民少于12个
call setProduce( 1, 'hpea', 0) // 在我们的起始基地中建造一个农民
else
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "We need no more peasants" )
endif
这只在只有2种情况可供选择的时候有效,我们如何在多种分支中选择呢?
if condition then
doSomething
elseif condition2
doSomethingElse
else
doSomeOtherThing
endif
if GetUnitCount( 'hpea' ) < 12 then // 如果我们的农民少于12个
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "We need more peasants" )
call setProduce( 1, 'hpea', 0) // 在我们的起始基地中建造一个农民
elseif GetUnitCount( 'hpea' ) < 20 then
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "We need no more peasants" )
else
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "We have to many peasants" )
endif
添加更多的elseif语句你就可以写一个在很多的动作间选择的程序了。你需要注意的仅仅是适当的放置条件。下面这个就没有按正确的顺序放。
if GetUnitCount( 'hpea' ) < 20 then
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "We need no more peasants" )
elseif GetUnitCount( 'hpea' ) < 12 then
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "We need more peasants" )
call setProduce( 1, 'hpea', 0)
else
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "We have to many peasants" )
endif
如果我们有一个农民,这段代码会说我们不需要更多的农民。这是因为条件是从上而下依次检查的。
循环
循环就是不断的重复做某事。如果你在其他的编程中用过循环结构,在使用JASS的循环时你可能会感到不适应。不过有一种编写在JASS中的while循环和for循环的方法。
让我们来看一个将永远执行下去的循环(或者执行到游戏引擎关闭掉它。)
loop
doSomethingForever
endloop
loop
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Let's spam the user forever")
call Sleep( 1.0 ) // 不用休眠的话就无法永远的执行
endloop
永远执行的循环有它们自己的用处,但是他们并不很灵活。所以让我们来看如何跳出循环。
loop
doSomething
exitwhen condition
doSomethingMore
endloop
local integer i = 1
loop
call Sleep( 1.0 )
exitwhen i > 10
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Let's spam the user 10 times")
set i = i + 1
endloop
for循环
我们在JASS中不能使用For循环,但是我们可以做一个像for循环的循环。
for ( initStatement; condition; endOfIterationStatement ) {
stuff;
}
在JASS中可以这样做
initStatement
loop
exitwhen not (condition)
stuff
endOfIterationStatement
endloop
现在让我们来看看一个更加具体的例子。
for (int i = 0; i < 10; i++) {
printf("We need to say it 10 times");
}
在JASS中变成
local integer i = 0
loop
exitwhen not ( i < 10 ) // 当 i >= 10 时跳出
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "We need to say it 10 times")
set i = i + 1
endloop
while
或许你应该自己来研究如何在JASS中实现while循环。如果你不太习惯用while循环那么就无视它们吧,反正JASS是没有这种循环。
如果你想了解更多,去查询TRIGGER和JASS的相关教程吧。
==============================================================
函数:目前为止我们所用到的
这部分列出了目前我们用到的所有的函数,看看它们是如何工作的,能干什么,以及为什么我们只让它们做什么。希望你会喜欢这部分。
对于每一个我们用过的函数,我都会写出来它们在资源文件中是如何声明的,在引数中是怎么解释的,它能做什么以及它返回什么。
native Sleep takes real seconds returns nothing
call Sleep( 3.5 ) // 让脚本暂停3.5,秒
如果我们不让脚本休眠,引擎会强制终止它
constant native GetLocalPlayer takes nothing returns player
local Player p = GetLocalPlayer() //区别玩家的电脑
利用它可以用来指定显示文本的对象。
native DisplayTextToPlayer takes player toPlayer, real x, real y, string message returns nothing
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Hello local player!" )
我们需要告诉这个函数显示给谁什么内容。把那些0改成不同的内容我们就可以控制文字在屏幕上显示的位置了。试验的时候随便写吧,用0一般就足够了。显示的内容会在一小会后消失,这由文本的长度决定。
native DisplayTimedTextToPlayer takes player toPlayer, real x, real y, real duration, string message returns nothing
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, 60, "Hello for 60 secs!" )
同上,不过我们可以控制文本显示的时间。
native ClearHarvestAI takes nothing returns nothing
call ClearHarvestAI() // 命令采集AI停止采集
这个函数和下面的2个配合起来一起用可以用来控制用几个农民采金子和几个农民采木头
native HarvestGold takes integer town, integer peons returns nothing
call HarvestGold( 0, 5 ) // 让主基地中的5个农民采集金子
如果这个函数被调用2次的时候,如果没用上面的那个函数的话就会让10个农民去采金子了。。。
native HarvestWood takes integer town, integer peons returns nothing
call HarvestWood( 0, 10 )
同上,只是这个采集的是木头
native SetProduce takes integer qty, integer id, integer town returns boolean
local boolean success = SetProduce( 1, 'hpea', 0 ) // 在主基地训练一个农民
call SetProduce( 1, 'hpea', 0 )
我并不完全相信返回值,它让我在很多时候产生疑惑
native GetUnitCount takes integer unitid returns integer
set numberOfPeasants = GetUnitCount( 'hpea' ) //清点AI玩家的农民数量
包含了正在训练的农民
native GetUnitCountDone takes integer unitid returns integer
set numberOfPeasants = GetUnitCount( 'hpea' ) // 清点AI玩家农民的数量
不包含正在训练的农民
==============================================================
何时该建造何物
这部分我们将用我们自己的函数来进行建筑,不过可能中间夹杂着不少的理论内容。所以我们必须考虑我们何时候该造何种建筑或者训练什么单位。在我们只有兵营而没有铁匠铺的时候显然是不能训练火枪手的。
让AI忽视任何需求尝试建造一个建筑是最简单的。如果我们把所有的建筑顺序写在一个循环里,它将会尝试建造所有我们命令它建造的建筑(如果我们没有忘记科技树的话)它在很多时候都用的不是很好,我们可能会建造许多同样的建筑,例如3个铁匠铺(真是疯了。。。),那么该如何解决呢?
如果我们回头看一下第四部分,关于建造更多的农场来支持更多的农民,和第六部分,建造兵营并且训练单位,我们不难发现,它们中用了一些if语句,用来决定该做什么事的规则。试想,如果是我们正在玩游戏,我们通常在脑中都会有一些,至少是一条建筑的规则。所以,我们还等什么呢?来试试吧!
规则 1: 当我们缺乏农民的时候应该训练农民
规则 2: 当我们人口不足时应该建造农场
规则 3: 没有兵营时应该造兵营
规则 4: 有兵营了就可以造步兵了
规则 5: 如果有兵营了就可以造一个铁匠铺了
规则 6: 如果我们没有祭坛就造一个祭坛
规则 7: 如果我们有祭坛而没有英雄就需要造一个英雄
让我们看看这些规则,它们会让我们建立一支由英雄带队的步兵和火枪手组成的部队。想想如何在JASS中实现他们吧!(回顾一下第七节会很有帮助)
懒得自己试么? =) 好吧,我带你们一起搞吧。。。呵呵
让我们看看如何将规则1应用到JASS中去,似乎用IF语句非常适合。
if "we have to few peasant" then
"train more peasants"
endif
few具体是指多少?让我们将规则1改为:
规则1B : 如果我们有少于10个农民那么就开始训练一个农民。
然后将它用JASS实现。
if GetUnitCount('hpea') < 10 then
call SetProduce( 1, 'hpea', 0 ) // 0是指我们最开始的基地
endif
好的~
那么我们以此类推来改一下其他的规则吧~
规则 2b: 如果我们人口剩余少于6个就造一个农场
规则 3b: 如果我们的兵营少于1个就建造一个兵营
规则 4b: 如果我们的兵营多于1个就训练一个步兵
规则 5b: 如果我们的兵营多于1个而铁匠铺少于1个就早一个铁匠铺
规则 6b: 如果我们祭坛少于1个就早一个祭坛
规则 7b: 如果我们的祭坛多于0个而英雄少于1个就训练一个英雄
规则 8b: 如果我们有少于一个的非JASS的规则那么我们就将它改为一个符合JASS的规则 =)
==============================================================
建立和使用函数
函数...他们到底好在哪里,为什么我们要用他们呢?厄...如果有另外一个人写了大量的不错的函数来给我们调用,我们就不用自己写了。如果我们想自己写几个函数,我们就可以防止我们的代码变成一团乱麻了。分割!征服!。把你的代码分割成很多函数,然后征服每个函数吧!
让我们来看一个简单的不能再简单的函数。
function myFunc takes nothing returns nothing
endfunction
这个函数什么也不能做。但是它包含了每个函数都必须具有的部分。它以function关键字开始,以endfunction结束。在function后是函数名:这里是MyFunc。下面的是takes以及函数使用的所有参数。这个函数不使用任何参数。它也不返回任何东西。它教给我们什么了?一个函数名为muFunc的函数,没有任何的实参和形参并且没有任何的返回值。
那我们现在来做一个可以实现一些功能,使用一些参数并且有返回值的函数吧。
function add takes integer a, integer b returns //a+b的和
return a + b
endfunction
他的功能很明显,不是吗?而且它一点也不实用。我们可以直接用+直接计算而不是用函数。让我们来做个更加有用的函数,用来让所有的农民采集资源。
function resourceManager takes goldPeasants returns nothing
call ClearHarvestAI()
call HarvestGold( 0, goldPeasants )
call HarvestWood( 0, GetUnitCountDone('hpea') - goldPeasants )
endfunctions
这个函数使用了决定多少个农民采集金子(其余的都去采木头)的参数。它在另外一个函数(例如main)中调用方法如下:
call resourceManager( 5 )
这样就可以让5个农民去采金子而其他的去采木头了。在前面的程序中使用这个函数我们在main中可以省去很多行的代码。在第二部分的程序可写为:
function resourceManager takes goldPeasants returns nothing
call ClearHarvestAI()
call HarvestGold( 0, goldPeasants )
call HarvestWood( 0, GetUnitCountDone('hpea') - goldPeasants )
endfunctions
function main takes nothing returns nothing
call Sleep( 1.0 )
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Script started" )
loop
call resourceManager( 4 )
call Sleep( 1.0 )
endloop
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Script exiting" )
endfunction
要注意被调用的极限函数是要写在调用它的函数前的。不然魔兽III的程序就会这样想:这是什么怪函数?从来没听说过嘛!我最好关闭这个脚本,它看上去不完整嘛。
另外一个有用的极限函数是像这样的:
function print takes string message returns nothing
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0.0, 0.0, 3600, message )
endfunction
==============================================================
一个战斗脚本
这部分可能出现的过早了。让我们一起重新编写一下第六部分中的代码。建造兵营并且训练一些士兵。
为了增加代码的可读性,我把它分成了用来控制资源,建造建筑和训练单位这几个不同的管理器中了
function resourceManager takes nothing returns nothing
local integer goldPeasants = 5
local integer peasantsDone = GetUnitCountDone('hpea')
if peasantsDone < 6 then
set goldPeasants = peasantsDone - 1
endif
call DisplayTextToPlayer(GetLocalPlayer(), 0.0, 0.0, "In manager")
call ClearHarvestAI()
call HarvestGold( 0, goldPeasants ) // then tell it to have
call HarvestWood( 0, GetUnitCountDone('hpea') - goldPeasants )
endfunction
function unitManager takes nothing returns nothing
if GetUnitCount('hpea') < 12 then
call SetProduce(1, 'hpea', -1) //在任何可行的地方训练农民
endif
call SetProduce(1, 'hfoo', -1) // 在任何可行的地方训练地面部队
endfunction
function buildingManager takes nothing returns nothing
local integer produced = 12 + 6 * GetUnitCount('hhou')
local integer used = 1 * GetUnitCount('hpea') + 2 * GetUnitCount('hfoo')
local integer foodSpace = produced - used
local integer barrack = GetUnitCount('hbar')
if foodSpace < 6 then
call DisplayTextToPlayer(GetLocalPlayer(),0.0,0.0,"Building house")
call SetProduce(1,'hhou',-1)
endif
if barrack < 1 then
call SetProduce(1,'hbar',-1)
endif
endfunction
function main takes nothing returns nothing //
// 命令单位移动到前方某处
//================================================== =======
function walk takes unit u, real distance returns nothing
local real dir = GetUnitFacing(u) * 3.14 / 180
local real x = GetUnitX(u) + distance * Cos(dir)
似乎GA缺少这部分内容
特地去找了下
话说 其实我对AI函数也不了解 |
评分
-
查看全部评分
|