2023年12月31日发(作者:)

AI脚本初级教程

??????????

【什么是jass AI?】:jass AI是用纯jass编写的AI程序,可以用新建文本文档写或jass工具编写.真三AI以及DOTA AI也是由AI脚本编写.

【AI脚本使用方法】:

①运行地图编辑器

②打开你最爱的对战地图,将它以另外一个名字保存(最好放在另外一个文件夹里面)

③按F12(或者点Modules(模块)菜单,然后选择Import manager(输入管理器))

④在Import manager(输入管理器)中选择File ->Import file (文件 -> 输入文件)

⑤选择刚刚建立好的**.ai.文件

⑥鼠标右击已经导入的文件,选择Modify file properties(修改文件属性)

⑦将文件的后缀名改为.ai

??◥??????????????????????????????????????????????????

【代码放置】:在文本文档中AI程序代码应如下放置

+ Shingo Jass Highlighter 0.41

globals

// 这个放全局变量

endglobals

function blabla takes blabla returns blabla

// 自定义函数

endfunction

function main takes nothing returns nothing

//主程序在这

Endfunction

[教程] 用T编写简单的AI,让你的电脑变的强大起来 (菜鸟必看)

首先要知道一点,对于1般的RPG,对战的AI是没有用处的,如果加了对战AI,电脑就只会造房子出兵,显然这个是我们不需要的

如果1个电脑单位没有任何AI,那么它就只拥有以下基本功能,对于旁边的敌人会主动的攻击,会自动放单体的杀伤魔法,(要说明的是,只会随便选择一个单位放技能,而没有针对性),敌人比较多的时候也会放群体的杀伤魔法,也会使用加血的技能和魔法,这些是不需要特殊的AI

的就可以办到的.

电脑的没有AI的缺点有以下几点

1,不会逃跑

2,不会学习技能

3.不会针对某个特别单位使用技能

4,不会使用部分物品和特殊的技能

^^^^^^

我现在就把ORC3C电脑英雄的沉没的AI简单的给大家介绍一下

基本的方法是这样

一般的说,ORC的电脑的沉没对冽炎风暴,火焰雨,暴风雪等持续的魔法更有效

基本的方法是这样:

事件: 任意单位发动技能效果

条件:满足任意的下面一个条件

释放的 技能是 暴风雪

释放的 技能是 火焰雨

释放的 技能是 烈炎风暴

释放的 技能是 ^^^^^^^

动作:选择 触发单位 为圆心 范围800 满足条件 (匹配的单位是 英雄 为 TRUE) (匹配单位控制者是 电脑) (匹配单位是 死亡 为 FLASE) (匹配单位是 是触发单位所有者的 敌人

为 TRUE) (匹配的单位所持有的 沉没权仗是 被持有的) 的单位做动作

LOOP

让选择的 单位使用 选择单位 所持有的 沉没权仗 到 触发单位的位置

就可以实现AI的沉默效果,一定要加 (匹配单位控制者是 电脑),否则玩家单位也会被强制使用物品

下面偶在讲个DOTA的里面暗影萨满的多个技能连杀的T

以暗影萨满11级的为例子

枷锁 LV4 MP 185 闪电 LV4 MP 160 蛇棒LV2 350

一个连招 3个魔法一共要消耗700点魔法

假使撒满身上有风仗,魔法充足

下面如下的写T

触发1__________________________________________________________

事件:任意单位被攻击

条件:被攻击的单位是英雄为真

被攻击的单位的生命值低于 70%

被攻击的单位是攻击单位的敌人

被攻击的单位是死亡 为 假

动作: :

设置变量 A= 被攻击的单位 //(为其他的T记录)

选择 触发单位 为圆心 范围800 满足条件 (匹配的单位的类型是 暗影撒满 为 TRUE)

(匹配单位控制者是 电脑) (匹配单位是 死亡 为 FLASE) (匹配单位是 是触发单位所有者的

敌人 为 TRUE) (匹配的单位所持有的 飓风权仗是 被持有的) 的单位做动作

LOOP

让选择的 单位使用 选择单位 所持有的 飓风权仗 到 被攻击的单位

设置变量 B= 选择的单位 //(为其他的T记录)

命令 B 使用 暗影猎手_毒蛇守卫 到 A 所在的点

开启触发器2

开启触发器4

触发2__________________________________________________________初始关闭

事件:每0.2事件

条件:

动作:

选择 A 为圆心 范围200 满足条件 (匹配的单位的类型是 毒蛇守卫LV2 为 TRUE) (匹配单位控制者是 电脑) (匹配单位是 死亡 为 FLASE) (匹配单位是 是触发单位所有者的 敌人

为 TRUE) 的单位做动作

LOOP

命令 选取的单位 发布 攻击 到 A

触发3__________________________________________________________

事件:任意单位死亡

条件:死亡的单位类型是 毒蛇守卫LV2

动作:

关闭 触发2

触发4__________________________________________________________初始关闭

事件:每0.2事件

条件:

动作:

选择 B 为圆心 范围600 满足条件 (匹配的单位的类型是 暗影撒满 为 TRUE) (匹配单位控制者是 电脑) (匹配单位是 死亡 为 FLASE) (匹配单位是 是触发单位所有者的 敌人

为 TRUE) 的单位做动作

LOOP

命令 B 发布 人族 龙鹰骑士_空中锁链 到 A

触发5__________________________________________________________

事件:任意单位 开始释放技能

条件:释放的技能是 枷锁

动作:关闭 触发4

触发6__________________________________________________________

事件:任意单位 释放技能结束

条件:释放的技能是 枷锁

动作:命令 B 发布 中立 那家海女巫_叉状闪电 到 A

命令 B 发布 中立 攻击 到 A

几个组合的T就可以让电脑使用出强大的组合技能,就就是基本T做的AI

下面的几页帖子在继续写其他的方面的AI 呵呵

[教程] 如何创建一个魔兽RPG的AI系统(转)

...从某地方挖出的

如何创建一个魔兽RPG的AI系统

作者:

翻译:通魔作坊?onlyxuyang

译文:

这篇文章将帮助你制作一个简单但是十分酷的英雄对战地图的人工智能。

这个你将学习的人工智能系统不是非常完美。我们将创建的是一个可以攻击其它英雄、可以自己拣物品、学习和使用技能的人工智能系统,但是还是无法与人类玩家相比。

但是,当你学习了基础的知识以后你应该可以自己改进它。

前提需要:

JASS基础----这篇文章使用JASS来制作示例,所以你必须了解JASS。在理论上它也可以在T中做出来,但是我不推荐那样做,因为用T来制作可能导致内存泄露、大量不必要的代码

以及在T中是无法使用JASS的返回值BUG和游戏缓存系统的。如果你不熟悉JASS,请预先补充一下你自己的JASS知识。你同样必须知道什么是代码行,如果你不知道的话,请补充自己的知识。

基于游戏缓存以及返回值BUG的系统

注意事项:

-我们将要制作的AI系统达不到人类的水平,但是比什么都没有强。而且我认为当你理解了基础以后可以自己改进它。

-你不用完全按照我说的做;我按做我的想法做,但是如果你的想法更好或者你觉得自己的做法更舒服,请按照你自己的想法做。我并不完美,这篇文章也不可能完美,但是我希望它可以对你有所帮助。

-你可以使用在我的演示地图里面的AI系统而不自己动手(如果你那样做了,请告诉我一声),但是我建议你自己动手写,因为地图可能很复杂而且你可以自己动手写一个AI系统中学到更多的知识。

初始化部分:

首先在WE中创建一个触发条件为"玩家1-玩家1(红色)离开游戏"的触发器,然后把它转换为JASS。我们需要这个触发器来监视玩家离开游戏,那样我们才能为这个玩家开启人工智能。现在它只监视一号玩家离开游戏,所以我们在正式地图中需要使用一个循环来监视从0-11号的玩家。

我们希望这个AI系统可以使用技能。听起来似乎很难,其实很简单。我们只需要使英雄学习技能,那么他们就可以自己使用。

注意:电脑控制的英雄释放自定义技能的情况总是和它释放这个自定义技能的基础技能的情况相同(这里翻译的有点含糊不清,自定义技能的基础技能的意思是....基础技能是游戏本身带有的技能,自定义技能都是以某个基础技能为基础的...这样说做过图的大大应该可以明白吧?).所以如果你的自定义技能是以沉默为基础技能的,电脑控制的英雄就会在对战地图中应该使用沉默的情况使用这个技能。千万不要将技能以"通魔(Channel)"为基础,因为电脑从来不会使用它们,即使改变技能的OrderString也没有什么用。

为了知道每个英雄都拥有什么技能,我们创建了一个游戏缓存(game cache)来保存它。

在演示地图中我的触发器在地图的初始化部分创建了一个游戏缓存并将它保存在全局变量

udg_GameCache 中。需要注意的是缓存必须在我们使用它之前初始化,所以我在地图的初始化时间中创建了它。

在我的地图中我写了一个函数SetupSkills.在这个AI触发器的InitTrig函数中我使用了库函数ExecuteFunc来开启另外一个线程执行这个函数。这是为了防止地图的初始化时间太长。

jass: Copy code

我的SetupSkills函数如下:

function SetupSkills takes nothing returns nothing

local string h // Create a local string variable

// Paladin // Here we’ll initialise the Paladin’s skills, repeat this for all other

heroes

set h = UnitId2String('Hpal') // Store the returned value of

UnitId2String(‘Hpal’) in the local

call StoreInteger(udg_GameCache, h, "BaseSkill1", 'AHhb') // One of his base

skills is Holy Light, store it as “BaseSkill1”

call StoreInteger(udg_GameCache, h, "BaseSkill2", 'AHds') // Store Divine

Shield as “BaseSkill2”

call StoreInteger(udg_GameCache, h, "BaseSkill3", 'AHad') // Store Devotion

Aura as “BaseSkill3”

call StoreInteger(udg_GameCache, h, "UltimateSkill", 'AHre') // Store

Resurrection as his “UltimateSkill”

„ // Repeat for each Hero.

endfunction

接着是我的AI触发器的InitTrig部分:

function InitTrig_AI takes nothing returns nothing

local integer i = 0

set gg_trg_AI = CreateTrigger( )

loop

exitwhen i > 11

call TriggerRegisterPlayerEventLeave( gg_trg_AI, Player(i) )

set i = i + 1

endloop

call TriggerAddAction( gg_trg_AI, function PlayerLeaves )

call ExecuteFunc("SetupSkills")

endfunction

为英雄开启AI系统

为了控制AI我们使用了一个定时器(timer).我写了一个函数StartAI来获取一个单位的类型:英雄(请在演示地图中查看这个函数)。这个函数只是创建一个定时器,并且"绑定"在这个英雄身上,并且开启这个定时器。

这是演示地图中的空的AILoop函数和StartAI函数(这里给的只是一个框架,等下我们将展示一些动作函数,但是你起码必须先把function和endfunction写上去以保证WE不报错) :

jass: Copy code

function AILoop takes nothing returns nothing

endfunction

function StartAI takes unit hero returns nothing

local timer m = CreateTimer()

call AttachObject(m, "hero", hero)

call TimerStart(m, 0, false, function AILoop)

set m = null

endfunction

注意,我的这个StartAI函数通过将periodic参数设置为false来达到使定时器只执行一次的目的(以后我们还会来讨论它的).

现在,你就可以在你的英雄选择系统中当由电脑控制的玩家选择英雄时调用这个函数,并且在玩家离开游戏的时候执行这个函数。检测玩家是否拥有一个英雄,如果它拥有,调用这个函数来开启那个英雄的AI系统。例如:

jass: Copy code

function PlayerLeaves takes nothing returns nothing

local player p = GetTriggerPlayer()

call DisplayTextToForce(bj_FORCE_ALL_PLAYERS, GetPlayerName(p)+" has left

the game.")

if udg_Hero[GetPlayerId(p)] != null then

call StartAI(udg_Hero[GetPlayerId(p)])

endif

set p = null

endfunction

注意:这个函数将使AI系统控制离开的玩家的英雄,但是这也不是必要的,你也可以做别的事情。

使这个AI做些什么

当定时器终止的时候我们希望它做了这些事情:

●如果英雄死亡,等待他复活。

●如果英雄将要死亡,命令他移动到地图中心的生命泉水。

●如果英雄状态良好,检测是否有敌人在附近。如果有,则命令英雄攻击它。 否则就检测是否有物品在附近,如果有的话,发送一个巧妙 的命令让英雄拣起它。然后命令英雄巡逻到地图的一个随机坐标。

●如果英雄是活着的而且有未使用的技能点,学习一个技能。

我们由变量的声明开始。注意在我函数里面的实变量"e",它定义了在定时器再次启动前所经过的时间,这样我们就可以在英雄死亡的时候等待短一点的时间,而在他攻击的时候等待长一点的时间。这个变量初始化值为5。

jass: Copy code

局部变量的声明:

function AILoop takes nothing returns nothing

local string a = GetAttachmentTable(GetExpiredTimer())

local unit h = GetTableUnit(a, "hero")

local rect i

local location r

local real x = GetUnitX(h)

local real y = GetUnitY(h)

local group g

local boolexpr b

local boolexpr be

local unit f

local string o = OrderId2String(GetUnitCurrentOrder(h))

local real l = GetUnitState(h, UNIT_STATE_LIFE)

local real e = 5

我们由检测英雄是否死亡开始,如果他死亡了,设置"e"为1.5(因为在复活以后等待5秒的时间太长了,我们并不想这样).

当英雄的生命值"l"为0时,设置"e"为1.5来使定时器更加频繁的检测英雄是否复活.

if l <= 0 then

set e = 1.5

endif

接着我检测英雄的生命是否低于最大生命值的20%.如果是的,命令英雄移动到生命泉并且设置"e"为3.

当英雄的生命值少于最大生命值的20%时,命令英雄移动到生命泉的位置。

if l < GetUnitState(h, UNIT_STATE_MAX_LIFE)/5 then

call IssuePointOrder(h, "move", GetUnitX(gg_unit_nfoh_0001),

GetUnitY(gg_unit_nfoh_0001))

set e = 3

如果英雄的状态良好,检测他是否处在一个普通命令中(防止它打断了通魔技能).如果是一个标准命令,我们再检测在500的半径内是否有敌人存在.如果存在敌人,简单的发出一个攻击命令(不要改变"e"的值,5秒对于这个情况刚刚好).

jass: Copy code

function AIFilterEnemyConditions takes nothing returns boolean

return GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0 and

IsPlayerEnemy(GetOwningPlayer(GetFilterUnit()),

GetOwningPlayer(GetAttachedUnit(GetExpiredTimer(), "hero")))

endfunction

else

if ((o == "smart") or (o == "attack") or (o == "patrol") or (o == "move")

or (o == "stop") or (o == "hold") or (o == null)) then

set g = CreateGroup()

set b = Condition(function AIFilterEnemyConditions)

call GroupEnumUnitsInRange(g, x, y, 500, b)

set f = FirstOfGroup(g)

if f == null then

else

call IssueTargetOrder(h, "attack", f)

endif

call DestroyGroup(g)

call DestroyBoolExpr(b)

endif

如果没有敌人存在,再检测物品.如果发现物品,再检测是否为一个提升状态的物品.如果不是,检测英雄物品栏是否有空栏,有的话就命令英雄将它拣起来.

jass: Copy code

function AISetItem takes nothing returns nothing

set bj_lastRemovedItem=GetEnumItem()

endfunction

function AIItemFilter takes nothing returns boolean

return IsItemVisible(GetFilterItem()) and GetWidgetLife(GetFilterItem()) > 0

endfunction

function AIHasEmptyInventorySlot takes unit u returns boolean

return UnitItemInSlot(u, 0) == null or UnitItemInSlot(u, 1) == null or

UnitItemInSlot(u, 2) == null or UnitItemInSlot(u, 3) == null or UnitItemInSlot(u,

4) == null or UnitItemInSlot(u, 5) == null

endfunction

if f == null then

set i = Rect(x-800, y-800, x+800, y+800)

set be = Condition(function AIItemFilter)

set bj_lastRemovedItem=null

call EnumItemsInRect(i, be, function AISetItem)

if bj_lastRemovedItem != null and

(GetItemType(bj_lastRemovedItem) == ITEM_TYPE_POWERUP or

AIHasEmptyInventorySlot(h)) then

call IssueTargetOrder(h, "smart",

bj_lastRemovedItem)

else

endif

call RemoveRect(i)

call DestroyBoolExpr(be)

如果物品栏没有空位,或者没有发现物品,则命令英雄到一个随机地点寻找新的目标.

else

set r = GetRandomLocInRect(bj_mapInitialPlayableArea)

call IssuePointOrderLoc(h, "patrol", r)

call RemoveLocation(r)

收藏 分享

linzefei 发短消息

加为好友

linzefei (橙zi 174)当前离线

我从来没出现过

主题108 精华2 积分50383 阅读权限120 在线时间3947 小时 最后登录2012-9-11

荣誉版主

UID101045 帖子6181 EXP5 影币1445 威望141 荣誉1 贡献4 金币1156 注册时间2007-3-14

沙发

发表于 2008-11-16 05:45 | 只看该作者

[ - 制图理论 - ]对于传统PVE,RPG地图设计的一些看法

现在我们需要检测的是英雄是否有未使用的技能点(将这个函数与进攻/拣取物品/前进到随机地点等模块分开).

如果英雄有未使用的技能点,调用函数来使英雄学习技能.在我的演示地图中,我是用一个函数来保存将要让英雄学习的技能的,使用的是下面这个模式:

jass: Copy code

function AILearnSkill takes unit h, string a returns nothing

local integer i = GetTableInt(a, "LearnSkillOrder")+1

if i == 1 or i == 4 or i == 8 then

call SelectHeroSkill(h, GetStoredInteger(udg_GameCache,

UnitId2String(GetUnitTypeId(h)), "BaseSkill1"))

elseif i == 2 or i == 5 or i == 9 then

call SelectHeroSkill(h, GetStoredInteger(udg_GameCache,

UnitId2String(GetUnitTypeId(h)), "BaseSkill2"))

elseif i == 3 or i == 7 or i == 10 then

call SelectHeroSkill(h, GetStoredInteger(udg_GameCache,

UnitId2String(GetUnitTypeId(h)), "BaseSkill3"))

elseif i == 6 then

call SelectHeroSkill(h, GetStoredInteger(udg_GameCache,

UnitId2String(GetUnitTypeId(h)), "UltimateSkill"))

endif

call SetTableInt(a, "LearnSkillOrder", i)

endfunction

if GetHeroSkillPoints(h) > 0 and l > 0 then

call AILearnSkill(h, a)

endif

现在所需要做的是使定时器在"e"秒之后再次开启:

call TimerStart(GetExpiredTimer(), e, true, function AILoop)

最后我们将局部变量设置为空:

set h = null

set i = null

set r = null

set g = null

set b = null

set f = null

set be = null

最后需要注意的事情

这些就是英雄AI系统的基础,它并不完美,但是它可以做为你的起点.

这个系统一点都不复杂,这样可以让你更加彻底的明白我的意思.

当你完成了一个属于你自己的AI系统时,尝试一下在你的系统中加入一个或者多个以下特征:

--尝试使它可以寻找周围最虚弱的敌人.

--尝试在杀死特殊的敌人时让不同的AI玩家合作.

--当大部分战斗都以生命泉为中心的时候,让英雄离开生命泉.

--让AI玩家根据情况的不同说出不同的话(比如在杀死你的时候AI玩家会说"死吧~可怜的孩子")

我的帖子总索引

求工具以及下载属性领取贴

那个``

TOP

linzefei 发短消息

加为好友

linzefei (橙zi 174)当前离线

我从来没出现过

主题108 精华2 积分50383 阅读权限120 在线时间3947 小时 最后登录2012-9-11

荣誉版主

UID101045 帖子6181 EXP5 影币1445 威望141 荣誉1 贡献4 金币1156 注册时间2007-3-14

板凳

发表于 2008-11-16 18:59 | 只看该作者

[ - 魔兽制图 -]全屏天赋系统

接某教程

2)线程(Threads)

(这部分属于AI部分, 作为入门者做一般性了解就行了, 因为AI都是纯JASS写的, 也没有真正好的AI EDITOR. 本人也对此一知半解, 关于AI的文章也不多, 没什么好参考的.)

线程只应用于AI脚本(AI JASS), 不能用于触发器脚本(Trigger Jass). 通常, 当AI脚本开始运行时只创建一个线程, 创建更多的线程可以用comman.j的本地函数:

+ Shingo Jass Highlighter 0.41

native StartThread takes code func returns nothing

调用 call StartThread(function myfunc) 将创建一个从函数myfunc开始执行的线程.

每个玩家最多可以拥有6个线程, 包括一开始执行的主线程. 当一个玩家有6个线程数时, 调用StartThread()的语句将被忽略. 线程不能回收, 当你为某玩家创建了5个自定义线程, 将无法为该玩家创建更多的线程.

当新线程创建时, 线程立即生效. 当线程让步执行时, 创建此线程的父线程将继续执行.

在同一玩家中的所有线程都共享全局状态(包括变量). 即是修改某个全局变量, 修改后的值在此玩家的所有线程中都是可见的.

线程在以下的情况让步执行, 返回父线程

a) 当线程中的操作码(opcode)超出限制, 线程会自动休眠 1 秒

b) 当线程中用使用 Sleep(n), 线程将休眠 n 秒, 然后继续执行.

线程在以下情况会中止, 返回父线程

a) 如果 call StartThread(null)中, 线程中止

b) 当线程的主函数返回, 线程中止.

(StartThread()中之间调用的函数就是主函数.)

c) 当线程中使用没有声明的变量, 线程中止. 在使用之前, 变量必须声明.

d) 当线程中出现零为被除数时, 线程中止

e) 线程主函数出现语法错误.

注意: 虽然AI脚本可以使用大部分common.j的库函数, 但有些类型的函数在AI不能正常工作, 如:

a) 返回字符串类型(string)的本地函数, 如I2S(), SubString()等

b) 需要以code, trigger, boolexpr 等类型数据为参数的本地函数, 如触发器函数,

队列函数(ForGroup, 等)

注意: AI中不可以使用Blizzard.j的函数, 触发器中也不可以使用的函数,

AI和触发器都可以使用common.j的函数(当然, 对于AI, 还受上面所说的限制)

和common.j是写AI时可以调用和参考库文件, 要研究AI, 先去读这2个文件.

3) 跨脚本通讯(Inter-Script Communication)

在游戏中, 可能会有多个独立的Jass脚本文件同时运行. 比如在对战地图中的游戏,

运行触发器脚本文件的同时, 也可能运行了每个电脑玩家的AI脚本文件. 每个脚本文件之间的全局变量不是共享的. 所以, 一个电脑玩家的AI脚本中设置的全局变量不会影响另一个电脑玩家的AI脚本的执行.

触发器脚本也不可以和AI脚本共享全局变量. 但可以用传递命令的方法进行脚本之间的数据交换. 命令由一对数值型数据(integer)组成: 命令值(command value)和数据值(data value).

+ Shingo Jass Highlighter 0.41

从触发器脚本向AI脚本发出通讯命令, 可以使用common.j中定义的以下本地函数:

native CommandAI takes player num,

integer command, integer data returns nothing

参数:

player num //玩家

integer command //命令

integer data //命令数据

以下是AI中使用的common.j函数, 注意: 每个电脑玩家都会有独立的AI脚本, 所以,

以下函数都没有要求玩家作为函数参数.

每个电脑玩家都有命令堆来堆放接受到的命令. 想知道有多数个命令堆放在命令堆, 可以用下面的函数:

native CommandsWaiting takes nothing returns integer

参数: 无

返回: 命令堆的命令数(integer)

获得存放在命令堆中最顶端的命令():

//返回命令

native GetLastCommand takes nothing returns integer

//返回命令数据

native GetLastData takes nothing returns integer

上面2个函数都不会移除命令堆中的命令, 要移除堆中的命令, 可以用:

native PopLastCommand takes nothing returns nothing

4) 队列(Enumerations)

虽然JASS不能自定义数据结构(因为JASS缺少指针操作符), 但API库中提供了一些实现队列操作的函数. 如一组单位为单位组(group), 一组玩家为势力(force), 虽然一组可破坏物没有明确定义它的数据类型, 但也可以用API函数来操作.

单位组和势力的操作函数很类似.

单位组处理函数

// 初始化单位组

native CreateGroup takes nothing returns group

// 在指定单位组中增加指定单位

native GroupAddUnit takes group whichGroup, unit whichUnit returns nothing

// 在指定单位组中移除指定单位

native GroupRemoveUnit takes group whichGroup, unit whichUnit returns

nothing

势力处理函数

// 初始化势力

native CreateForce takes nothing returns force

// 在指定势力中增加指定玩家

native ForceAddPlayer takes force whichForce, player whichPlayer returns

nothing

// 在指定势力中移除指定玩家

native ForceRemovePlayer takes force whichForce, player whichPlayer returns

nothing

JASS不能直接操作队列里面的元素, 它是通过callback类型的函数来实现对队列的操作:

// 对指定单位组中的每个单位都运行指定callback函数callback

// (对应GUI语言的For Each Unit in )

native ForGroup takes group whichGroup, code callback returns nothing

// 对指定势力中的每个玩家都运行指定callback函数callback

// (对应GUI语言的For Each Player in )

native ForForce takes force whichForce, code callback returns nothing

输入上面两个函数的callback函数必须是无参数无返回值函数(takes nothing

returns nothing)

同样, 操作可破坏物也可以用在区域内的可破坏物作为队列, 可以以用类似的方法:

// 在指定区域r内符合指定过滤器filter的都运行指定callback函数actionFunc

// (过滤器见下节的讲解)

native EnumDestructablesInRect takes rect r,

boolexpr filter, code actionFunc returns nothing

在callback函数, 可以用下面的函数获得队列中的下一个元素:

// 获得单位组中的下一个单位

// (对应GUI语言的Pick Every Unit in )

constant native GetEnumUnit takes nothing returns unit

// 获得势力中的下一个玩家

// (对应GUI语言的Pick Every Player in )

constant native GetEnumPlayer takes nothing returns player

// 获得可破坏物组中的下一个可破坏物

// (对应GUI语言的Pick Every Destructables in )

constant native GetEnumDestructable takes nothing returns destructable

注意: AI中不支持队列函数的使用.

这是杀死单位组中所有单位的实例:

// 这是callback函数, 无参数并无返回值

function KillGroupCallback takes nothing returns nothing

// 获得单位组中的下一个单位

local unit nextUnit = GetEnumUnit()

// 杀死该单位

call KillUnit(nextUnit)

endfunction

// 调用ForGroup

// 对单位组groupToKill中的每个单位都运行函数KillGroupCallback

call ForGroup(groupToKill, function KillGroupCallback)

另一个经常是用的例子是在队列中查找特定条件的元素. 不幸的是, 因为JASS只支持callback函数来处理队列中的元素, 所以只有用全局变量来保存不同单位的属性. 下面是找出单位组里生命最高的单位的例子:

//定义全局变量

globals

//用于储存两单位比较后较高的生命值, 初始化为 0

real mostLifeSoFar

//用于储存两单位比较后有较高生命值的单位, 初始化为 null

unit unitWithMostLifeSoFar

endglobals

//比较单位生命值的callback函数

function MostLifeCallback takes nothing returns nothing

//获得单位组中的下一个单位

local unit nextUnit = GetEnumUnit()

//获得单位属性 - 生命

//UNIT_STATE_LIFE是common.j中定义的常量

local real life = GetUnitState(nextUnit, UNIT_STATE_LIFE)

//比较生命值

if life > mostLifeSoFar then

//把较大的生命值储存

set mostLifeSoFar = life

//把有较大生命的单位储存

set unitWithMostLifeSoFar = nextUnit

endif

endfunction

...

//初始化全局变量的值为空值

set mostLifeSoFar = 0

set unitWithMostLifeSoFar = null

//调用ForGroup

//对单位组myGroup中的每个单位都运行函数MostLifeCallback比较生命

call ForGroup(myGroup, function MostLifeCallback)

//上句运行后, 全局单位类型变量unitWithMostLifeSoFar便指向单位组myGroup中最高生命的单位, 或:

//如果单位组myGroup是空组, 那么unitWithMostLifeSoFar便是空值null

...

当然, 实现队列操作, 也可以用数组的方法来处理. 但, 数组不能使用紧接着要说的队列过滤器, 也不能定义数组中包含数组. 这些都是队列所拥有的优势, 如可以有数组型的单位组(相当于数组中包含数组), 也可以用队列过滤器.

5)队列过滤器(Filters)

队列过滤器用于在队列中增加符合条件的元素. 比如, 在创建一个法力小于20的单位组时, 便可以用队列过滤器(Filters)来创建.

+ Shingo Jass Highlighter 0.41

//在单位组中增加指定单位名为unitname, 并符合队列过滤器filter的单位

native GroupEnumUnitsOfType takes group whichGroup, string unitname,

boolexpr filter returns nothing

//在单位组中增加指定玩家为whichPlayer, 并符合队列过滤器filter的单位

native GroupEnumUnitsOfPlayer takes group whichGroup, player whichPlayer,

boolexpr filter returns nothing

//在单位组中增加指定玩家为whichPlayer, 并符合队列过滤器filter的单位

native GroupEnumUnitsOfTypeCounted takes group whichGroup, string unitname,

boolexpr filter, integer countLimit returns nothing

//在单位组中增加指定区域为r, 并符合队列过滤器filter的单位

native GroupEnumUnitsInRect takes group whichGroup, rect r, boolexpr filter

returns nothing

//在单位组中增加countLimit个指定区域为r, 并符合队列过滤器filter的单位

native GroupEnumUnitsInRectCounted takes group whichGroup, rect r,

boolexpr filter, integer countLimit returns nothing

//在单位组中增加在指定点坐标范围之内, 并符合队列过滤器filter的单位

native GroupEnumUnitsInRange takes group whichGroup, real x, real y,

real radius, boolexpr filter returns nothing

//在单位组中增加在指定点范围之内, 并符合队列过滤器filter的单位

native GroupEnumUnitsInRangeOfLoc takes group whichGroup,

location whichLocation, real radius, boolexpr filter returns nothing

//在单位组中增加指定个数, 在指定点坐标范围之内, 并符合队列过滤器filter的单位

native GroupEnumUnitsInRangeCounted takes group whichGroup, real x, real y,

real radius, boolexpr filter, integer countLimit returns nothing

//在单位组中增加指定个数, 在指定点范围之内, 并符合队列过滤器filter的单位

native GroupEnumUnitsInRangeOfLocCounted takes group whichGroup,

location whichLocation, real radius, boolexpr filter,

integer countLimit returns nothing

//在单位组中增加被指定玩家选中, 并符合队列过滤器filter的单位

native GroupEnumUnitsSelected takes group whichGroup, player whichPlayer,

boolexpr filter returns nothing

类似地, 对于势力也有相应的操作函数

//在势力中增加符合队列过滤器filter的玩家

native ForceEnumPlayers takes force whichForce, boolexpr filter returns

nothing

//在势力中增加指定个数, 并符合队列过滤器filter的玩家

native ForceEnumPlayersCounted takes force whichForce, boolexpr filter,

integer countLimit returns nothing

// Add all units that are allies of 'whichPlayer' that satisfy 'filter'

//在势力中增加和指定玩家同盟, 并符合队列过滤器filter的玩家

native ForceEnumAllies takes force whichForce, player whichPlayer,

boolexpr filter returns nothing

//在势力中增加和指定玩家敌对, 并符合队列过滤器filter的玩家

native ForceEnumEnemies takes force whichForce, player whichPlayer,

boolexpr filter returns nothing

以上函数中boolexpr filter在本章第1)节触发器中有提到, 通常可以使用过滤器(filterfunc).过滤器跟触发器的条件函数(conditionfunc)类似. 创建过滤器可以用以下语句:

native Filter takes code func returns filterfunc

其中参数函数code func必须是无参数返回值为布尔值的函数(takes nothing returns

boolean), 过滤器用于在创建队列时增加额外的条件. 在过滤器中, 可以使用下面的函数获得下一个待查的单位/玩家/不可破坏物:

//获得下个待查单位

constant native GetFilterUnit takes nothing returns unit

//获得下个待查玩家

constant native GetFilterPlayer takes nothing returns player

//获得下个待查可破坏物

constant native GetFilterDestructable takes nothing returns destructable

我们来看个创建一个法力小于20的单位组例子:

//过滤函数, 是无参数返回值为布尔值的函数

function LessThan20ManaCallback takes nothing returns boolean

//获得下个检查的单位

local unit nextUnit = GetFilterUnit()

//检查待查单位的法力是否小于20

//小于20则返回true, 否则返回false

return GetUnitState(nextUnit, UNIT_STATE_MANA) < 20

endfunction

...

//创建过滤器, 过滤函数是LessThan20ManaCallback

local filterfunc myFilter = Filter(function LessThan20ManaCallback)

//在单位组中增加指定区域, 符合过滤条件的单位

call GroupEnumUnitsInRect(myGroup, someRect, myFilter)

// Destroy the filter if we are not going to use it again

//不再使用过滤器, 销毁过滤器, 避免内存泄漏

call DestroyFilter(myFilter)

1

评分人数