【War3】英雄作成 – 西行寺幽幽子

发表于 2019-10-17  423 次阅读


国庆期间由于充电头没带用随便买的充电头打DOTA老断电打LOL也断电毒奶粉不想打东方弹幕懒得做导致闲的没事干就使用YDWE制作了一个UUZ的英雄,而不久后就听到了WAR3重置版的消息。
我算是每天抽了几个小时做了这么个英雄,不得不感叹自己已经是个老年人了。现在来介绍下这个英雄吧。

如上图这是一个很标准的LOL式MOBA英雄,拥有一个被动4个主动,就是懒得导入这些技能的图标了,接下来我将会为大家介绍一下每一个技能的效果及实现原理。

首先放上被动技能,它的技能效果如下图。

这是一个大量使用了J的被动技能,并且使用了VJ,不然只有JASS怕是要累死。这里我来贴一段类代码,里面有很详细的注释。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
struct Musugoku
    private unit target //幽灵集火目标
    private unit array ghosts[9]//幽灵
    private real array x[9]//对应幽灵所在的位置。
    private real array y[9]//对应幽灵所在的位置。
    private integer max = 3//最大幽灵数量
    private unit master//UUZ自身
    private integer stacks = 0//层数
    private real baseDegree//起始角度
    private integer overflow = 0//计时器用来判断用的。
    private boolean flag = true//防溢出FLAG
   
    public method resetOverFlow takes nothing returns nothing
        set overflow = overflow - (overflow / 50) * 50//必须要重置周期,否则就会发生每次攻击都会重置伤害间隔的情况,若你觉得这是合理的,就设置其为0。
    endmethod
   
    public method addOverflow takes nothing returns nothing
        set overflow = overflow + 1//看计时器。
    endmethod
   
    public method getOverflow takes nothing returns integer
        return overflow
    endmethod
   
    public method setTarget takes unit target returns nothing
        set this.target = target
    endmethod
   
    public method setMaster takes unit master returns nothing
        set this.master = master
    endmethod
   
    public method setStacks takes integer stacks returns nothing
        if stacks <= max then//这个和计时器相关的,看计时器,这里层数是不能超过最大幽灵数的。
            set this.stacks = stacks
        endif
    endmethod
   
    public method setBaseDegree takes real degree returns nothing
        set this.baseDegree = degree
    endmethod
   
    public method setGhost takes unit ghost returns nothing//设置幽灵,这个最初索引的幽灵不会暴毙,只会一起死,所以i无脑自加了。
        local integer i = 0
        local boolean flag = false
        loop
            if ghosts[i] == null then
                set ghosts[i] = ghost
                set flag = true
            else
                set i = i + 1
            endif
            exitwhen flag
        endloop
    endmethod
   
    public method damageUnit takes integer gi returns nothing//对敌人造成伤害,不知道无敌会不会有驱散掉不了这个效果的情况,如果驱散不了,幽灵会一直在他头上转,但不造成伤害。
        if IsUnitAliveBJ(target) and GetUnitAbilityLevel(target, 'Avul') < 1 then
            call UnitDamageTarget(ghosts[gi], target, I2R(GetHeroInt(master, true)) * 0.3 + 3 + 2 * I2R(GetUnitLevel(master)), false, true, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_DEATH, WEAPON_TYPE_WHOKNOWS)
           
        if GetUnitAbilityLevel(master, 'Ault') > 0 and DistanceBetweenXYs(GetUnitX(master), GetUnitY(master), GetUnitX(target), GetUnitY(target)) <= 1000 then//造成伤害的同时,判断UUZ是否在开大招,开大招且目标在1000码内就给UUZ回血。
                call SetUnitLifeBJ(master, GetUnitState(master, UNIT_STATE_LIFE) + I2R(GetHeroInt(master, true)) * 0.3 + 3 + 2 * I2R(GetUnitLevel(master)) * (0.15 + 0.05 * I2R(GetUnitAbilityLevel(master, 'A009'))))
            endif
        endif
    endmethod
   
    public method getTarget takes nothing returns unit
        return target
    endmethod
   
    public method getMaster takes nothing returns unit
        return master
    endmethod
   
    public method setMax takes nothing returns nothing
        set this.max = 3 + GetUnitLevel(master) / 3
    endmethod
   
    public method destroyMaster takes nothing returns nothing
        set master = null//清除,这一类的方法做的同一件事,不多赘述。
    endmethod
   
    public method destroyTarget takes nothing returns nothing
        set target = null
    endmethod
   
   
    public method destroyGhosts takes nothing returns nothing
        local integer i = 0
        loop
            call KillUnit(ghosts[i])//干掉所有幽灵
            set ghosts[i] = null
            set i = i + 1
            exitwhen i >= stacks
        endloop
        set ghosts = 0//干掉数组
    endmethod
   
    public method getStacks takes nothing returns integer
        return stacks
    endmethod
   
    public method generateGhost takes nothing returns nothing
        if flag then//创建幽灵,flag为FALSE就不再创建幽灵
            set ghosts[stacks - 1] = CreateUnit(GetOwningPlayer(master), 'h004', CosBJ(baseDegree + 360 / I2R(max) * I2R(stacks)) * 200 + GetUnitX(target), SinBJ(baseDegree + 360 / I2R(max) * I2R(stacks)) * 200 + GetUnitY(target), 0)
        endif
        if stacks == max then//一旦层数达到最大值,就要把层数设为false,要问为什么不直接把上面的调条件设置成stacks != max,这是因为到了第9层的时候还需要执行一次,而且这个值也不会达到max + 1,关联的东西太多了。
            set flag = false
        endif
    endmethod
   
    private method setUnitPosition takes integer order returns nothing//设置位置,你能看懂,不多解释,升级的时候会唐突一些,我懒得改了。
        set x[order] = CosBJ(baseDegree + 360 / I2R(max) * I2R(order)) * 200 + GetUnitX(target)
        set y[order] = SinBJ(baseDegree + 360 / I2R(max) * I2R(order)) * 200 + GetUnitY(target)
        set baseDegree = baseDegree + 1
        call SetUnitX(ghosts[order], x[order])
        call SetUnitY(ghosts[order], y[order])
    endmethod
   
    public method damageTarget takes nothing returns nothing//按层数让指定的幽灵去对目标造成伤害,这个伤害不能让英雄本身来造成,所以需要使用循环。
        local integer i = 0
        loop
            call damageUnit(i)
            set i = i + 1
            exitwhen i >= stacks
        endloop
    endmethod
   
    public method surround takes nothing returns nothing
        local integer i = 0
        loop
            call setUnitPosition(i)//指定角度环绕。
            set i = i + 1
            exitwhen i >= stacks
        endloop
    endmethod

endstruct

这里要讲解的是J部分如何保存对象,详细可以搜一下VJASS的教程,只需看完第一些基本的讲解即可。我们定义的对象在JASS中本质会被转换成一个整形变量,这个变量若为空,那就是0。这里我们就要用到哈希表,去提取受到伤害单位的句柄在哈希值对应的索引下的整形数值,虽然这听起来狠晦涩,但本质上就是这样一段代码。

1
2
3
4
local unit target = GetTriggerUnit()//获取挨打单位。
local integer oh = GetHandleId(target)//获取挨打单位的句柄,而不是UUZ的。
local Musugoku obj = 0//初始化一个空指针对象。
set obj = LoadInteger(HT, oh, 0)//Load一下对象,用于接下来的条件判断。

然后如你所见,这里我们去从哈希表提取了保存在哈希表中索引为0的整形数值。如果你不曾保存过或是已经清空,那么获取到的就是0,否则那就是有对象被绑定到这个单位身上了。然后我们就按照已经有幽灵和没有幽灵的情况来分别调用类方法了。
还有一点要注意的是,我这里为了能让异常状态可以被附加在隐形单位的身上,释放技能的马甲被设置成了受击单位的所有者,技能也设置成了可以对友军释放,因此最好多执行几次释放技能命令的触发语句,否则谜之不放。

接下来放Q技能。



这是一个纯J技能,其实没什么好说的,都是非常标准的冲锋之类的玩法,而且这个技能好像是前年做的,因此用的方法可能并不如现在好。唯一要注意的就是我刚说的那个给隐形单位套异常状态的事。


W技能,喜闻乐见的纯T技能,实质上就是加了个带100%闪避和龙卷风减速光环的魔法书,为了兼容性没用2,-11图标位置。


E技能,非纯J技能,这里传参时使用了技能释放点,因为当地图初始载入或是位移后单位碰撞开启后强制位移的话,用其他获取位置的函数就会莫名获取到地图中心,希望到了重置版不会有这种情况。


R技能,非纯J技能,T部分用来放蝴蝶特效,蝴蝶特效是不会造成伤害的蝗虫群技能。
关于可以打断的这个吟唱1秒,其实这触发的时间并非发动技能效果而是释放技能结束。使用的是释放技能结束而不是停止释放技能是因为释放技能结束是特指玩家不进行任何操作来打断释放技能的过程,停止释放技能是包括这一点的,所以用释放技能结束可以制作这种可以打断的吟唱技能,该技能的模板是通魔,如果需要暂停吟唱,可以试试将这里的参数改为释放技能时隐藏其他图标。减CD太麻烦抱歉就没搞。
需要注意的是这里随便给英雄加了个技能,以判断英雄是否在释放大招,这一点在Musugoku类里有所体现。

最后在这里要说的一点就是千万要记住排泄,用完的每一个变量要记得置空,即set null,用完的每一个点,每一个组以及每一个计时器都要记得销毁,每一个死亡的马甲要记得及时删除,虽然你测试时没有什么问题,但是到了真的开始游戏时,这些垃圾变量就会成千上万地堆积,导致游戏越来越卡。

英雄体验视频链接。


引导着你的王道的狂视幻像(Disorder Eye)载着我们的梦来到极贫乏世界。