【游戏功能】
叠层伤害到底该怎么叠?加法派一层加三点,十层才见真章;乘法派一层乘一成,三层就敢叫板——两种叠法写出来的完全是两个技能。今天拆的蚀骨蛊站在乘法派这一边:一蛊一层、一层活六秒、蛊毒一秒一跳,跳数等于层数乘三——八层满蛊的时候一秒二十四,比大多数普攻都疼。这篇的核心代码按引擎技能脚本的全规格走:配置表、蛊虫飞行构件、逐层到期的层表、定时器、调试按钮。
一、效果演示:八颗点,一条上坡
演示场点「下蛊!」,一枚紫蛊拖着尾线钉在怪身上,血条上方八颗层点亮起第一颗——每颗层点自带六秒的小倒计时,先叠的先到期。蛊毒一秒一跳:一层跳三、三层跳九、八层跳二十四,跳的数字一层比一层大,怪身上的紫色裂纹也一层比一层密。你的任务是按着按钮把八层全部喂上去——中途手停,层点一颗颗暗掉,跳数跟着一层层掉下来。演示里故意停手两秒再补蛊,看层点的到期和补层刷新在同一颗点上的接力——这套层表的手感全在那颗点里。
fx-bonerot
二、底层原理:一张逐层到期的层表加一条乘法跳
机制的账本是一张层表。每次命中往表里压一个六秒的倒计时对象,表长就是层数;每帧倒序扫表逐个减秒、到期出表;蛊毒的跳秒计时独立于层表——每一整秒结算一次,跳数等于当时的表长乘三。乘法跳是这套机制和加法系分家的地方:加法系的跳数恒定、层数只决定跳多久,玩家叠层的动力是"磨";乘法系的跳数跟着层数涨,玩家叠层的动力是"滚"——越叠每秒越疼,八层的一秒顶一层八秒。层各自到期是第三根柱子:新蛊压进来的新层救不了旧层,断蛊的惩罚是逐层掉、不是清盘,玩家掉一层补一层还能续命,清盘式的层表会让手残党直接弃疗。
三、核心代码:完整模块(上·骨架)
--------------------------------------------------------------------------------
-- @file BoneRot.lua
-- @brief 蚀骨蛊 —— 一层比一层深的毒,叠八层烧穿骨
-- 客户端表现模块:配置表 / 层表 / 乘法跳结算 / 定时器
--------------------------------------------------------------------------------
local BoneRot = {}
--------------------------------------------------------------------------------
-- 配置与常量
--------------------------------------------------------------------------------
local CONST = {
ROT_CAP = 8, -- 八层封顶
ROT_LIFE = 6.0, -- 每层六秒
ROT_TICK = 1.0, -- 一秒一跳
DMG_PER_STACK = 3, -- 每层跳三
CAST_CD = 2.2, -- 下蛊冷却
BUG_FLY = 0.30, -- 蛊虫飞行
-- 颜色
COLOR_ROT = "#a371f7", -- 蛊紫
COLOR_DEEP = "#4a2a7a", -- 深紫
COLOR_BONE = "#e6edf3", -- 骨白
ZORDER_GROUND = 118,
ZORDER_BUG = 134,
ZORDER_EFFECT = 135,
AUTOINC_BASE = 923000,
}
--------------------------------------------------------------------------------
-- 模块内部状态
--------------------------------------------------------------------------------
local _stacks = {} -- 层表:每个元素一个六秒倒计时
local _bugs = {} -- 飞行中的蛊虫
local _tickT = 0 -- 跳秒计时
local _cdLeft = 0
local _scheduler = nil
local _autoInc = 0
local m_cos = math.cos
local m_sin = math.sin
--------------------------------------------------------------------------------
-- 辅助函数
--------------------------------------------------------------------------------
local function GenID(prefix)
_autoInc = _autoInc + 1
return string.format("%s_%d", prefix or "BRT", CONST.AUTOINC_BASE + _autoInc)
end
local function GetActorPos(actorID)
if not actorID then return nil end
local x = SL:GetValue("ACTOR_POSITION_X", actorID)
local y = SL:GetValue("ACTOR_POSITION_Y", actorID)
if not x or not y then return nil end
return { x = x, y = y }
end
local function SafeRemove(node)
if node and not GUI:Widget_IsNull(node) then
GUI:removeFromParent(node)
end
end
local function ShowTip(msg)
if msg and msg ~= "" then SL:ShowSystemTips(msg) end
end
---蛊虫命中光效
local function CreateRotBurst(x, y, stacks)
local node = GUI:Layout_Create(GUI:Attach_SceneF(), GenID("Burst"), x, y, 0, 0, false)
GUI:setLocalZOrder(node, CONST.ZORDER_EFFECT)
local r = 18 + stacks * 2.5
for i = 1, 12 do
local a1 = (i - 1) / 12 * 6.28
local a2 = i / 12 * 6.28
GUI:DrawLine_Create(node, string.format("r_%d", i), 0, 0, 2,
m_cos(a1) * r, m_sin(a1) * r * 0.4, m_cos(a2) * r, m_sin(a2) * r * 0.4,
CONST.COLOR_ROT, 190)
end
GUI:runAction(node, GUI:ActionSequence(
GUI:ActionFadeOut(0.32),
GUI:CallFunc(function() SafeRemove(node) end)
))
end
骨架的三处定调。_stacks 是倒计时对象的数组而不是"层数加统一计时"——八层八个闹钟才是这套机制的账本,统一计时的版本补一层等于全员续命,乘法跳就成了永动。层点上限、层寿命、跳秒间隔、每层跳数四个数全在 CONST 表里互相牵制,改一个要心算另外三个。CreateRotBurst 的半径跟着层数走——命中光效一圈比一圈大,层数不用念,光圈自己会报数。
四、核心代码:完整模块(下·定时器与乘法跳)
--------------------------------------------------------------------------------
-- 层表维护
--------------------------------------------------------------------------------
local function Rot_Apply()
if #_stacks >= CONST.ROT_CAP then
table.remove(_stacks, 1) -- 满层挤掉最老的一层
end
table.insert(_stacks, CONST.ROT_LIFE)
return #_stacks
end
local function Rot_Update(dt)
for i = #_stacks, 1, -1 do
_stacks[i] = _stacks[i] - dt
if _stacks[i] <= 0 then
table.remove(_stacks, i) -- 到期的层自己散
end
end
end
local function Rot_DotTick(targetID)
if #_stacks <= 0 then return end
local vd = #_stacks * CONST.DMG_PER_STACK
local tp = GetActorPos(targetID)
if tp then
SL:ActorHurt(targetID, vd)
SL:TipAbove(targetID, "-" .. vd)
if #_stacks >= 5 then
SL:PlayBoneCrack(targetID, #_stacks)
end
end
end
--------------------------------------------------------------------------------
-- 蛊虫飞行与命中
--------------------------------------------------------------------------------
local function Bug_Update(bug, dt)
local tp = GetActorPos(bug.targetID)
if not tp then
return false
end
bug.x = bug.x + (tp.x - bug.x) * math.min(1, 7 * dt)
bug.life = bug.life - dt
if math.abs(bug.x - tp.x) < 16 or bug.life <= 0 then
local stacks = Rot_Apply()
CreateRotBurst(tp.x, tp.y, stacks)
SL:TipAbove(bug.targetID, "蛊" .. stacks .. "层")
return false
end
return true
end
--------------------------------------------------------------------------------
-- 公共接口
--------------------------------------------------------------------------------
function BoneRot.Cast(myID, targetID)
if _cdLeft > 0 then return end
if #_stacks >= CONST.ROT_CAP then return end
_cdLeft = CONST.CAST_CD
local mp = GetActorPos(myID)
if mp then
table.insert(_bugs, { x = mp.x + 16, y = mp.y - 58, targetID = targetID,
life = CONST.BUG_FLY * 3 })
end
end
--------------------------------------------------------------------------------
-- 定时器与调试
--------------------------------------------------------------------------------
if not _scheduler then
_scheduler = SL:Schedule(function(dt)
_cdLeft = math.max(0, _cdLeft - dt)
Rot_Update(dt)
_tickT = _tickT + dt
if _tickT >= CONST.ROT_TICK then
_tickT = _tickT - CONST.ROT_TICK
Rot_DotTick(SL:GetValue("MARK_TARGET_ID"))
end
for i = #_bugs, 1, -1 do
if not Bug_Update(_bugs[i], dt) then
table.remove(_bugs, i)
end
end
end, 0.02)
end
SL:ScheduleOnce(function()
ShowTip("技能已加载: 蚀骨蛊 (调试按钮触发)")
end, 1.0)
SL:RegisterLUAEvent(LUA_EVENT_ACTOR_DEAD, "BRT_Dead", function(data)
if data and data.id == SL:GetValue("MARK_TARGET_ID") then
_stacks, _bugs = {}, {}
end
end)
return BoneRot
下半场的节拍器还是那条唯一的定时器,但它同时喂四张嘴:冷却、层表、跳秒、蛊虫——_tickT 这个跳秒累加器是乘法跳的心脏,攒满一秒放一次 Rot_DotTick,跳数现场数表长,层数在跳的瞬间是几就乘几,绝不用上一次的缓存。满层的挤法写在 Rot_Apply 里:挤掉最老的一层而不是拒绝新蛊,玩家的每一箭都有下落,账面不吞粮。死亡钩子把层表和虫表一次清空——怪死了蛊还活着追下一具尸体的版本,是层表模块最经典的闹鬼。
五、调参指南与商业服怎么用
调参先算一笔满蛊账:八层乘三是二十四一跳,八秒满蛊期理论产值一百九十二——把它和玩家十秒普攻产值对表,占四成上下是蛊系的甜区。层寿命六秒对下蛊冷却两点二秒是"手速合格线":合格的手能维持五层以上,不合格的在三到四层晃——层数曲线就是玩家操作水平的实时心电图。跳秒一秒是痛苦的可读周期,半秒一跳数字糊脸,两秒一跳蛊就没了牙。层点的到期顺序要和层表严格一致——先叠的先到期写在视觉上,玩家看层点就知道该补哪一颗。常见坑三个:满层挤旧层时忘了把对应特效的层点同步移位,账本和画面各说各话;死亡钩子只清了层表漏了飞行中的蛊,蛊追着尸体满天飞;跳秒计时没有在层表归零时复位,第一层新蛊要等上一次跳秒的剩余时间,首跳延迟半拍。
商业服里蚀骨蛊是"操作流"门派的招牌:装备垫底的手速党靠八层蛊打出装备党的伤害,操作的价值第一次有了跳数做证据。行会玩法里它是集火发令枪——指挥喊"蛊满",全队的爆发技能按八层那一秒齐射。变体做成蛊品阶:青蛊八层、血蛊十二层、蛊母叠完全场跳,一条层表养三档付费。江湖里它还是下毒流的身份证:八层蛊叠满的瞬间报出跳数,跳数就是这门手艺的段位。这一篇的演示和整套模块照抄能跑,改的就是 CONST 那张表。
写完留一句给做叠层系的同学:层表卖的是"每层都有名字"——层点的每一颗到期都清清楚楚,玩家的手速才有地方使。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
【游戏功能】 安全巡检扫出一笔可疑的挂账:玩家的"周围单位结算"列表里,同一只怪每零点八秒出现一次,可战斗记录里玩家根本没出…
【游戏功能】 困灵阵的全机制就一句:阵落在它脚下,八秒里它就是圈中之物——敢跨出圈沿,一步吃十五还被弹回去,你在圈外安安稳稳…
【游戏功能】 先泼油还是先点火?这道题答错的代价是一地白烧的火——灯点在空地上,怪还没踩上来,四秒的火一点没沾着它的毛。火油…
【游戏功能】 寻路组收到一笔诡异的工单:怪物巡逻到某个坐标段必卡三秒,像踩了看不见的门槛——排查两小时,发现那段路上有一个上…
【游戏功能】 local a, b = math.min(x1, x2), math.max(x1, x2) ——一行把两根…
【游戏功能】 测试组报过一口邪门的单:头目的读条明明被打断过,技能照样出了膛——查了半天不是打断失效,是打断只"清了"不"冻…