找回密码
 点一下
查看: 3469|回复: 15

系统函数 - 创建任意动态圆形及扩展圆形特效

[复制链接]
发表于 2009-2-28 15:42:31 | 显示全部楼层 |阅读模式
前一阵子做了个创建任意圆形曲线的函数,但是只能创建静态特效,也无法在触发器中设置特效单位的属性(比如定时生命),现在进行了一下改进。顺便传上几个应用举例,大致上可以把它作为一个系统函数来使用了。以后我还会不定期上传新的实例,让大家能尽量减少浪费在特效设置上的时间。当然,在没有影响使用的前提下,函数本身可能存在这样那样的不足,希望发现这些不足的朋友能不吝赐教,帮忙指出来。
在此,特别感谢水水,橙子,埃里克斯,知秋,〓GOT)YB〓及其他所有在我学习Jass过程中提供过无私帮助的朋友们。
这个是演示地图: 函数演示-创建任意圆形及变异圆形.w3x (21 KB, 下载次数: 75)


看下几个实例的截图,可以看出,只要改变几个参数,就能获得截然不同的特效。考虑到页面打开速度,我截取了静态图,但基本上能想象出动态效果来。当然,最真实的效果是要在游戏中看的。

注意:测试不同演示的时候,请吧其他演示的触发器禁用或者设置初始关闭,因为他们调用相同的圆心点,也使用相同的缓存类型。


第一个是离心曲线,就好比转动一把伞,伞上的水珠被甩出去的路径。许多人认为是像炸开那样中心开花,实际是这样的哦。这个使用了24个特效单位(每条线都是两个单位的重叠,看起来特效会比较亮)
1.JPG (49.88 KB)
2009-2-8 15:36



第二个是动态球体,使用了20个特效单位
2-2.JPG (29.25 KB)
2009-2-8 15:36

更换了一个模型
2.JPG (34.14 KB)
2009-2-8 15:36

第三个是平面炸开,使用了100个特效单位
4.JPG (15.97 KB)
2009-2-8 15:36

第四个是上升的螺旋曲线,就是12股的弹簧,使用了12个特效单位
3.JPG (37.42 KB)
2009-2-8 15:36

因为本函数使用的参数比较多,所以在这里做一下解释。
我们就以最后这个螺旋曲线为例,说明函数的用法。
1.GIF (3.54 KB)
2009-2-8 15:36

这个是创建特效单位的触发器动作,它的事件是游戏开始后1秒。
不需要其他设置(当然某些曲线可能要做额外的计算,会多几条语句),直接调用创建特效的函数HuaYuan()。最后一句是开启动态特效的触发器,暂时先无视它。
第一个参数:圆心投影点。数据类型:点。因为圆心可能有高度,所以我称它为投影点。这里我用了区域B的中心点;
第二个参数:圆心高度。数据类型:实数。这个很容易理解,它直接关系到圆的整体高度。如果指定高度为-1,将不会重新设置特效单位的飞行高度,这样创建出来的特效必然是水平圆
第三个参数:圆半径。数据类型:实数。指的是形成特效后,特效单位到圆心的距离(注意不是地面投影距离,因为投影通常是以椭圆,半径不是恒定值),它影响到圆的大小。如果要做扩散或缩紧的特效,就要动态改变这个值。
第四个参数:圆面倾角。数据类型:实数。就是圆面与地面的夹角,0度、180度为水平圆,90度、270度为立圆。
看下图,第一个倾角是0度,第二个是45度,第三个是335度。
3.GIF (28.53 KB)
2009-2-8 15:36


第五个参数:Z轴预旋角。数据类型:实数。它相当于指定开始创建特效单位的角度,如果去掉它的影响,总是从0度开始的。看下边的图。
2.GIF (2.08 KB)
2009-2-8 15:36
如果我们要创建3个特效单位组成的圆,在没有预旋角影响的情况下,必然是左边图里表示的形态。假如我们要做像右边图里表示的那样的特效,就要指定一个角度β,这个就是预旋角。如果动态改变这个值,会导致特效单位在圆周上移动。
第六个参数:Z轴后旋角。数据类型:实数。如果我们认为默认的水平圆是面向上,背向下的话,那么后旋角就指的是在圆面倾斜的情况下,圆面朝向的方向。如果取消它的影响,设置圆面倾斜角,会导致圆面离屏幕远端的地方翘起,近端下降,增大这个值就增加翘起程度,直到立起来,然后会倒向屏幕,最后趴下,也就是说,不是面向屏幕,就是背向屏幕。如果我们要改变圆面朝向,比如要它侧身向屏幕,就要指定后旋角。需要注意的是,如果圆面倾斜角是0度的话,它与预旋角造成的效果是相同的。
看下图,3个圆,倾角都是90度,也就是立圆,第一个圆后旋角为0,第二个是45度,第三个是90度。看影子的话效果更好。
4.GIF (21.84 KB)
2009-2-8 15:36


第七个参数:特效单位类型。数据类型:整数。就是指定要用哪个类型的单位去拼凑,它本身是整数型,使用单位类型的ID,在单位编辑器中按Ctrl+D可以显示单位类型的ID。
第八个参数:特效单位数量。数据类型:整数。对于指定不同的数量,函数在创建过程中会自动把他们均匀的分配到圆周上,并且每个单位都是面背向圆心的。
第九个参数:缓存类别。数据类型:字符串。因为调用一次函数可能要创建许多单位,这样就不能在调用函数后使用 最后创建的单位 来捕获特效单位,所以要在创建过程中使用缓存来记录它们,函数默认会调用一个叫cchHuaYuan的全局变量。这个参数指定缓存类别,第一个创建的单位缓存名字为“1”,第二个为“2”,依次类推。如果指定一个空字符串,表示不对特效单位进行记录,适用于创建某些永久的静态特效,比如地上的标志。或者单位本身是负生命恢复速度的,如果创建静态特效,可以不记录它们。需要注意的是:如果某个缓存类型正在使用中,再次指定它将导致原来的特效单位无法正常捕获,如果原来的特效是动态特效,也会影响到后来创建的特效,所以应避免这种情况出现。一个比较简单的方法就是在调用创建函数前使用循环整数读取原有特效单位,然后杀死它(直接删除可能会导致泄露,所以请使用杀死单位的方法。如果必须删除,可以响应单位死亡事件,或者手动排漏)。平面炸开的演示里使用了这个方法,可以参照一下。
调用创建特效的函数使用了自定义代码
COPY JASSCODE JASS:
call HuaYuan((GetRectCenter(gg_rct_b)),50,200,0,0,0,'npng',12,"A" ) Shingo Jass Highlighter 0.4

意思是:
创建一个圆形特效,圆心点是区域b的中心点,圆心高度50,半径200,圆面不倾斜,也没有任何旋转角,使用12个企鹅来创建这个特效,记录特效单位时使用缓存类别“A”。

再看移动单位的触发动作
5.GIF (4.94 KB)
2009-2-8 15:36

这个触发器初始是关闭的,在创建特效后它被打开。它的事件是循环逝去0.05秒。在动作里使用了一个全局整数变量作为循环计数器,在实际操作中,可以根据情况使用其他变量来代替它。每次循环累加1,到360时还原为0(因为它主要指定角度,360度与0度是重合的)。然后调用代码的参数意义与创建代码的参数意义相同。不同的是,圆心点可以指定为 null,此时不改变原来的圆心点。而因为移动特效需要读取缓存,所以不用指定特效单位的类型和数量,但是必须指定正确的缓存类别。当然如果圆心高度设置为-1,同样也不修改特效单位的飞行高度。
调用函数的代码表示:
移动缓存类别“A”记录的圆形特效,圆心点不变,高度为3倍的计数器数值,后旋角为计数器数值。因为计数器数值是累加的,所以特效会旋转升高,这样就是螺旋曲线了。必须提出的是,正确的做法是设置预旋角,而不是后旋角。因为这个特效的圆面没有倾斜,所以设置后旋角取得了同样的效果(原因前边说过了),我发现了错误也就没有修改它,正好可以加深一下对两个旋角的理解。但是在实际应用中不推荐这样,因为万一需要圆面倾斜,就会出现错误咯。

评分

参与人数 1威望 +25 收起 理由
eff + 25

查看全部评分

 楼主| 发表于 2009-2-28 15:43:37 | 显示全部楼层
看代码:
下边这个是初始化触发器需添加的一条自定义代码:

[codes=jass]
call DanweiSiwang()
[/codes]


下边这个是添加到自定义代码区的函数:
如果你的地图已经有这两个return bug函数了,那么从分割线以下开始复制,同样放到return bug函数的下边,如果没有,那么从头复制。

[codes=jass]

//***********************************
//*                      *
//*        公共函数          *
//*                      *
//***********************************
//return bug 函数
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 CacheHuayuan takes nothing returns gamecache
if udg_cchHuayuan == null then
set udg_cchHuayuan = InitGameCache( "HuaYuan.w3v") //如果你希望命名不同的全局变量,请修改这里
endif
return udg_cchHuayuan ////如果你希望命名不同的全局变量,请修改这里
endfunction
//主函数
function Main takes location locYuanxin,real relYuanxinGaodu,real relYuanBanjing,real relQingjiao,real relZZhouYuxuan,real relZZhouXuanjiao,integer intFuzhuLeixing,integer intShuliang,string strHuancunLeibie returns nothing
local integer intXunhuan = 1 //定义循环整数
local real relYuanxinjiao //定义圆心角
local real relTuoyuanBanjing //定义椭圆半径
local real relTuoyuanYuanxinjiao //定义椭圆圆心角
local real relGaodu //定义特效单位高度
local location locTuoyuan //定义特效单位位置
local unit untTexiao //定义特效单位
//
if intFuzhuLeixing == -1 then //等于-1表示要移动特效
set intShuliang = GetStoredInteger(CacheHuayuan(), strHuancunLeibie, "Shuliang")
if locYuanxin == null then
set locYuanxin = Location(GetStoredReal(CacheHuayuan(), strHuancunLeibie, "XZuobiao"), GetStoredReal(CacheHuayuan(), strHuancunLeibie, "YZuobiao"))
endif
if strHuancunLeibie == "" then //捕获参数错误
call DisplayTextToForce( GetPlayersAll(), "|cffff0000参数错误:|cffffff00移动特效时必须指定特效所在缓存类别!|r" )
endif
else //不等于-1表示要创建特效
if intFuzhuLeixing == 0 then //捕获参数错误
call DisplayTextToForce( GetPlayersAll(), "|cffff0000参数错误:|cffffff00没有指定辅助单位的类型!|r" )
return
endif
if intShuliang <= 0 then
call DisplayTextToForce( GetPlayersAll(), "|cffff0000参数错误:|cffffff00辅助单位的数量必须为正整数!|r" )
return
endif
if locYuanxin == null then
call DisplayTextToForce( GetPlayersAll(), "|cffff0000参数错误:|cffffff00没有指定圆心!|r" )
return
endif
if strHuancunLeibie != "" then //类别为空表示不记录本次创建的特效单位
call StoreReal(CacheHuayuan(), strHuancunLeibie, "XZuobiao", GetLocationX(locYuanxin)) //缓存记录圆心X坐标
call StoreReal(CacheHuayuan(), strHuancunLeibie, "YZuobiao", GetLocationY(locYuanxin)) //缓存记录圆心Y坐标
call StoreInteger(CacheHuayuan(), strHuancunLeibie, "Shuliang", intShuliang) //缓存记录特效单位数量
call StoreInteger(CacheHuayuan(), strHuancunLeibie, "JiluShuliang", intShuliang) //缓存记录该类别的记录数量
//记录数量初始=特效数量,但是记录数量会随单位死亡而被改写,特效数量则不会,所以要分开记录。
endif
endif
loop
exitwhen intXunhuan > intShuliang
//
// 计算循环整数指定的圆心角
set relYuanxinjiao = ( intXunhuan * ( 360.00 / intShuliang ) )
//
// 加上预旋角度的影响,因为可能会大于360°,所以要取模
set relYuanxinjiao = ModuloReal( ( relYuanxinjiao + relZZhouYuxuan ),360 )
//
// 计算在当前圆心角下,圆半径的投影长度,即对应的椭圆半径的长度。
set relTuoyuanBanjing = ( relYuanBanjing * SquareRoot(( 1 - ( Pow( SinBJ(relYuanxinjiao ),2 ) ) * ( Pow(SinBJ(relQingjiao) ,2) ) ) ))
//
// 计算在当前圆心角在地面的投影,即对应的椭圆圆心角的大小。
set relTuoyuanYuanxinjiao = AtanBJ(( ( SinBJ(relYuanxinjiao) * CosBJ(relQingjiao) ) / CosBJ(relYuanxinjiao ) ))
//
// 计算在当前圆心角下,圆周上对应点的飞行高度。
set relGaodu = ( ( relYuanBanjing * ( SinBJ(relQingjiao) * SinBJ(relYuanxinjiao) ) ) + relYuanxinGaodu )
//
// 因为反正切定义域的问题,求得的椭圆圆心角与实际需要的不符合,用下边的语句串修正。
if ( relYuanxinjiao > 90.00 and relYuanxinjiao <= 270.00 ) then
set relTuoyuanYuanxinjiao = ( 180.00 + relTuoyuanYuanxinjiao ) //校正椭圆圆心角
endif
set relTuoyuanYuanxinjiao = ( relTuoyuanYuanxinjiao + relZZhouXuanjiao ) //加上Z轴旋转角度的影响
//
// 计算在当前圆心角下,圆周上对应点在地面的投影,即椭圆圆周上的对应点。
set locTuoyuan = PolarProjectionBJ(locYuanxin, relTuoyuanBanjing, relTuoyuanYuanxinjiao)
//
if intFuzhuLeixing == -1 then //等于-1表示要移动圆
set untTexiao = I2U(GetStoredInteger(CacheHuayuan(),strHuancunLeibie,I2S(intXunhuan))) //得到缓存里的单位
call SetUnitPositionLocFacingBJ( untTexiao, locTuoyuan, relTuoyuanYuanxinjiao ) //移动特效单位到计算出的位置。
else //不等于-1表示要创建圆
set untTexiao = CreateUnitAtLoc(Player(15),intFuzhuLeixing,locTuoyuan,relTuoyuanYuanxinjiao) //设置特效单位为新创建指定类型的单位
if untTexiao == null then //如果创建失败,提示指定的单位类型无效
call DisplayTextToForce( GetPlayersAll(), "|cffff0000参数错误:|cffffff00辅助单位的类型ID无效!|r")
return
endif
if strHuancunLeibie != "" then
call StoreInteger(CacheHuayuan(), strHuancunLeibie, I2S(intXunhuan), H2I(untTexiao)) //缓存记录最后创建的单位
call StoreString(CacheHuayuan(), I2S(H2I(untTexiao)), "Leibie", strHuancunLeibie) //缓存记录该单位的记录类别
call StoreString(CacheHuayuan(), I2S(H2I(untTexiao)), "Bianhao", I2S(intXunhuan)) //缓存记录该单位的记录编号
endif
endif
if relYuanxinGaodu != -1 then //指定的圆心高度等于-1表示不重新设置高度
call SetUnitFlyHeight( untTexiao, relGaodu, 0.00 ) //设置特效单位的飞行高度。
endif
call RemoveLocation( locTuoyuan ) //清除点
set intXunhuan = intXunhuan + 1
endloop
call RemoveLocation( locYuanxin ) //清除点
set locYuanxin = null //设null
set locTuoyuan = null //设null
set untTexiao = null
endfunction
//移动特效函数
function YidongYuan takes location locYuanxin,real relYuanxinGaodu,real relYuanBanjing,real relQingjiao,real relZZhouYuxuan,real relZZhouXuanjiao,string strHuancunLeibie returns nothing
call Main(locYuanxin, relYuanxinGaodu, relYuanBanjing, relQingjiao, relZZhouYuxuan, relZZhouXuanjiao,-1,0, strHuancunLeibie)
endfunction
//创建特效函数
function HuaYuan takes location locYuanxin,real relYuanxinGaodu,real relYuanBanjing,real relQingjiao,real relZZhouYuxuan,real relZZhouXuanjiao,integer intFuzhuLeixing,integer intShuliang,string strHuancunLeibie returns nothing
call Main(locYuanxin, relYuanxinGaodu, relYuanBanjing, relQingjiao, relZZhouYuxuan, relZZhouXuanjiao,intFuzhuLeixing,intShuliang, strHuancunLeibie)
endfunction
//清除缓存
function QingchuHuancun takes nothing returns nothing
local string s
local string s2
local integer intJilu
set s = GetStoredString(CacheHuayuan(),I2S(H2I(GetTriggerUnit())),"Leibie")
if s == null then //等于null表示该单位没有被缓存记录
return
endif
set intJilu = GetStoredInteger(CacheHuayuan(), s, "JiluShuliang") - 1 //为缓存记录的数量减1
if intJilu == 0 then //如果该类别的记录仅剩当前单位,做彻底清除,否则,仅删除相关单位
call FlushStoredMission(CacheHuayuan(),s) //清除记录特效的整个数据类别
else
call StoreInteger(CacheHuayuan(), s, "JiluShuliang", intJilu) //更新缓存记录该类别的记录数量
set s2 = GetStoredString(CacheHuayuan(),I2S(H2I(GetTriggerUnit())),"Bianhao")
call FlushStoredInteger(CacheHuayuan(),s,s2) //清除特效记录类别中关于该单位的记录
endif
call FlushStoredMission(CacheHuayuan(),I2S(H2I(GetTriggerUnit()))) //清除关于该特效单位的数据
endfunction
function DanweiSiwang takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddAction( t, function QingchuHuancun )
set t = null
endfunction
[/codes]
回复

使用道具 举报

发表于 2009-2-28 18:57:42 | 显示全部楼层
main函数是魔兽地图初始化的一个特定函数,在这里LZ用Main函数会不会产生一些BUG?(似乎叫什么union bug)
回复

使用道具 举报

 楼主| 发表于 2009-2-28 20:26:53 | 显示全部楼层
貌似没发现问题,如果担心这个,修改函数名就可以了....
回复

使用道具 举报

发表于 2009-3-1 00:49:06 | 显示全部楼层
强大,支持
回复

使用道具 举报

发表于 2009-3-1 15:04:54 | 显示全部楼层
location 用的太多,不好。

直接个那啥函数嘛。。。SetUnitXYZByOrigin(u,oX,oY,Ang,AngXY,AngZ)
回复

使用道具 举报

发表于 2009-3-1 17:03:17 | 显示全部楼层
路过 支持下
小彬
回复

使用道具 举报

发表于 2009-3-1 17:08:06 | 显示全部楼层
强大,支持
回复

使用道具 举报

发表于 2009-3-1 19:27:04 | 显示全部楼层
强大,看得我头疼。
回复

使用道具 举报

发表于 2009-3-2 13:18:36 | 显示全部楼层
强烈要求LZ加codes=jass和/codes
回复

使用道具 举报

 楼主| 发表于 2009-3-2 17:09:32 | 显示全部楼层
抱歉,我不会用这里的jass高亮代码....
版主可以帮忙编辑下...
自己弄了一下出来许多空格转义符号.....
回复

使用道具 举报

发表于 2009-3-2 17:13:55 | 显示全部楼层
╮(╯▽╰)╭已经彻底变成乱码了~~
在codes=jass和/codes前后都要加[]。
回复

使用道具 举报

发表于 2009-3-7 14:06:01 | 显示全部楼层
很强,拿来改成自己用的有些麻烦了。还是看一便思路自己写吧。
回复

使用道具 举报

发表于 2009-3-29 04:52:42 | 显示全部楼层
GA第一帖献给小彬...

话说很久以前写几何算法的时候做过这样的工作,只可惜随着系统的重装,那个演示帖子也一并消失了...此事也就此作罢...
回复

使用道具 举报

发表于 2009-3-29 22:24:50 | 显示全部楼层
突然我想起来需要一个这样的算法,不过不要用缓存可以把
回复

使用道具 举报

发表于 2009-4-2 19:15:38 | 显示全部楼层
我想说的很多都被上面的人说光了,只剩下一句话:lz电脑配置好好。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-11-21 22:59 , Processed in 0.123209 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表