|
[仅仅适用于不会jass的同学]
//=======================================
热情啊.. 做什么都需要热情
//=======================================
前言
//=======================================
其实卡布刚开始要求我学Jass的时候我是拒绝的,不能你让我学就学,我要先看看有什么好处
不要总说jass好,同学问起来我在学什么,我说跟你学J,最后同学们都去学J,
结果发现J不是我说的那么好用,结果联合起来鄙视我
这样就很不好
后来我知道Jass是为了轻松的做地图,于是跟卡布学了一个月,感觉还不错.
于是推荐给同学们. 发帖之前卡布就对我说,不要加很多诱惑的语言进去,该怎样说就怎样说,
不能诱导观众.希望同学们了解到J的方便.我学J感觉到做图轻松,你们学会J也同样会感觉轻松.
//=======================================
下面说的这些..仅仅是一些J与T不同的地方,还有一般J的用法
//=======================================
一般做图,我都是写触发的..毕竟是中文的. 比英文要亲近的多.
偶尔加一句自定义代码,也是直接从某触发转成J的..
所以一般情况下J和T都是差不多的.
除了局部变量之外,J还有一个T里完成不了,或者说要经过很多周折,费很多的时间才可以模拟的功能
那就是自定义函数..
.
.
.
.
函数:将一段经常需要使用的代码封装起来,在需要使用时可以直接调用
.
也可以说函数就是一连串的动作..我们平时用触发的时候,编辑各种触发动作,事实上也是在调用各个函数
BLZ把经常用的一些功能封装起来,然后做成一条条的触发供我们使用
========================
比如经常用的
单位 - 创建多个单位(面向角度) 这个动作,实际上就是一个函数
这个函数里包含了以下几个动作:
-------------------------
单位组 - 清空(最后创建的单位组)
循环N次:
- 创建单位
- 单位组 - 添加 (最后创建的单位) 到 (最后创建的单位组)
-------------------------
于是用这个函数创建单位之后,我们可以直接用(最后创建的单位组)来命令刚刚创建的单位
如果没有这个函数的话, 我们必须写上面的那一串动作.就显得十分不方便了.
========================
第二个例子:
英雄 - 创建物品给英雄
这个函数大家应该会有印象,如果英雄背包有空格的话,就直接到背包里,
如果没有空格的话,会落在英雄脚下.
这个函数里实际上包含了如下动作
-------------------------
物品 - 创建(物品)在(英雄)所在位置
英雄 - 把(最后创建的物品)给(英雄)
-------------------------
所以就达到了上面说的那种效果了
========================
最后个例子:
等待(游戏时间)
这个比较复杂了,动作如下:
-------------------------
设置 t = (新建计时器)
IF
(设定的等待时间) 大于 0
THEN
计时器 - 开启计时器 t,时间: (设定的等待时间),一次性
循环:直到 (计时器t的剩余时间) 小于或等于 0
- 如果 (计时器t的剩余时间) > 2.00 秒
- 那么 等待( (计时器t的剩余时间) x 0.1 )秒
- 否则 等待( 0.1 )秒
-------------------------
因为"等待"这个动作是实际的时间,遇到玩家掉线或者游戏暂停时,他还是会继续计时.
而"计时器"是使用游戏内时间,暂停时,计时器的时间也会不动,
利用这个特点,直到计时器到期为止,一直会循环等待的动作,也就做成了等待游戏内时间的效果
如果没有这个函数的话,可想而知.. 难道要每次等待时都写这么一大串么..
========================
看完了上面这些, 大概对函数有一定的了解了吧.
函数的方便是T做不到的.
下面就说说怎么自己制作函数
最简单的例子是数学里的函数,
比如 f(x) = x + 1
好好学习的同学都应该知道
f 是函数名, x 是函数的参数, 也就是自变量
这个函数完成的功能就是计算x+1的值
用j写出来的话如下:
[jass]
function f takes real x returns real
return x + 1
endfunction
[/jass]
简单的介绍下格式
function 函数名 takes 参数类型 参数名 returns 返回值类型
计算并返回 x + 1
endfunction
..
函数名, 就是函数的名字, 是区分大小写的,有了名字,我们才可以在后面使用它
参数,就是要代入的数据,比如上面的是将x代入计算
返回值类型, 就是计算后得到结果的类型,
比如上面计算的结果是一个实数, 所以就要用real
函数写出来了,下一步就是使用
设置 Y = f(3)
就是把3代入函数进行计算,得到的结果就是3+1
Y的值就是4
---------
f(x) = x + 1
f(3) = 4
---------
- -当然这个太简单了似乎没什么用.那么弄个比较复杂的.
跳跃类的技能
跳跃类的技能与普通的高速移动类技能不同.不但要移动,而且要设置高度,
连续变化的高度是一条抛物线
要做的就是代入已知的条件从而得到应该在的高度
已知的条件:
起点到终点的距离: D
最高点的高度与D的比值(弧度):R
(点)与起点的水平距离:X
然后经过计算得到这一点的高度..具体计算方法不多说直接说公式了
f(X,R,D) = 4R(X-X·X/D)
比如f(300,0.5,1000)的结果为420.
也就是说跳跃1000距离,弧度为0.5的情况下,离开起点距离300时,距地面高度为420
[jass]
function f takes real X , real R , real D returns real
return 4 * R * (X-X*X/D)
endfunction
[/jass]
..
如果只用T,当然也会有办法做出来..但是不免会很麻烦..
---------------
上面的这两个似乎都太抽象了,毕竟只是数字的运算, 与地图没啥联系..那么请看下面这个
自动漂浮文字:
自动的创建漂浮文字,并在设定的时间后删除
封装的动作如下:
---------------
设置 t = 新建漂浮文字
设置漂浮文字的文字大小
绑定漂浮文字到(单位)头顶
设置漂浮文字颜色
禁用漂浮文字永久可见
设置漂浮文字移动方向和速度
设置漂浮文字生命周期
---------------
如果用T的话,需要好几条动作来完成, 而我们可以将这些动作封装到一起,用的时候就方便多了
如下:
[jass]
function AutoCreateTextTag takes string s,unit whichUnit,real zOffset,real size,integer red,integer green,integer blue,integer alpha,real timeout,real speed,real angle returns nothing
local texttag t = CreateTextTag()
call SetTextTagText(t , s , size)
call SetTextTagPosUnit(t , whichUnit , zOffset)
call SetTextTagColor(t , red , green , blue , alpha)
call SetTextTagPermanent(t , false)
call SetTextTagVelocityBJ(t , speed , angle)
call SetTextTagLifespan(t , timeout)
set t = null
endfunction
//AutoCreateTextTag(文字,单位,高度偏移,大小,红,绿,蓝,透明,生命周期,移动速度,移动方向)
[/jass]
甚至可以在UI里将这个函数加入, 然后直接在触发中就可以使用~~
甚至可以做用函数做许多魔兽里原来没有的功能.
总之..自定义函数的功能,让J可以更简单的完成更多的功能..
所以说. J并不是那么麻烦,而是更方面使用的东西
学J只是为了更轻松的完成地图.
以上..
//=======================================
后记
//=======================================
许多人对我学jass都不明白..
在我学J之前,他们会说用T就足够了,专门去学J是很傻的一件事..,为何要花时间学那么麻烦的东西.
当然, 在我师傅卡布的热情教导下(比如半夜突然爬起来然后教我一个算法..)..
还是学会了J.. 嗯准确的说仅仅是一点皮毛,
学了J我才发现,原来学J不是自找麻烦.而是为了更轻松的做图
//=======================================
后续:技能的制作 以及 成品技能函数
//=======================================
后续:
技能的制作
经常能看到大师们的演示,一个技能,仅仅需要一行的调用,就可以完成一连串庞大的动作
产生十分绚丽的效果.
当然,再复杂的函数,也是一条条的动作封装成的.
下面说一个很简单的技能
使用风暴锤后立即移动到对方身前,并对敌人造成技能等级x敏捷值的伤害
这个技能的动作如下:
单位 - 命令 (触发单位) 对 (技能施放目标) 造成 ((转换 (风暴之锤 的等级对 (触发单位)) 为实数) x (转换 (敏捷 对 (触发单位) (包括 加成)) 为实数)) 点伤害,攻击类型: 混乱 伤害类型: 冰冻
等待0.1秒游戏时间
单位 - 立即移动(触发单位)到(技能释放目标)的位置
如果用J来做的话..
[jass]
function FBC takes unit u , unit t returns nothing
call UnitDamageTargetBJ( u, t, I2R(GetUnitAbilityLevelSwapped('ANca', u)*GetHeroStatBJ(bj_HEROSTAT_AGI, u, true)), ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL )
call PolledWait(0.1)
call SetUnitPosition(u,GetUnitX(t),GetUnitY(t))
endfunction
[/jass]
在技能的动作下面只需要call FBC(GetTriggerUnit(),GetSpellTargetUnit())
就会自动的进行下面的功能,而且还避免了等待时间后造成无法得到技能释放目标的BUG
当然,如果只这样的话,还是不够的,这样也没有减少多少工作量
那么我们可以在函数上改动一下,以适应更多技能
增加一个技能类型,就可以适应多种技能,
再增加一个英雄属性类型,就可以做出与更多属性挂钩..
改造如下
[jass]
function FBC takes unit u ,unit t,integer abil,integer stat returns nothing
call UnitDamageTargetBJ( u, t, I2R(GetUnitAbilityLevelSwapped(abil, u)*GetHeroStatBJ(stat, u, true)), ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL )
call PolledWait(0.1)
call SetUnitPosition(u,GetUnitX(t),GetUnitY(t))
endfunction
[/jass]
这样call FBC(GetTriggerUnit(),GetSpellTargetUnit(),'ANca',1)
就可以造成风暴锤等级x敏捷的伤害.
在其他的技能里,可以call FBC(GetTriggerUnit(),GetSpellTargetUnit(),'AUfn',2)
来造成 霜冻新星的等级x智力的伤害
如果不用函数的话, 每个技能都需要设置3条动作哦..而且, 触发器里动作编辑的速度实在很慢...
熟练运用后,就可以尝试更多的动作,做出更厉害的技能~
-------
关于xx系统的制作
系统,也就是能够(自动)完成某一系列动作的东东.
比如现在许多的物品合成系统..野外刷怪系统.
说到底不外乎是用函数完成的一连串的动作...
不在此举例了
-------
成品技能函数举例:
linzefei橙的弹幕函数
只需要一行.. 就可以按设定的距离让一个马甲往指定方向飞,而且还可以伤害到沿途的单位
call AddMoveMode(玩家,辅助单位id,初始x,初始y,移动角度,移动速度,最大距离,碰撞检查范围,伤害值)
如果要用触发来制作的话,首先第一点就是,很难做到可以多人使用
第二点,如果多个技能需要做马甲飞行的话,必须每个技能做一遍....
而用J, 只需要把函数写出来,然后要用到的地方添加一个调用的动作就可以了十分方便.
以下是全部的函数, 橙子同学已经加上了很详细的说明
[jass]
//调用方法:
//call AddMoveMode(玩家,辅助单位id,初始x,初始y,移动角度,移动速度,最大距离,碰撞检查范围,伤害值)
//角度 按角度制即 0-360
//==============code line==============
globals
integer array udg_MoveIndex
real array udg_MoveSpeed
real array udg_MoveAngle
real array udg_MoveRange
real array udg_MoveDamage
real array udg_MoveDistance
unit array udg_MoveUnit
filterfunc udg_udg_BarrierUnitSetselFilter
boolean udg_BarrierUnitSetsel
group udg_BarrierUnitSetselGroup=CreateGroup()
integer udg_SetselInt
endglobals
function PopUnit takes integer id returns nothing
local integer i=udg_MoveIndex[0]
set udg_MoveUnit[id]=udg_MoveUnit[ i]
set udg_MoveSpeed[id]=udg_MoveSpeed[ i]
set udg_MoveDistance[id]=udg_MoveDistance[ i]
set udg_MoveAngle[id]=udg_MoveAngle[ i]
set udg_MoveRange[id]=udg_MoveRange[ i]
set udg_MoveDamage[id]=udg_MoveDamage[ i]
set udg_MoveUnit[ i]=null
set udg_MoveIndex[0]=i-1//指针左移
endfunction
function MoveSetsel takes nothing returns boolean//判断是否碰到
local unit u
if udg_BarrierUnitSetsel or IsUnitType(GetFilterUnit(),UNIT_TYPE_DEAD) then//一旦此变量真 亦即选取到敌人单位 就跳过以下动作(只伤害1个单位)
return FALSE
endif
set u=GetFilterUnit()
if IsUnitEnemy(udg_MoveUnit[udg_SetselInt],GetOwningPlayer(u))==TRUE then//如果选取单位是敌人
set udg_BarrierUnitSetsel=TRUE//设置此判断变量真 然后伤害选取到的敌人
call UnitDamageTarget(udg_MoveUnit[udg_SetselInt],u,udg_MoveDamage[udg_SetselInt],TRUE,FALSE,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS )
call KillUnit(udg_MoveUnit[udg_SetselInt])//杀死弹幕单位
call PopUnit(udg_SetselInt) //把最后1个元素 移动到 销毁元素位置
endif
set u=null
return FALSE//返回假 单位组会仍是空单位组
endfunction
function MoveMode takes nothing returns nothing
local integer i=udg_MoveIndex[0]//获得栈里当前记录单位数
local real x
local real y
loop
exitwhen i==0// 如果栈拥有 >0 个单位 就会从 高id往低id 的对栈里每个单位执行动作
if udg_MoveDistance[ i]<0 then//如果移动距离到了 就杀死单位 记录销毁序号
call KillUnit(udg_MoveUnit[ i])//就杀死单位
call PopUnit(i) //把最后1个元素 移动到 销毁元素位置
else//否则移动单位 同时判断是否碰撞单位 如果碰到就不移动
set x=GetUnitX(udg_MoveUnit[ i])+Cos(udg_MoveAngle[ i])*udg_MoveSpeed[ i]//获得位移坐标x
set y=GetUnitY(udg_MoveUnit[ i])+Sin(udg_MoveAngle[ i])*udg_MoveSpeed[ i]//获得位移坐标y 到 ("+R2S(x)+","+R2S(y)+")")
set udg_BarrierUnitSetsel=FALSE//初始化布尔值变量
set udg_SetselInt=i//记录当前单位id
call GroupEnumUnitsInRange(udg_BarrierUnitSetselGroup,x,y,udg_MoveRange[ i],udg_udg_BarrierUnitSetselFilter)//选取坐标附近指定范围的所有单位检查条件是否匹配
if udg_BarrierUnitSetsel==FALSE then//如果此为假 亦即没有选取到敌人单位
call SetUnitX(udg_MoveUnit[ i],x)//移动单位到指定x坐标
call SetUnitY(udg_MoveUnit[ i],y)//移动单位到指定y坐标
set udg_MoveDistance[ i]=udg_MoveDistance[ i]-udg_MoveSpeed[ i]//减少记录的距离 亦即记录剩下移动距离
else
endif
endif
set i=i-1
endloop
endfunction
//call AddMoveMode(玩家,辅助单位id,初始x,初始y,移动角度,移动速度,最大距离,碰撞检查范围,伤害值) //角度 按角度制即 0-360
function AddMoveMode takes player p,integer uid,real x0,real y0,real r,real speed,real juli,real range,real damage returns nothing
local integer i
set udg_MoveIndex[0]=udg_MoveIndex[0]+1 //指针右移
if udg_MoveIndex[udg_MoveIndex[0]]!=0 then //如果此位置记录销毁id
set i=udg_MoveIndex[udg_MoveIndex[0]] //设置取得id=此被销毁id
else //如果此位置没记录销毁id
set i=udg_MoveIndex[0] //设置取得id=指针位置
endif
set r=bj_DEGTORAD*r //把角度制转 弧度制 (例:180转bj_PI)
set udg_MoveUnit[ i]=CreateUnit(p,uid,x0,y0,r)//创建单位 记录单位
set udg_MoveSpeed[ i]=speed//记录速度
set udg_MoveDistance[ i]=juli//记录最大距离
set udg_MoveAngle[ i]=r//记录移动角度
set udg_MoveRange[ i]=range//记录碰撞检查范围
set udg_MoveDamage[ i]=damage//记录伤害值
endfunction
function InitMoveMode takes nothing returns nothing//初始化函数
set udg_udg_BarrierUnitSetselFilter=Filter(function MoveSetsel)
call TimerStart(CreateTimer(),0.01,TRUE,function MoveMode)//永久开启计时器
endfunction
//==============code line==============
[/jass]
//=======================================
完
//======================================= |
评分
-
查看全部评分
|