找回密码
 点一下
查看: 3458|回复: 19

为何要学J ---- 刚刚学会点皮毛的感言

[复制链接]
发表于 2009-6-13 15:46:25 | 显示全部楼层 |阅读模式
[仅仅适用于不会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
---------

- -当然这个太简单了似乎没什么用.那么弄个比较复杂的.

跳跃类的技能
跳跃类的技能与普通的高速移动类技能不同.不但要移动,而且要设置高度,
连续变化的高度是一条抛物线
要做的就是代入已知的条件从而得到应该在的高度

GetH.jpg
已知的条件:
起点到终点的距离: 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里将这个函数加入, 然后直接在触发中就可以使用~~
t1.jpg
甚至可以做用函数做许多魔兽里原来没有的功能.
t2.jpg

总之..自定义函数的功能,让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]


//=======================================



//=======================================

评分

参与人数 1威望 +5 收起 理由
血戮魔动冰 + 5

查看全部评分

发表于 2009-6-13 16:14:10 | 显示全部楼层
hmmmm,这帖不错

后半段技能的内容意义不大
回复

使用道具 举报

发表于 2009-6-13 16:44:56 | 显示全部楼层
很好很强大~~

话说。。我当时似乎为了完美排泄。。。因为地图很卡
回复

使用道具 举报

发表于 2009-6-13 16:45:11 | 显示全部楼层
学J的好处在于可以更灵活地控制语句的执行
回复

使用道具 举报

阿里山慝少 该用户已被删除
发表于 2009-6-13 17:04:26 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

发表于 2009-6-13 17:12:49 | 显示全部楼层
对C没啥帮助只有变量定义的格式是相同的,关键字风马牛不相及
回复

使用道具 举报

阿里山慝少 该用户已被删除
发表于 2009-6-13 17:15:06 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

发表于 2009-6-13 17:18:19 | 显示全部楼层
语法不重要,重要的是算法
回复

使用道具 举报

发表于 2009-6-13 17:26:33 | 显示全部楼层
算法......
如果基本逻辑结构也算的话,或许还有点用处
其实JASS的算法更像是常识
回复

使用道具 举报

发表于 2009-6-13 17:28:25 | 显示全部楼层
话说我当初为了做抛物线写了个很神奇的系统......

用的六个变量:Vx, Vy, Vz, Ax, Ay, Az

物理万岁.......= =|||
回复

使用道具 举报

发表于 2009-6-13 17:39:06 | 显示全部楼层
好冷啊
回复

使用道具 举报

阿里山慝少 该用户已被删除
发表于 2009-6-13 17:43:13 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

发表于 2009-6-15 20:06:38 | 显示全部楼层
这个WOW8也有
回复

使用道具 举报

发表于 2009-6-15 21:08:18 | 显示全部楼层
都是一个作者
回复

使用道具 举报

发表于 2009-6-15 22:43:34 | 显示全部楼层
刚瞄了一眼WOW8所以有印象
回复

使用道具 举报

发表于 2009-6-15 22:57:15 | 显示全部楼层
鼓励发心得。

学会j就是不做地图的开始
回复

使用道具 举报

发表于 2009-6-16 00:11:01 | 显示全部楼层
楼上你不能说出真相啊!
回复

使用道具 举报

发表于 2009-6-16 14:01:58 | 显示全部楼层
前言的红字部分,我第一眼看到想起了鲁迅和刘和珍,第二眼想起了成龙和霸王。
回复

使用道具 举报

发表于 2009-6-16 22:40:26 | 显示全部楼层
话说,抛物线不是用y=x^2计算出来的么。
回复

使用道具 举报

发表于 2009-7-5 14:58:40 | 显示全部楼层
好东西~在犹豫中啊……自己的C#经验和没有一样~
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-12-22 16:09 , Processed in 0.070350 second(s), 26 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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