|
发表于 2008-1-7 15:54:42
|
显示全部楼层
五、坐标函数
现在有了我们timer,再做以前那些卡机技能,比如“跳砍”,每0.01秒移动次单位,系统运行效率可以提高不少呢!那么我再把timer的好朋友——坐标函数介绍给你,它们搭档能进一步提高效率。由于坐标方面的内容比较少,因此我直接放到timer这章一并讲解。
假如,我们要将一个单位移动到(100,200)这个点,传统做法是
[codes=jass]
local location point = Location(100,200)
call SetUnitPositionLoc( 龙套演员, point )[/codes]
或者,你直接这样写
[codes=jass]call SetUnitPosition(龙套演员,100,200)[/codes]
但上面的写法都不太好,最高效的代码应该这样写
[codes=jass]call SetUnitX(龙套演员,100)
call SetUnitY(龙套演员,200)[/codes]
使用SetUnitPositionLoc非常麻烦,这里就不多说了;现在着重比较下SetUnitX跟SetUnitPositionLoc;老狼做过测试,SetUnitX效率比SetUnitPosition高20倍;按小强的说法,SetUnitPosition要到内存里面搜索实际位置。关于原理,我们没必要去探询;我们只需要知道,使用SetUnitX效率最高,便足够了。
SetUnitX比起SetUnitPosition除了高效,还有很大的优点——不会打断单位当前order。在使用SetUnitPosition时,我们经常看到单位在抽搐——当山丘哥哥举起“加爵牌”锤子正要敲一个憎恶,突然被SetUnitPosition移动到别的位置,于是举起的手又放了下来;随即它又举起锤子,准备教训下身边的猥琐男,结果又被SetUnitPosition……于是只见山丘不停地把手举起又放下,跟跳健康操似的。而使用SetUnitX,这样说吧,你可以让老虎MM一边围着你旋转一边放流星雨,也可以让巫妖一边凋零别人基地一边后退。
不过,SetUnitX有个最大的缺陷,那便是,当坐标超出了地图边界,地图会立刻崩溃(试想下,你把单位移动到地图之外,系统能不郁闷到咬舌自尽吗)。因此,使用SetUnitX时必须先判断下坐标是否在超越了地图边界;除此之外,SetUnitX几乎没有其他缺点。
六、实例
演示永远是最好的教程。
还记得JASS培训班第一期考试题吗,最后一道,是要求做个冲锋函数。那么,我们一起来做个单位移动函数吧!
我们知道 路程S=速度V x 时间T,而在这移动函数里,速度V(也就是每秒单位移动的距离)=每次移动位移R x (1/移动时间间隔Timeout);比如,每隔0.02秒移动次单位,每次移动距离为10,那么单位的移动速度V=10 x (1/0.02)=10x50=500,移动10秒,移动距离s=500x10=5000,就这么简单。
由于那道考试题目中的函数是
[codes=jass]function HeroMoveTimeout takes unit hero,location point,real timeout returns nothing[/codes]
(在确定目的地point后,可以根据单位目前位置,获得距离S;而自定义每次移动位移,根据输入的时间间隔,可以得到速度V;最后我们可根据S=V x T的关系求得时间T,然后用T除以时间间隔timeout获得移动次数。)
因此,为了避免重复(毕竟那是考试题,留给学员做的,所以就不以这个函数为例子),我们换个思路来写移动函数,如
[codes=jass]function UnitMove takes unit orderUnit,real lasttime,real interval,real dis,real angle returns nothing[/codes]
(持续时lasttime便是时间T,angle是移动方向;用移动时间间隔interval和每次移动的距离dis可以求出移动速度V;根据S=V x T求出最终移动距离。)
函数如下
[codes=jass]
function H2I takes handle h returns integer
return h
return 0
endfunction
function I2U takes integer i returns unit
return i
return null
endfunction
function Move_LOOP takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer i = 0
local unit orderUnit=I2U(GetStoredInteger(udg_GC,I2S(H2I(t)),"orderUnit"))
local real UnitLocX = GetStoredReal(udg_GC,I2S(H2I(t)),"X")
local real UnitLocY = GetStoredReal(udg_GC,I2S(H2I(t)),"Y")
local real tempLocX
local real tempLocY
local real angle = GetStoredReal(udg_GC,I2S(H2I(t)),"angle")
local real dis = GetStoredReal(udg_GC,I2S(H2I(t)),"distance")
local integer steps= GetStoredInteger(udg_GC,I2S(H2I(t)),"steps")
local integer Max= GetStoredInteger(udg_GC,I2S(H2I(t)),"Max")
if steps>0 then
set steps=steps-1
call StoreInteger(udg_GC,I2S(H2I(t)),"steps",steps)
set tempLocX = UnitLocX + dis*Cos(angle*bj_DEGTORAD)*(Max-steps)
set tempLocY = UnitLocY + dis*Sin(angle*bj_DEGTORAD)*(Max-steps)
if tempLocX > udg_Map_X_Max then
set tempLocX = udg_Map_X_Max
endif
if tempLocX < udg_Map_X_Min then
set tempLocX = udg_Map_X_Min
endif
if tempLocY > udg_Map_Y_Max then
set tempLocY = udg_Map_Y_Max
endif
if tempLocY < udg_Map_Y_Min then
set tempLocY = udg_Map_Y_Min
endif
call SetUnitX(orderUnit,tempLocX)
call SetUnitY(orderUnit,tempLocY)
else
set i=0
call FlushStoredMission(udg_GC,I2S(H2I(t)))
call DestroyTimer(t)
endif
set orderUnit=null
endfunction
function UnitMove takes unit orderUnit,real lasttime,real interval,real dis,real angle returns nothing
local real UnitLocX = GetUnitX(orderUnit)
local real UnitLocY = GetUnitY(orderUnit)
local timer t=CreateTimer()
local integer steps=R2I(lasttime/interval)
call StoreReal(udg_GC,I2S(H2I(t)),"X",UnitLocX)
call StoreReal(udg_GC,I2S(H2I(t)),"Y",UnitLocY)
call StoreInteger(udg_GC,I2S(H2I(t)),"steps",steps)
call StoreInteger(udg_GC,I2S(H2I(t)),"Max",steps)
call StoreReal(udg_GC,I2S(H2I(t)),"angle",angle)
call StoreReal(udg_GC,I2S(H2I(t)),"distance",dis)
call StoreInteger(udg_GC,I2S(H2I(t)),"orderUnit",H2I(orderUnit))
call TimerStart(t,interval,true,function Move_LOOP)
set t=null
endfunction[/codes]
首先,利用持续时间lasttime和移动时间间隔interval求出移动次数steps,比如持续10秒,每0.02秒移动次单位,那么这个单位将移动500次,即移动函数被执行500次。
其次,把所有参数储存到缓存中,用TimerStart循环执行函数Move_LOOP。
最后,在Move_LOOP中,从缓存中读出数据;函数每被执行依次,就让steps减1,直到为0;特别一提的是,必须让单位的坐标tempLocX和tempLocY跟地图边界比较,边界值由全局变量Map_X_Min、Map_X_Max、Map_Y_Min和Map_Y_Max保存。
上面函数看起来代码冗长,其实内容很简单,只不断从缓存中读取和写入数据以致繁琐。
现在我们再看一个旋转函数。其实很简单,把上面的代码稍微改下就是了。
[codes=jass]function H2I takes handle h returns integer
return h
return 0
endfunction
function I2U takes integer i returns unit
return i
return null
endfunction
function Circle_LOOP takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer i = 0
local unit OrderUnit=I2U(GetStoredInteger(udg_GC,I2S(H2I(t)),"OrderUnit"))
local unit CircleUnit=I2U(GetStoredInteger(udg_GC,I2S(H2I(t)),"CircleUnit"))
local real UnitLocX = GetUnitX(OrderUnit)
local real UnitLocY = GetUnitY(OrderUnit)
local real tempLocX
local real tempLocY
local real AngleSpeed = GetStoredReal(udg_GC,I2S(H2I(t)),"AngleSpeed")
local real radius = GetStoredReal(udg_GC,I2S(H2I(t)),"radius")
local real AngleSpeed = GetStoredReal(udg_GC,I2S(H2I(t)),"AngleSpeed")
local real degrees = GetStoredReal(udg_GC,I2S(H2I(t)),"degrees")
local integer steps= GetStoredInteger(udg_GC,I2S(H2I(t)),"steps")
if steps>0 then
set steps=steps-1
call StoreInteger(udg_GC,I2S(H2I(t)),"steps",steps)
set degrees=degrees+AngleSpeed
set tempLocX = UnitLocX + radius*Cos(degrees*3.14159/180.0)
set tempLocY = UnitLocY + radius*Sin(degrees*3.14159/180.0)
if tempLocX > udg_Map_X_Max then
set tempLocX = udg_Map_X_Max
endif
if tempLocX < udg_Map_X_Min then
set tempLocX = udg_Map_X_Min
endif
if tempLocY > udg_Map_Y_Max then
set tempLocY = udg_Map_Y_Max
endif
if tempLocY < udg_Map_Y_Min then
set tempLocY = udg_Map_Y_Min
endif
call SetUnitX(CircleUnit,tempLocX)
call SetUnitY(CircleUnit,tempLocY)
else
set i=0
call FlushStoredMission(udg_GC,I2S(H2I(t)))
call DestroyTimer(t)
endif
set orderUnit=null
set CircleUnit=null
endfunction
function UnitCircle takes unit OrderUnit,unit CircleUnit,real lasttime,real interval,real radius,real AngleSpeed returns nothing
local timer t=CreateTimer()
local integer steps=R2I(lasttime/interval)
call StoreInteger(udg_GC,I2S(H2I(t)),"steps",steps)
call StoreReal(udg_GC,I2S(H2I(t)),"radius",radius)
call StoreReal(udg_GC,I2S(H2I(t)),"AngleSpeed",AngleSpeed)
call StoreInteger(udg_GC,I2S(H2I(t)),"OrderUnit",H2I(OrderUnit))
call StoreInteger(udg_GC,I2S(H2I(t)),"CircleUnit",H2I(CircleUnit))
call TimerStart(t,interval,true,function Circle_LOOP)
set t=null
endfunction[/codes]
该函数的作用是让一个单位绕另一个单位旋转,可以设置旋转持续时间lasttime,旋转角速度AngleSpeed等;我们只是修改了前个函数中计算坐标的部分代码,其余部分都大同小异。篇幅所限,我就只介绍这两个函数函数,学员可找更多跟timer有关的演示来学习。
好了,老规矩,放上演示供大家参考。
最后罗嗦两句,希望这个JASS培训班能越来越火,希望JASS高手能抽时间指点下新人,希望新人能多提问积极地学习。末了,祝大家新年快乐! |
|