Starbound mod 武器制作教程(二)

接下来我们来看energymeleeweapon.lua
应该能解决不少上篇在看animation的时候留下的问题

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
require "/scripts/util.lua"
require "/scripts/vec2.lua"
require "/items/active/weapons/weapon.lua"

function init()
animator.setGlobalTag("paletteSwaps", config.getParameter("paletteSwaps", ""))
animator.setGlobalTag("directives", "")
animator.setGlobalTag("bladeDirectives", "")

self.weapon = Weapon:new()

self.weapon:addTransformationGroup("weapon", {0,0}, util.toRadians(config.getParameter("baseWeaponRotation", 0)))
self.weapon:addTransformationGroup("swoosh", {0,0}, math.pi/2)

local primaryAbility = getPrimaryAbility()
self.weapon:addAbility(primaryAbility)

local secondaryAttack = getAltAbility()
if secondaryAttack then
self.weapon:addAbility(secondaryAttack)
end

self.weapon:init()

self.activeTime = config.getParameter("activeTime", 2.0)
self.activeTimer = 0
animator.setAnimationState("blade", "inactive")
end

function update(dt, fireMode, shiftHeld)
self.weapon:update(dt, fireMode, shiftHeld)

local nowActive = self.weapon.currentAbility ~= nil
if nowActive then
if self.activeTimer == 0 then
animator.setAnimationState("blade", "extend")
end
self.activeTimer = self.activeTime
elseif self.activeTimer > 0 then
self.activeTimer = math.max(0, self.activeTimer - dt)
if self.activeTimer == 0 then
animator.setAnimationState("blade", "retract")
end
end
end

function uninit()
self.weapon:uninit()
end

比如init()一开始就发现了那几个没找到的GlobalTag 出处。而且我们可以发现这三个都是空的)
虽然不知道为啥是空的,但是管它呢,反正没用了。

self.weapon = Weapon:new() 这个new是weapon.lua的函数,注意到lua脚本文件的最上方往往都有引用的脚本名称,本脚本引用了util.lua vec2.lua weapon.lua 这三个脚本
这些脚本我们不会去细看,如果有需要理解的地方,我们就翻出来单独看某个函数就行。

那么这个new是什么,翻出来找定义。

1
2
3
4
5
6
7
8
9
10
11
12
function Weapon:new(weaponConfig)
local newWeapon = weaponConfig or {}
newWeapon.damageLevelMultiplier = config.getParameter("damageLevelMultiplier", root.evalFunction("weaponDamageLevelMultiplier", config.getParameter("level", 1)))
newWeapon.elementalType = config.getParameter("elementalType")
newWeapon.muzzleOffset = config.getParameter("muzzleOffset") or {0,0}
newWeapon.aimOffset = config.getParameter("aimOffset") or (newWeapon.muzzleOffset[2] - 0.25) -- why is it off by 0.25? nobody knows!
newWeapon.abilities = {}
newWeapon.transformationGroups = {}
newWeapon.handGrip = config.getParameter("handGrip", "inside")
setmetatable(newWeapon, extend(self))
return newWeapon
end

一般来说,lua的名字为new的函数,都是用来继承的,也就是新模块调用这个new函数就可以把定义new函数的模块的内容继承过去。这个过程是通过setmetatable这个函数来完成的,不懂就查百度谷歌,懒得查就别管了。

总之我们可以看到这个函数返回的newWeapon里面基本上也就是定义了一些奇奇怪怪的变量,懒得管了,你看注释里都写了nobody knows!,可见是玄学代码,动了就会炸。总之我们至少知道了这个new函数是在做什么,因此我们pass,到时候发现了脚本使用self.weapon的时候再回来找对应变量吧。

行吧下一句就是,或者说,到处都是,这说明这个lua脚本基本上可以当成是一个小weapon.lua)

self.weapon:addTransformationGroup
这个函数当然也是继承来的,我们去weapon.lua里找定义。

1
2
3
4
function Weapon:addTransformationGroup(name, offset, rotation, rotationCenter)
self.transformationGroups = self.transformationGroups or {}
table.insert(self.transformationGroups, {name = name, offset = offset, rotation = rotation, rotationCenter = rotationCenter})
end

table.insert就是往table里插入内容,而transformationGroup上一篇里应该是介绍过了。这里不赘述。整个函数的意思也就是创建一个transformationGroup变量,然后往里面塞入传入的参数(name offset rotation rotationCenter)。

注意到第一句 addTransformationGroup 的参数里,rotation的对应参数是
util.toRadians(config.getParameter(“baseWeaponRotation”, 0))
那我们去util.lua里找找这个函数,哦好吧就是简单的角度单位转换,要是不知道你可能得复习下中学数学)

接下来定义了个 local primaryAbility = getPrimaryAbility()
getPrimaryAbility 是上面引用的weapon.lua里的 WeaponAbility 模块里的函数,具体功能是返回配置文件(即activeitem)里指定的primaryability对应的lua脚本,这里指的是meleecombo.lua 由于weapon.lua里有两个模块,一个是Weapon,一个是WeaponAbility,比较容易混乱,所以特此加粗注意。
下一行又把primaryability当参数传到 self.weapon:addAbility 里了,我们来看看这个函数。

1
2
3
4
function Weapon:addAbility(newAbility)
newAbility.weapon = self
table.insert(self.abilities, newAbility)
end

把Weapon这个模块自己传入了primaryability里面,没看懂。
然后把primaryability 插入了self.abilities 里面,这个
self.abilities 在new里定义了,顾名思义应当是保存武器功能配置的,那么总结这个函数的功能就是把传入的配置加入一个weapon表,然后塞入self.abilities里。
同时在update里也可以看到是在对abilities里的数值进行更新的,不过基本上就没有其他地方提及abilites了,大部分相关功能可能都是在abilities里指明的lua文件实现的。

primary之后是 secondaryAttack ,和上面一样,不说了

然后调用了weapon的init,其中包含一个for循环,给每个ability都调用了它的init函数。

然后set了动画状态,我们上一篇已经看过animation文件了

接下来是update函数

self.weapon:update ,这个函数内容是更新后面的参数,再加上调用abilities的update函数。我们来看下meleecombo.lua,发现这个东西继承了 WeaponAbility这个模块,而 WeaponAbility 这个模块和Weapon一样写在了weapon.lua里,注意一个lua文件不一定只对应一个模块。
而且meleecombo里面确实有一个self.weapon,对应了上面Weapon:addAbility里的操作。

我们继续看abilities的update函数,首先调用了父级即WeaponAbility 的update,这个函数的功能只有更新三个参数而已。
接下来是计时器更新,然后切换状态。
readyFlash 这个函数在下面有定义,并且我们发现了那个一直失踪的tag:bladeDirectives ,在该函数中,将 bladeDirectives 通过 animator.setGlobalTag 函数设置为了 self.flashDirectives ,然而我只在broadswordcombo.weaponability这个JSON文件中找到了flashDirectives,虽然不清楚JSON文件里的键值对是怎么加载到lua里面的,但是管它的,我们看到JSON里的
flashDirectives 的值是 “fade=FFFFFFFF=0.15” ,这玩意我查了一下,应该是这个Image Processing Directives,在wiki页面有介绍,fade=某个颜色=某个值就是在说让一个图片逐渐向某一颜色转变,后面的值是转变的程度
到此,结合上一篇我们遇到的位置,大家应该就清楚这个东西发挥了什么作用了吧,也就是给剑刃特效变颜色用的,不过我倒是在游戏里没注意到这个细节。
之后的内容大家自己理解,理解不了就pass

这个ability的lua脚本后面就都是状态的逻辑了,每种状态前面都加了简短的介绍,总之pass。暂时没必要深究。

ok还记得我们到哪了么,我刚介绍完了energymeleeweapon.lua的update函数的第一句。我们继续往下看。
接下来的逻辑是如果该武器有至少一个功能激活的话,就把nowactive这个变量设置为true,然后判断activetimer计时器并伸出剑刃,或者nowactive为false,则判断计时器并收回剑刃。

至此我们搞定了维奥大剑的lua脚本,尽管还是很混乱,不得不说武器这里的脚本确实比较复杂,但是如果上手制作的话我觉得并不会太困难,至少可以试一试。