|
用导弹模拟系统可以做出很多有趣的效果,诸如:任意时间反弹一个飞行中的导弹,或者随意改变飞行中导弹的伤害值,随意改变飞行中导弹的速度等等,最为重要的一点是,我们可以使用模拟使得导弹击中目标后触发我们想要的效果函数。先贴出VJ的导弹模拟系统代码:
[jass]library MissileSimulation
struct MissileData
unit caster
unit target
real damage
real speed
string func
boolean valid
location p
endstruct
globals
unit GetTriggerUnitEx
unit GetSpellTargetUnitEx
endglobals
private function Abs takes real i returns real
if i < 0 then
return 0 - i
endif
return i
endfunction
private function CacheValue takes nothing returns gamecache
if bj_lastCreatedGameCache == null then
call FlushGameCache( InitGameCache("ReturnBugSystem.w3v") )
set bj_lastCreatedGameCache = InitGameCache("ReturnBugSystem.w3v")
endif
return bj_lastCreatedGameCache
endfunction
private function ConvertUnit takes integer value returns unit
return value
return null
endfunction
private function H2I takes handle h returns integer
return h
return 0
endfunction
private function ConvertHandleInt takes handle valueHandle returns integer
return valueHandle
return 0
endfunction
private function ConvertHandle takes integer value returns handle
return value
return null
endfunction
private function I2H takes integer value returns handle
return value
return null
endfunction
private function H2S takes handle valueHandle returns string
return I2S( ConvertHandleInt(valueHandle) )
endfunction
private function SetHandle takes string s1,string s2,handle u returns nothing
call StoreInteger( CacheValue(), s1, s2, ConvertHandleInt(u) )
endfunction
private function GetUnit takes string s1,string s2 returns unit
return ConvertUnit( GetStoredInteger(CacheValue(), s1, s2))
endfunction
private function SetInteger takes string s1,string s2,integer i returns nothing
call StoreInteger( CacheValue(),s1,s2,i)
endfunction
private function GetInteger takes string s1,string s2 returns integer
return GetStoredInteger( CacheValue(),s1,s2)
endfunction
private function CleanCV takes string s returns nothing
call FlushStoredMission( CacheValue(), s )
endfunction
private function CDamage takes unit u1,unit u2,real DM returns nothing
call UnitDamageTarget( u1, u2, DM, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, WEAPON_TYPE_WHOKNOWS )
call CreateTextTagUnitBJ(I2S(R2I(DM)),u2,64,10,75,25,100,15)
call SetTextTagVelocityBJ( GetLastCreatedTextTag(), 100, 90 )
call SetTextTagPermanent( GetLastCreatedTextTag(), false )
call SetTextTagFadepoint( GetLastCreatedTextTag(), 1 )
call SetTextTagLifespan( GetLastCreatedTextTag(), 1.7 )
endfunction
private function Angle takes unit u,location p returns real
return bj_RADTODEG * Atan2(GetLocationY(p) - GetUnitY(u),GetLocationX(p) - GetUnitX(u))
endfunction
private function AngleBetweenUnits takes unit u1,unit u2 returns real
return bj_RADTODEG * Atan2(GetUnitY(u2) - GetUnitY(u1),GetUnitX(u2) - GetUnitX(u1))
endfunction
function MissileMove takes nothing returns nothing
local timer lt = GetExpiredTimer()
local unit mu = GetUnit(H2S(lt),"mu")
local MissileData md = MissileData(GetUnitUserData(mu))
local real x = GetUnitX(mu)
local real y = GetUnitY(mu)
local real angle = Angle(mu,md.p)
local real distance
local real highspeed
local real heightdistance = GetUnitFlyHeight(md.target) - GetUnitFlyHeight(mu) + 60
if md.valid == true then
set md.p = GetUnitLoc(md.target)
set distance = SquareRoot((x-GetLocationX(md.p))*(x-GetLocationX(md.p)) + (y-GetLocationY(md.p))*(y-GetLocationY(md.p)))
if Abs(heightdistance) >= 50 then
set highspeed = heightdistance/(distance / md.speed) * .03
call SetUnitFlyHeight( mu, GetUnitFlyHeight(mu) + highspeed, 0.00 )
endif
else
set distance = SquareRoot((x-GetLocationX(md.p))*(x-GetLocationX(md.p)) + (y-GetLocationY(md.p))*(y-GetLocationY(md.p)))
endif
if distance <= (md.speed * .03 / 2) then
call KillUnit(mu)
if md.valid == true then
call CDamage(md.caster,md.target,md.damage)
if md.func != null then
set GetTriggerUnitEx = md.caster
set GetSpellTargetUnitEx = md.target
call ExecuteFunc(md.func)
endif
endif
call CleanCV(H2S(lt))
call CleanCV(H2S(mu))
call DestroyTimer(lt)
call MissileData.destroy(md)
else
call SetUnitX(mu,Cos(angle*bj_DEGTORAD)*md.speed * .03 + x)
call SetUnitY(mu,Sin(angle*bj_DEGTORAD)*md.speed * .03 + y)
call SetUnitFacing(mu,angle)
endif
set lt = null
set mu = null
endfunction
function MissileStart takes unit caster,unit target,real damage,real speed,string func,integer modleunitid returns nothing
local timer lt = CreateTimer()
local MissileData md = MissileData.create()
local unit mu
set md.caster = caster
set md.target = target
set md.damage = damage
set md.speed = speed
set md.func = func
set md.p = GetUnitLoc(target)
set md.valid = true
set mu = CreateUnit(GetOwningPlayer(caster),modleunitid,GetUnitX(caster),GetUnitY(caster),AngleBetweenUnits(caster,target))
call UnitAddAbility(mu,'Aloc')
call UnitAddAbility(mu,'Avul')
call UnitAddAbility(mu,'Arav')
call UnitRemoveAbility(mu,'Arav')
call SetUnitFlyHeight(mu,60.,0)
call SetUnitUserData(mu,md)
call SetHandle(H2S(lt),"mu",mu)
call TimerStart(lt,.03,true,function MissileMove)
set mu = null
set lt = null
endfunction
endlibrary[/jass]
使用规则call MissileStart(施法者,目标,伤害值,导弹速度,效果函数,模型单位id)。
你的效果函数可以不写在library MissileSimulation里面,在效果函数的顶端,你应该先把GetTriggerUnitEx和GetSpellTargetUnitEx传递给局部函数,如:[jass]
function Effect takes nothing returns nothing
local unit triggerUnit = GetTriggerUnitEx
local unit spelltargetunit = GetSpellTargetUnitEx
……[/jass]
这里的技能施放目标和施放技能的单位都是用全局变量传递的,如果你的效果函数里有诸如等待的语句,那么那个时候这两个全局变量的值可能已经被其他导弹的值覆盖掉了。
下面是效果的一些演示代码:
注意:3包括3以前的演示代码是需要注释掉call UnitAddAbility(mu,'Aloc')这条语句的,因为处于蝗虫状态的单位无法被枚举。删除这个技能依然无法被枚举,直到这个单位死亡为止。
具体的解决方法参看第四点。
1.blink技能施放后导弹丢失目标。[jass]
function blink_filter takes nothing returns nothing
local unit u = GetFilterUnit()
if GetUnitAbilityLevel(u,'导弹标识技能') > 0 then
set s__MissileData_valid[GetUnitUserData(u)] = false
endif
set u = null
endfunction
function blink takes nothing returns nothing
local group g = CreateGroup()
local unit u = GetTriggerUnit()
call GroupEnumUnitsInRange(g,GetUnitX(u),GetUnitY(u),1000.,Condition(function blink_filter))
call DestroyGroup(g)
set g = null
set u = null
endfunction[/jass]
2.反弹全部靠近施法者1000范围内的所有导弹。[jass]
function blink_filter takes nothing returns nothing
local unit u = GetFilterUnit()
local unit temp
if GetUnitAbilityLevel(u,'导弹标识技能') > 0 then
set temp = s__MissileData_target[GetUnitUserData(u)] = false
set s__MissileData_target[GetUnitUserData(u)] = s__MissileData_caster[GetUnitUserData(u)]
set s__MissileData_caster[GetUnitUserData(u)] = temp
set temp = null
endif
set u = null
endfunction
function blink takes nothing returns nothing
local group g = CreateGroup()
local unit u = GetTriggerUnit()
call GroupEnumUnitsInRange(g,GetUnitX(u),GetUnitY(u),1000.,Condition(function blink_filter))
call DestroyGroup(g)
set g = null
set u = null
endfunction[/jass]
使用一个技能创建一个结界,进入结界内的导弹速度将降为N的做法也大同小异,这里就不给出代码了,需要的可以自己做做看。
3.linken失效
[jass]function linken_filter takes nothing returns boolean
local unit u = GetFilterUnit()
if GetUnitAbilityLevel(u,'导弹标识技能') > 0 then
set s__MissileData_valid[GetUnitUserData(u)] = false
endif
set u = null
return false
endfunction
function linken_Conditions takes nothing returns boolean
local group g
local unit u = GetTriggerUnit()
if GetSpellAbilityId() == 'ANss' then
set g = CreateGroup()
call GroupEnumUnitsInRange(g,GetUnitX(u),GetUnitY(u),1000.,Condition(function linken_filter))
call DestroyGroup(g)
set g = null
endif
set u = null
return false
endfunction[/jass]
4.解决蝗虫单位无法被枚举
因为本人能力有限,这里提供3种解决的思路。如果大家有其他的思路,欢迎提供。
⑴建立一个单位数组,创建一个导弹单位就记录在单位数组里面,死亡的时候从数组种移除,并把数组指针拨回这个单位的数组位置。当施放以上技能的时候,用loop判断单位的s__MissileData_target[GetUnitUserData(该单位)] 是否等于施放上述技能的单位,如果等于就更改有效值为false。因为你不可能在同一时间有成百上千个导弹单位,所以这样的耗时并不是很大。
⑵选中单位如果有'导弹标识技能'就将该单位的选择移除。当然这样的做法玩家会发现还是可以选择导弹单位的。
⑶使用动态注册,在模拟导弹函数当中,动态注册触发器事件,把导弹单位绑定在触发器上。当目标单位施放以上技能(为了简化你可以建立线性表)的时候,就把导弹单位的有效值设置为false。 |
评分
-
查看全部评分
|