疯人¢衰人 发表于 2009-9-1 22:20:15

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

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

演示下载:

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大约也能自己改成完好的。
其中:

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是移动后的,具体请自己看真实投射物曲线吧(下载)。 调用MoveProjectileB时,你只要将VX,Aim和Projectile传递过去即可。

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


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


中调用即可。

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




如果有谁要完整能用的函数……
找小血要吧……
嘿嘿……

函数是未完整的……
感觉还是很对不起大家……
恩恩……
于是躲起来……
也许会偶尔上来看看的……

alexries 发表于 2009-9-1 22:25:29

怎么可能……
阿。还是多回来罢。
还有那啥。投射的角度呢。

疯人¢衰人 发表于 2009-9-1 22:33:17

忘记了……
投射角度相关的数据室K
为单位的射弹弧度这项数值
实际上就是最高点高度与攻击单位到目标之间距离的比值

alexries 发表于 2009-9-1 22:35:10

你竟然对你的帖子用了强效置顶无视器……

疯人¢衰人 发表于 2009-9-1 22:35:46

好吧……
用错道具结果置顶了……

alexries 发表于 2009-9-1 22:41:57

苦命呢……宝贵的置顶器……
好久没和你水了

疯人¢衰人 发表于 2009-9-1 23:09:23

……
还有很多……
19+
你不知道
我醒目灯也用了3个……

alexries 发表于 2009-9-1 23:21:42

为啥用这末多呢~不是一次可以选中包括粗斜亮加上一个颜色的嘛

疯人¢衰人 发表于 2009-9-1 23:26:13

改了两回都感觉不好

alexries 发表于 2009-9-1 23:30:27

终于还是决定用你最喜欢的黄~色~了末~

alexries 发表于 2009-9-2 07:33:42

为什么这个帖子没有投影仪的标记呢?
猜想是用了置顶之后再用了其他道具,把置顶的标记覆盖了,然后置顶结束会消除标记,结果就把其他的标记取消了。

louter 发表于 2009-9-2 22:25:59

魔兽的投射物是如此判定的:arc若不为0时,投射物会无视目标单位是否移动强制性飞向发射时所记录的目标的x,y,z,如果到达时没有击中(只判断x,y),则以arc为0的轨迹移动,高度会重新判断,但貌似不会对过快的变化做出反应。
疯人的函数是怎么写的?手机实在是看得太难受。
话说当初我就是因为那个口胡的SetUnitLookAt无效所以就放弃这系统了……

疯人¢衰人 发表于 2009-9-3 09:04:25

引用第11楼louter于2009-09-02 22:25发表的 :
魔兽的投射物是如此判定的:arc若不为0时,投射物会无视目标单位是否移动强制性飞向发射时所记录的目标的x,y,z,如果到达时没有击中(只判断x,y),则以arc为0的轨迹移动,高度会重新判断,但貌似不会对过快的变化做出反应。
疯人的函数是怎么写的?手机实在是看得太难受。
话说当初我就是因为那个口胡的SetUnitLookAt无效所以就放弃这系统了…… http://bbs.islga.org/images/back.gif

我做过测试……
但是并非按阁下所说的轨迹呢……
实际上如果arc为0
那么无论目标是否移动,都是在三维坐标中从投射物到目标的直线……(这个没测试,猜的)
如果arc不为0
那么投射物会如你所说:飞向发射时所记录的目标的x,y,z
然而一旦目标移动,投射物会直线追踪目标……
我这帖子里有演示的

eff 发表于 2009-9-3 12:45:06

用gc者死

『四裤全输』 发表于 2009-9-3 13:17:54

又学会了一招。

血戮魔动冰 发表于 2009-9-3 13:18:44

…………………………………………………………!!
传说中的……吐槽?

louter 发表于 2009-9-3 15:20:58

因为是很早以前写的,所以测试的结果什么的记得就不是很清楚了,外加现在没电脑。

如果没错的话应该所有的投射物在z轴上都是一个方向……

疯人¢衰人 发表于 2009-9-3 17:13:13

引用第16楼louter于2009-09-03 15:20发表的:
因为是很早以前写的,所以测试的结果什么的记得就不是很清楚了,外加现在没电脑。

如果没错的话应该所有的投射物在z轴上都是一个方向…… http://bbs.islga.org/images/back.gif

一个方向?
这个理解不能……
总之是轨迹是个抛物线吧……
其实这个帖子的重要意义在于计算抛物线轨迹的公式……
很多比较小的GAER没学过抛物线
所以没法做
用公式就可以了……
其他内容诸位无视吧……

infi 发表于 2009-9-3 17:33:57

不懂JASS的路过iu·············

alexries 发表于 2009-9-5 16:44:10

呀……突然发现这个在教学区有投影,呜。
竟然把水带进来了
页: [1] 2
查看完整版本: 模拟投射物轨迹——函数粗略版