3. RPG AI
RPG AI(例如真三AI等)
file:///G:/%E9%AD%94%E5%85%BD%E5%88%B6%E5%9B%BE2/wow8%E7%BD%91%E9%A1%B5%E6%96%87%E4%BB%B6&%E5%90%84%E7%A7%8D%E4%B8%8B%E8%BD%BD%E8%B5%84%E6%96%99&%E6%95%B4%E7%90%86%E8%80%85%E9%99%84%E5%8A%A0%E8%A1%A5%E5%85%85/AI%E7%9B%B8%E5%85%B3/_%EF%BC%89%E2%9E%B9AI%E8%84%9A%E6%9C%AC%E5%88%9D%E7%BA%A7%E6%95%99%E7%A8%8B%E2%96%85%E2%96%81%E2%96%81%E2%96%81BY%E2%96%81%E2%96%81%E2%96%81weituotian%E3%80%90%E6%9B%B4%E6%96%B0ing%E3%80%91%20-%20%E7%B3%BB%E7%BB%9F%20_%20%E5%92%B8%E9%B1%BC%E7%AA%9D/_%EF%BC%89%E2%9E%B9AI%E8%84%9A%E6%9C%AC%E5%88%9D%E7%BA%A7%E6%95%99%E7%A8%8B%E2%96%85%E2%96%81%E2%96%81%E2%96%81BY%E2%96%81%E2%96%81%E2%96%81weituotian%E3%80%90%E6%9B%B4%E6%96%B0ing%E3%80%91%20-%20%E7%B3%BB%E7%BB%9F%20_%20%E5%92%B8%E9%B1%BC%E7%AA%9D_files/10070616044833145a710df7e5.png
测试图可以做到以下功能,还不完善!
RPG AI的英雄应该做到
1.英雄会去攻击敌人
2.红血时会回家
3.会购买物品,会捡物品(英雄自动到商店购买)
4.会学习技能
高级:
5.会补刀,进攻和撤退
6.会使用技能
7.会卡兵
8.会使用物品
接下来我们先开始制作初级的英雄的AI(像真三那样只控制一个英雄,不是lost temple 3c是控制多个英雄的)
j/globals
unit aihero //记录玩家的英雄
ai_player //记录AI玩家
boolean flee=false //设置是否逃跑,一开始false表示不在,如果ture表示在
boolean attack_enemy=false //设置攻击状态,一开始false表示不在攻击,如果ture表示在攻击
boolean buyitem=false //设置是否在购买物品,一开始false表示不在,如果ture表示在
boolean kabing=false //设置是否在卡兵,一开始false表示不在,如果ture表示在
boolean useskills=false //设置是否在使用技能,一开始false表示不在,如果ture表示在
boolean buxue=false //判断英雄是否在补血
real ratio=1 //radio是用于判断生命比的整数
integer count=0 //记录游戏开始秒数
location start_loc //玩家开始的地方
group udg_g //用于记录AI玩家所有单位
endglobals
/j
先声明以上的全局变量就OK了,下面我会创建4个线程.我开始了很多个线程!这只是我实现的一种方法罢了,
仅作参考!以上的线程可以集中为一个线程,这里为了方便说明就分开来了.
j/function main takes nothing returns nothing
set ai_player=Player(GetAiPlayer()) //用变量记录当前的AI玩家为 ai_player
call SetMeleeAI() //开始对战AI
call SetHeroesBuyItems(true) //设置英雄自动买物品
call SetHeroesFlee(true) //设置英雄生命值少时自动逃跑
call SetHeroesTakeItems(true) //设置英雄自动捡物品
call SetIgnoreInjured(true) //在集结部队进攻时,忽略生命值低于50%的单位
call SetRandomPaths(true) //增加AI的选择目的地的随机性
call CreateCaptains() //创建攻击组
call ShareEverythingWithTeamAI () //可以和AI分享物品等
call StartThread(function attack_loop) // 开始线程,运行(function attack_loop)
call StartThread(function check_hp) // 开始线程,运行(function check_hp)
call StartThread(function buy_item) // 开始线程,运行(function buy_item)
call StartThread(function attack) // 开始线程,运行(function attack)
endfunction
/j
刚才有的函数是不是很熟悉,就是二楼中建立对战AI可以用到的。这里我只选用了英雄部分.
call ShareEverythingWithTeamAI可以和AI分享物品等在本图中可以用到.
还有一点是我开始了很多个线程!这只是我实现的一种方法罢了,仅作参考!你们可以从中
实现第一个功能1.英雄会去攻击敌人(英雄可以在原地图中创建,下面函数是得到AI玩家的英雄
j/
function setup_force takes nothing returns nothing //选取英雄
local unit u=null
call GroupEnumUnitsOfPlayer(udg_g,ai_player,null) //选取AI玩家的所有单位
loop
set u=FirstOfGroup(udg_g) //设置u是单位组的第一个单位
exitwhen u==null //当u为没有单位时
if IsUnitType(u,UNIT_TYPE_HERO)==true then //如果单位u是英雄
set aihero=u //设置aihero就是英雄了
endif
call GroupRemoveUnit(udg_g,u) //移除单位u后,单位组内就没有u这个单位了
endloop
endfunction
/j
开始攻击了吧,以下是攻击的线程
j/
function attack_loop takes nothing returns nothing
local integer cmd
call WaitForSignal() // <== 等到地图发出一个命令
set cmd = WaitForSignal() // 得到命令被承认,让AI起作用
if cmd == 0 then
call setup_force//调用刚才上面的函数,选取英雄
loop //开始进入循环
loop
call Sleep(1) //停止1秒
exitwhen ((not buyitem and not flee)and not useskills) and ((not kabing and radio=<0.3) and ( GetUnitCurrentOrder(aihero) == OrderId("stop")) //当不在购买物品的时候,血少逃跑的时候和卡兵的时候,单位停止的时候退出循环
endloop
call IssueNeutralPointOrder( Player(0), GetTriggerUnit(), "attack", 2817.00, 2555.00 )//命令攻击到坐标2817.00, 2555.00
call Sleep(1)
endloop
endfunction
/j
以上的变量udg_g,ai_player已在全局变量声明部分声明了
这里用到跨脚本通讯,我们在原地图触发中使用AI-发送AI命令
其中发送的是两个数字,第一个数字是命令,第二个数字是命令数据
我规定命令数字0就是选择英雄了.
在以上函数中就能接受到触发来的命令,开始选择英雄
我们要明确英雄什么时候去攻击,购买物品的时候不能,血少,逃跑的时候不能
卡兵的时候都不能.还要判断英雄当前的命令是stop,即什么都不做!避免冲突.
radio是英雄的生命值百分比,坐标2817.00, 2555.00是地图中设置的敌人基地
如果敌人的基地是不确定的,我们可以在二楼教程中对战AI的寻找敌人的函数,还记得吗?
j/
native AddDefenders takes integer qty, integer id returns boolean
//获取中立敌对营地<最小总等级,最大总等级,是否包括飞行单位>
native GetCreepCamp takes integer min, integer max, boolean flyers_ok returns unit
//开始寻找敌人基地
native StartGetEnemyBase takes nothing returns nothing
//是否正在寻找敌人基地
native WaitGetEnemyBase takes nothing returns boolean
//获取敌人基地
native GetEnemyBase takes nothing returns unit
//获取下一个扩张点有威胁的单位
native GetExpansionFoe takes nothing returns unit
//获取敌人扩张点(分基地)
native GetEnemyExpansion takes nothing returns unit
//获取可能的扩张点X坐标
native GetExpansionX takes nothing returns integer
//获取可能的扩张点X坐标
native GetExpansionY takes nothing returns integer
/j
英雄会攻击了,没血了也要回来吧!
实现第2个功能.红血时会回家
我的思路是用一个线程去检测HP吧!此线程在main也提出过
我们会用到全局变量radio,表示英雄的生命百分比
我们知道,英雄的生命是最重要的,是攻击,购买物品,卡兵等等的前提
所以红血时,所有的一切都要被停止吧,而且要逃跑回家!
j/
function check_hp takes nothing returns nothing
local real r1=0
local real r2=0
loop
call Sleep(1) //停止1秒
set r1=GetUnitState(aihero,UNIT_STATE_LIFE) //设置r1是英雄的现在生命值
set r2=GetUnitState(aihero,UNIT_STATE_MAX_LIFE) //设置r2是英雄的最大生命值
set ratio=r1/r2
if radio>0.3 then
set flee=flase //设置逃跑为flase
else
set flee=ture //设置逃跑为false
set buyitem=false //设置购买物品为false
set kabing=false //设置卡兵为false
set attack_enemy //设置攻击敌人为false
call IssuePointOrder( GetTriggerUnit(), "move", -2843.00, -3147.00 ) //命令英雄回家 ,-2843.00, -3147.00是地图中家的坐标
endif
endloop
endfunction
/j
英雄少血的时候就会回家了,这时不能暂停这个线程,等英雄回复血后还要出去战斗
我们还要考虑到英雄如果真的不幸死了。让英雄复活可以在地图的触发中设置.
英雄杀怪有钱赚了,我们让他去买些物品吧!
实现第3个功能.会购买物品,会捡物品(英雄自动到商店购买)
会捡物品在main中用
call SetHeroesTakeItems(true)
可以轻松实现.那么去买物品时,看看怎么判断一个英雄是否具有某样物品.
以下是简单的实现方法,实际上是判断每个物品栏是否有这个物品
j/
function isunithaveitem takes unit whichUnit integer itemId returns boolean
local integer index=0
loop
set index=index+1
if (UnitItemInSlot(whichUnit, index) != null) and (GetItemTypeId(UnitItemInSlot(whichUnit, index)) == itemId) then//判断是否有这样物品
return ture //有就返回ture
endif
set index = index + 1
exitwhen index >5
endloop
return false//没有就返回false
endfunction
/j
判断单位物品栏的物品数量
j/
function UnithaveitemCount takes unit whichUnit returns integer
local integer index = 0
local integer count = 0 //记录物品数量
loop
if (UnitItemInSlot(whichUnit, index) != null) then//如果第几个物品栏不为空
set count = count + 1//记录物品数量+1
endif
set index = index + 1
exitwhen index >5
endloop
return count
endfunction
/j
还要一定有足够的钱,而且血很多(死了怎么买?)而且
不在战斗,不在卡兵,不再逃跑,不在使用技能(如果在逃跑还去买东西,那就是被人杀死),在家里等等!
以下是实现买东西的线程,只是一个思路.这里只设置了购买医疗剂.
j/
function buyloop takes unit hero,unit Store,item whichitem returns nothing//监视英雄买东西
set buyitem=ture //设置买东西为ture
loop
call IssueTargetOrderById( store, 852566, aihero() ) //852566是选择动作的ID ,命令中立商店选择英雄
call IssueNeutralImmediateOrderById( ai_player, store, GetItemTypeId(whichitem)) //命令电脑玩家在中立商店购买医疗剂
call IssuePointOrderByIdLoc( aihero, 851986, GetUnitLoc(store) )//英雄移动到中立商店
call Sleep(1)
exitwhen isunithaveitem( aihero,GetItemTypeId(whichitem))//英雄买到了退出循环
endloop
set buyitem=false//设置买东西为false
endfunction
function function buy_item takes nothing returns nothing
loop
if (not flee and not kabing)and (not attack_enemy and not useskills) then //如果flee为flase 和 kabing为false 和 attack_enemy为false
if UnithaveitemCount(aihero)<6 then //如果英雄携带物品少于6
if GetPlayerState(ai_player, PLAYER_STATE_RESOURCE_GOLD)>100 and not isunithaveitem( aihero,'hslv') then//如果玩家的金钱大于100和英雄没有医疗剂
call buyloop(aihero,gg_unit_ngme_0003,'hslv')//调用上面监视英雄买东西的函数,参数英雄,商店,物品)
endif
endif
else
setbuyitem=false
endif
call sleep(5)
endloop
endfunction
/j
你看到上面在线程中调用了某个函数也有loop,会执行完这个函数才回到线程。这是线程的优点
以上可以不断添加购买的物品,不过每一次的条件最好不同.否则会引起错乱.这样子就完成了购买物品的AI
接下来实现第4个功能.会学习技能
至于学习技能.我们完全可以在触发中设置.下面都是在触发中设置的.简略地提一下.
我们要先知道英雄的技能,所以为他们注册技能,以下技能学习只是一个方法.
j/
call RestoreHeroSkills('Hmkg','AHav','AHtb','AHbh','AHtc')
…………
/j
'Hmkg'是英雄代码,后面四个依次是技能.
接下来要用到两个gamecache的函数
j/
function SetHandleInt takes string subject,string name,integer value returns nothing
if value==0 then
call FlushStoredInteger(udg_GameCache,subject,name)//清除udg_GameCache中的subject,name下的整数
else
call StoreInteger(udg_GameCache,subject,name,value)//储存udg_GameCache中的subject,name下的整数为value
endif
endfunction
function GetHandleInt takes string subject,string name returns integer
return GetStoredInteger(udg_GameCache,subject,name)//得到已存储的英雄技能ID
endfunction
function RestoreHeroSkills takes integer a0,integer a1,integer a2,integer a3,integer a4 returns nothing
call SetHandleInt("heroskills",I2S(a0)+"1",a1) //储存a1为英雄技能中的第1个
call SetHandleInt("heroskills",I2S(a0)+"2",a2) //储存a1为英雄技能中的第2个
call SetHandleInt("heroskills",I2S(a0)+"3",a3) //储存a1为英雄技能中的第3个
call SetHandleInt("heroskills",I2S(a0)+"4",a4) //储存a1为英雄技能中的第4个
endfunction/j
储存完技能就让英雄学习下吧!
在地图触发中新建英雄升级事件,在使用自定义代码call AILearnSkills()
j/
function AILearnSkills takes unit u returns nothing
local integer i=GetUnitTypeId(u) //设置i是英雄Id
local string s="" //设置字符串s是""
set s=I2S(i) //设置s为英雄id转换过来
call SelectHeroSkill(u,GetHandleInt("heroskills",s+"1"))//命令英雄学习第1个技能
loop
if GetHeroSkillPoints(u)>0 then//如果英雄还有技能点数
call SelectHeroSkill(u,GetHandleInt("heroskills",s+"2"))//命令英雄学习第2个技能
endif
if GetHeroSkillPoints(u)>0 then//如果英雄还有技能点数
call SelectHeroSkill(u,GetHandleInt("heroskills",s+"3"))//命令英雄学习第3个技能
endif
if GetHeroSkillPoints(u)>0 then//如果英雄还有技能点数
call SelectHeroSkill(u,GetHandleInt("heroskills",s+"4"))//命令英雄学习第4个技能
endif
exitwhen GetHeroSkillPoints(u)==0//英雄没有技能点数退出
call sleep(0.5)//停止0.5秒
endloop
endfunction
/j
英雄学习技能在触发中完成比较好.
接下来实现第5个功能.补刀,这是比较难的部分.
我们创建一个线程来实现这个功能吧!
我们知道,如果英雄补刀可以算作一个攻击状态,那么为了不与其它线程
相冲突,我们可以设置在不买东西,不逃跑(逃跑时也判断血量少),
不卡兵,不使用技能的时候补刀吧!
j/
function attack takes unit u returns nothing
loop
if (not buyitem and not skills) and (not flee and not kabing) then
//这里设置动作
call Sleep(1)
endloop
endfunction
/j
基本的我们实现了,那么下面给大家介绍一个补刀的函数,作点仔细的介绍.
j/
function GetWeakestUnit takes unit center,real range returns unit //得到一个单位组里最弱的单位
local unit temp //设置局部变量单位temp,用于记录单位组中存活的单位
local unit weakest //设置局部变量单位temp,用于记录单位组嫩生命值最少的单位
local group g=CreateGroup() //建立一个单位组,用于记录全部单位
local group group=CreateGroup()//建立一个单位组,这个单位组用于记录存活非英雄单位
call GroupEnumUnitsInRange(g,GetUnitX(center),GetUnitY(center),range,null) //将英雄范围内的单位全送进单位组
call GroupRemoveUnit(g,center) //移除英雄自己出单位组,因为不可能自己杀自己吧
loop //进入循环
set weakest=FirstOfGroup(g) //设置weakest是全部单位组内第一个单位
exitwhen weakest==null //当weakest为没有单位时退出循环
if GetUnitState(weakest,UNIT_STATE_LIFE)>0 and IsUnitType(weakest, UNIT_TYPE_HERO) == false then
GroupAddUnit(group, weakest) //如果weakest是存活非英雄单位,就进入单位组group
endif
call GroupRemoveUnit(g,weakest) //移除weakest出单位组
endloop
loop
set temp=FirstOfGroup(group) //设置temp是group的第一个单位
exitwhen temp == null //当temp为没有单位时退出
if GetUnitState(weakest,UNIT_STATE_LIFE)>GetUnitState(temp,UNIT_STATE_LIFE) then
set weakest = temp//如果weakest得生命值大于temp就设置weakest为temp
endif
call GroupRemoveUnit(group,temp)//删除单位组移除单位temp出group
endloop
call DestroyGroup(g) //删除单位组
call DestroyGroup(group) //删除单位组
set temp = null //设置temp为没有单位
set g = null //设置g为空单位组
return weakest
endfunction
/j
unit center我们设置为英雄,real range可是设置在多少范围内,取实数.接下来还要写
两个函数:
function GetEnemyBingInRangeCount得到范围内敌人小兵的数量
function GetAllyBingInRangeCount得到范围内盟友小兵的数量
判断数量用于进攻和撤退.
j/
function IsAlive takes unit u returns boolean//用于判断单位是否存活
return(GetWidgetLife(u)>.405)
endfunction
function GetEnemyBingInRangeCount takes unit Theunit,real Radius returns integer//得到范围内敌人小兵的数量
local integer result=0
local unit u = null
local group g = CreateGroup()
call GroupEnumUnitsInRange(g,GetUnitX(Theunit),GetUnitY(Theunit),Radius,null)//选取范围内的单位进入单位组
loop
set u = FirstOfGroup(g) //设置u是单位组g内第一个单位
exitwhen u == null //当u为没有单位时退出循环
if(IsEnemyBing(u)and IsAlive(u))then
set result=result+1 //设置数量+1
endif
call GroupRemoveUnit(g, u )//移除u出单位组g
endloop
call DestroyGroup(g)
set g = null
return result
endfunction
function GetAllyBingInRangeCount takes unit Theunit,real Radius returns integer//得到范围内盟友小兵的数量
local integer result=0
local unit u = null
local group g = CreateGroup()
call GroupEnumUnitsInRange(g,GetUnitX(Theunit),GetUnitY(Theunit),Radius,null)//选取范围内的单位进入单位组
loop
set u = FirstOfGroup(g)//设置u是单位组g内第一个单位
exitwhen u == null //当u为没有单位时退出循环
if(IsAllyBing(u)and IsAlive(u))then
set result=result+1//设置数量+1
endif
call GroupRemoveUnit(g, u )//移除u出单位组g
endloop
call DestroyGroup(g)
set g = null
return result
endfunction
/j
看懂了以上的函数,我们就可以简单地实现进攻和撤退,补刀.
j/
function moverandom takes unit h returns nothing
local real x = GetUnitX(h)
local real y = GetUnitY(h)
local rect i = Rect(x-250, y-250, x+250, y+250)
IssuePointOrderByIdLoc( aihero, 851986, Location(GetRandomReal(GetRectMinX(i), GetRectMaxX(i)), GetRandomReal(GetRectMinY(i), GetRectMaxY(i))))
//命令移动到矩形区域内随机点
function attack takes nothing returns nothing
local unit target
loop
if (not buyitem and not useskills) and (not flee and not kabing) then
if GetEnemyBingInRangeCount(aihero,500)> 0 and GetAllyBingInRangeCount(aihero,500)<=0
call IssuePointOrder( aihero, "move", -2843.00, -3147.00 ) //命令英雄回家 ,-2843.00, -3147.00是地图中家的坐标
else
set target=GetWeakestUnit(aihero,500)//设置target是单位组内最弱的单位
if (target!=null) then
set attack_enemy=ture //设置正在攻击
call IssueTargetOrder(aihero,"attack",target)//命令英雄攻击target
call Sleep(1)
set attack_enemy=false//设置不在攻击了
set target=null
else
call moverandom //如果target不存在,就命令他移动到随机点
endif
endif
call Sleep(1)
endloop
endfunction
/j
终于完成了补刀线程,这是最简单的了.
6.会使用技能
有的技能电脑自己会使用,但那是魔兽本身设计的.如果有自己的技能,
我们可以判断情况,然后再用命令使英雄使用技能.真三AI.DOTA AI中
也是这样的!
为了防止英雄乱用技能,我们可以使用
j/
SetPlayerAbilityAvailable( ai_player, 'AHtc', false )//允许使用技能
SetPlayerAbilityAvailable( Player(0), 'AHtb', true )//禁止使用技能了
/j
这是一个让英雄不乱用技能的方法.就是禁用技能,以上函数是
禁止AI玩家使用风暴之锤(演示技能).优点是还可以保留CD.所以
我们还要判断技能是否在CD中再去使用.
以下是一种实现的方法,在main程序中加个函数用来记时间
j/
function main takes nothing returns nothing
local timer t==CreateTimer()
call TimerStart (t,1,ture,function count)
set t=null
endfunction
function count takes nothing returns nothing
set count=count+1
endfunction
/j
这样就可以计算脚本运行时间了,下面还要获得当前时间
j/
function Getcurrentime takes nothing returns integer
return count
endfunction
/j
有了以上的准备就可以开始做一个施放技能的函数了.
施放技能了一定不在逃跑,不卡兵等等,而且应该有英雄存在或者
魔法满了,免得浪费.那么可以在补刀时判断是否有英雄,再决定施放技能
英雄
这个是检测敌人英雄的函数,返回范围内的第一个英雄
j/
function GetEnemyHeroInRange takes takes unit Theunit,real Radius returns unit
local integer result=0
local unit u = null
local group g = CreateGroup()
call GroupEnumUnitsInRange(g,GetUnitX(Theunit),GetUnitY(Theunit),Radius,null)//选取范围内的单位进入单位组
loop
set u = FirstOfGroup(g)//设置u是单位组g内第一个单位
exitwhen u == null // 如果u为没有单位就退出循环
if((IsUnitEnemy(u,ai_player))and(IsUnitHero(u))and IsAlive(u))then//如果u是玩家的敌人,是英雄,且存活
return Theunit //返回单位
endif
call GroupRemoveUnit(g, u )//移除u出单位组
endloop
call DestroyGroup(g)
set g = null
return null
endfunction
/j
那么我们接下来加入补刀部分那里
j/
function attack takes nothing returns nothing
local unit target
loop
if (not buyitem and not useskills) and (not flee and not kabing) then
if GetEnemyBingInRangeCount(aihero,500)> 0 and GetAllyBingInRangeCount(aihero,500)<=0
call IssuePointOrder( GetTriggerUnit(), "move", -2843.00, -3147.00 ) //命令英雄回家 ,-2843.00, -3147.00是地图中家的坐标
else
set target=GetWeakestUnit(aihero,500)//设置target是单位组内最弱的单位
if (target!=null) then
set attack_enemy=ture //设置正在攻击
call IssueTargetOrder(aihero,"attack",target)//命令英雄攻击target
call Sleep(1)
set attack_enemy=false//设置不在攻击了
set target=null
else
call moverandom //如果target不存在,就命令他移动到随机点
endif
set target=GetWeakestUnit(aihero,500)//设置target为范围内的英雄
if GetEnemyHeroInRangeCount(aihero,500)!=0 then
SetPlayerAbilityAvailable( Player(0), 'AHtb', true )//允许使用技能
call IssueTargetOrderById(aihero, 852095, target )//命令使用技能风暴之锤
SetPlayerAbilityAvailable( Player(0), 'AHtb', true )//禁止使用技能了
set target=null
endif
endif
call Sleep(1)
endloop
endfunction
/j
以上添加后看起来很复杂,其实思路很清新,在补刀部分后面才判断英雄,当然也可以
放在其它地方,这是优先权的问题.
在英雄升级时,我们要允许技能,否则将学不到,那么在学习后就又禁止.可以在学习
技能部分添加.如:
j/
SetPlayerAbilityAvailable( Player(0), GetHandleInt("heroskills",s+"1"), true )//允许技能
call SelectHeroSkill(u,GetHandleInt("heroskills",s+"1"))//命令英雄学习技能
SetPlayerAbilityAvailable( Player(0), GetHandleInt("heroskills",s+"1"), false )//禁止技能
/j
7.卡兵
这里要运用到算法.算法我只是简单注释下.不求解了.学会用就OK了!
首先写两个函数
RangeToLoc到点的距离
RangeToUnit到单位的距离
j/
function RangeToLoc takes unit u,location Target returns real//到点的距离
local real X=GetLocationX(Target)-GetUnitX(u)
local real Y=GetLocationY(Target)-GetUnitY(u)
return(SquareRoot(X*X+Y*Y))
endfunction
function RangeToUnit takes unit u,unit Target returns real//到单位的距离
local real X=GetUnitX(Target)-GetUnitX(u)
local real Y=GetUnitY(Target)-GetUnitY(u)
return(SquareRoot(X*X+Y*Y))
endfunction
/j
|