疯人¢衰人 发表于 2009-9-6 08:06:34

模拟投射物轨迹——函数粗略版

模拟投射物轨迹——函数粗略版
引用 下定决心减少来GA的时间了……而且是大量的减少……恩……其实很早就有这样的打算了……不过我这人一向是重视承诺的……至少自己该做的……绝对会做完……好吧……
这个函数本来时被小血逼着为位面消隐做的东西……
因为自己不会VJ,所以只是写了个简单的函数,用于测试高度公式以及效果,连排泄都没有做……
而且我也根本没有想将其发上来,至少在开始写这个帖子之前没有……
算了,还是不多说了……

演示下载:http://bbs.islga.org/images/wind/file/zip.gif aim.w3x (22 K) 下载次数:2
复制代码 jass
function Getb takes real H0,real H1,real L,real K returns real
//b
return 2*((K*L-H0)+SquareRoot((K*L-H0)*(K*L-H1)))*10000/L
endfunction
function Geta takes real H0,real H1,real L,real K returns real
//a
local real b = Getb(H0,H1,L,K)
return b*b/40000/(H0-K*L)
endfunction
function MoveProjectileB takes nothing returns nothing
local timer udg_t = null
local unit udg_u = null
local integer udg_i = 0
local integer temp = 0
local real VX = 0
local real H1 = 0
local real H2 = 0
local real dis = 0
local real angle = 0
local unit Aim = null
local unit Projectile = null
local location Aimloc = null
local location Proloc = null
set udg_t = GetExpiredTimer()
set temp = udg_i
set VX = GetStoredReal(udg_W3V,I2S(temp),"VX")
set udg_i = GetStoredInteger(udg_W3V, I2S(temp), "AimUnitHandle")
set Aim = udg_u
set Aimloc = GetUnitLoc(Aim)
set udg_i = GetStoredInteger(udg_W3V, I2S(temp), "Projectile")
set Projectile = udg_u
set Proloc = GetUnitLoc(Projectile)
set dis = DistanceBetweenPoints(Proloc, Aimloc)
set angle = AngleBetweenPoints(Proloc, Aimloc)
if dis < VX then
call RemoveUnit(Projectile)
call PauseTimer(GetExpiredTimer())
//命中目标
//省略诸多排泄
endif
set H2 = GetUnitFlyHeight(Projectile)
set H1 = GetUnitFlyHeight(Aim)
call SetUnitFlyHeight(Projectile, H2-(H2-H1)*VX/dis, 0 )
set Proloc = PolarProjectionBJ(Proloc,VX, angle)
call SetUnitX(Projectile,GetLocationX(Proloc))
call SetUnitY(Projectile,GetLocationY(Proloc))
call SetUnitFacing( Projectile,angle)
endfunction
function MoveProjectileA takes nothing returns nothing
local timer udg_t = null
local unit udg_u = null
local integer udg_i = 0
local integer temp = 0
local real VX = 0
local real X = 0
local real Y = 0
local real H0 = 0
local real T = 0
local real a = 0
local real b = 0
local unit Aim = null
local unit Projectile = null
local location Aimloc = null
local location Proloc = null
local timer time
set udg_t = GetExpiredTimer()
set temp = udg_i
set udg_i = GetStoredInteger(udg_W3V, I2S(temp), "AimUnitHandle")
set Aim = udg_u
set Aimloc = GetUnitLoc(Aim)
set X = GetStoredReal(udg_W3V,I2S(temp),"X")
set Y = GetStoredReal(udg_W3V,I2S(temp),"Y")
set VX = GetStoredReal(udg_W3V,I2S(temp),"VX")
set H0 = GetStoredReal(udg_W3V,I2S(temp),"H0")
set udg_i = GetStoredInteger(udg_W3V, I2S(temp), "Projectile")
set Projectile = udg_u
if (GetLocationX(Aimloc) != X) or (GetLocationY(Aimloc) != Y) then
set udg_t = CreateTimer()
set temp = udg_i
set time =udg_t
call StoreReal(udg_W3V,I2S(temp),"VX",VX)
set udg_u = Aim
call StoreInteger(udg_W3V,I2S(temp),"AimUnitHandle",udg_i)
set udg_u = Projectile
call StoreInteger(udg_W3V,I2S(temp),"Projectile",udg_i)
call TimerStart(time,udg_interval,true,function MoveProjectileB)
call PauseTimer(GetExpiredTimer())
call DestroyTimer(GetExpiredTimer())
return
//进入第二种移动方式
//省略诸多排泄
endif
set a = GetStoredReal(udg_W3V,I2S(temp),"a")
set b = GetStoredReal(udg_W3V,I2S(temp),"b")
set Proloc = GetUnitLoc(Projectile)
if DistanceBetweenPoints(Proloc, Aimloc) < VX then
call RemoveUnit(Projectile)
call PauseTimer(GetExpiredTimer())
//命中目标
//省略诸多排泄
endif
set T = GetStoredReal(udg_W3V,I2S(temp),"T")
call SetUnitFlyHeight(Projectile,a*T*T/10000*VX*VX+b*T*VX/10000+H0, 0 )
set Proloc = PolarProjectionBJ(Proloc,VX, AngleBetweenPoints(Proloc, Aimloc))
call SetUnitX(Projectile,GetLocationX(Proloc))
call SetUnitY(Projectile,GetLocationY(Proloc))
call StoreReal(udg_W3V,I2S(temp),"T",T+1)
endfunction
function GetAim takes unit aim,location loc,integer ut,player p,real k,integer v,real h0 returns nothing//参数依次是 目标单位aim, 发动攻击单位位置loc, 投射物马甲的单位类型ut ,攻击单位的所有者(所有玩家)p, 射弹弧度k ,射弹速率v ,射弹初始高度h0
local timer udg_t = null
local unit udg_u = null
local integer udg_i = 0
local integer temp = 0
local location l = null
local timer temptimer
set udg_t = CreateTimer()
set temptimer = udg_t
set temp = udg_i
set udg_u = aim
call StoreInteger(udg_W3V,I2S(temp),"AimUnitHandle",udg_i)
call StoreReal(udg_W3V,I2S(temp),"VX",R2I(I2R(v) * udg_interval))
set l = GetUnitLoc(aim)
call CreateNUnitsAtLoc( 1, ut, p, loc, AngleBetweenPoints(loc,l) )
set udg_u = GetLastCreatedUnit()
call SetUnitFlyHeight( udg_u, h0, 0 )
call StoreInteger(udg_W3V,I2S(temp),"Projectile",udg_i)
call StoreReal(udg_W3V,I2S(temp),"b",Getb(h0,GetUnitFlyHeight(aim),DistanceBetweenPoints(l, loc),k))
call StoreReal(udg_W3V,I2S(temp),"a",Geta(h0,GetUnitFlyHeight(aim),DistanceBetweenPoints(l, loc),k))
call StoreReal(udg_W3V,I2S(temp),"X",GetLocationX(l))
call StoreReal(udg_W3V,I2S(temp),"Y",GetLocationY(l))
call StoreReal(udg_W3V,I2S(temp),"T",0)
call StoreReal(udg_W3V,I2S(temp),"H0",h0)
call TimerStart(temptimer,udg_interval,true,function MoveProjectileA)
endfunction


以上是最简单的代码,GC版,无排泄,无变量声明(声明看最后的演示吧)。反正诸位也许会用的GAer大约也能自己改成完好的。
其中:
复制代码 jass
function Getb takes real H0,real H1,real L,real K returns real
//b
return 2*((K*L-H0)+SquareRoot((K*L-H0)*(K*L-H1)))*10000/L
endfunction
function Geta takes real H0,real H1,real L,real K returns real
//a
local real b = Getb(H0,H1,L,K)
return b*b/40000/(H0-K*L)
endfunction
这两个函数的返回值是投射物曲线的抛物线方程Y=aX2+bX+c中的a、b参数,而参数c是H0,也就是投射物的初始高度。

之后的三个函数是具体模拟投射物效果的函数:
GetAim是记录各种参数,然后开始曲线方案1的计时器。具体需要绑定的参数有:
Aim,(目标,函数中保存的是Handle),
Projectile,(投射物单位,在函数里创建的,类型通过 GetAim 函数的参数获得,演示里也是用Handle值传递的)
VX,(水平方向的速度,就是每间隔时间内投射物的移动距离,其值是投射速率这个系数乘以移动间隔时间)
b,(Getb获得的,b=2*[(K*L-H0)+√((H0-K*L)*(H1-K*L)) ] 其中√代表平方根)
√a,(Geta获得的,a=b2/4/(H0-K*L),b用Getb获得)
X,(目标X轴坐标,用于判断目标是否移动)
Y,(同X,不过是Y轴的)
H0,(投射物的初始高度)
T,(执行次数,用于计算的,每次循环要+1)

因为不是成品,所以还是仔细说明下。
特别要提到的是
我并没有让投射物创建在攻击单位头上,而是向着目标移动一个移动间隔(VX),这是因为感觉这样效果真实。
MoveProjectileA,MoveProjectileB是两个投射物运行方式A是目标不移动的轨迹,B是移动后的,具体请自己看真实投射物曲线吧(下载http://bbs.islga.org/images/wind/file/zip.gif 投射物.w3x (18 K) 下载次数:1 )。 调用MoveProjectileB时,你只要将VX,Aim和Projectile传递过去即可。

MoveProjectileB的调用在MoveProjectileA中(函数上面有注释),无论哪种方式,当命中目标(判断目标和投射物之间的距离小于VX)后,需要运行其他函数,请插入函数中相关注释的部分 。
演示采用的方法是不考虑地面的,也就是未曾考虑地面不平的问题。,如果诸位需要考虑,可以将H0和H1(目标高度)都加上对应点的GetLocationZ。设置投射物高度时要减去 GetLocationZ。另外还有判断计算出来的高度是否高于地面,如果高于地面,请将投射物隐藏或替换,取消投射物模型,这样更真实些。(正常地图不必考虑这些)

复制代码 jass
if DistanceBetweenPoints(Proloc, Aimloc) < VX then
call RemoveUnit(Projectile)
call PauseTimer(GetExpiredTimer())
//命中目标
//省略诸多排泄
endif

中调用即可。

关于目标不移动时投射物的曲线的方程,
还有个计算用的解释图:

http://bbs.islga.org/p_w_upload/Mon_0909/12_4487_7030699f60e4472.jpg



如果有谁要完整能用的函数……
找小血要吧……
嘿嘿……
引用
函数是未完整的……
感觉还是很对不起大家……
恩恩……
于是躲起来……
也许会偶尔上来看看的……
页: [1]
查看完整版本: 模拟投射物轨迹——函数粗略版