【游戏功能】
数值组复盘过一场灭团:全队血量健康、输出达标,灭在头目百分之五的血线上——事后逐帧回放,答案是一发没人喊过的同归爆:战士把两千血烧到剩一,一口气炸出一整片六千,怪倒了,他也倒在了下一拍的普攻里。指挥的复盘里只写下了一句:这一发,该喊的。今天这篇拆同归爆——把血当炸药点的机制,代码照引擎技能脚本的全规格来,一节不缺。
一、效果演示:一秒点火,半屏清账
演示场点「同归!」:玩家脚下先炸开一圈红圈预警——一秒的点火期,红圈一圈圈收拢,火粒往身上卷;点火结束的瞬间,整条血烧到剩一,烧掉多少血就按三倍炸出去:三百血炸九百,半屏之内的大怪直接吃满,震屏、闪红、双层冲击环全套伺候。炸完的你只剩一口血、周身发红发虚——大怪的下一记普攻都可能是最后一根稻草。演示里可以试两种血量点火:满血点火炸九百但接下来的仗步步惊心,压到半血点火炸四百五、炸完还能打——什么时候点火,就是这门爆发的全部算术——早了亏杠杆,晚了没命点。
fx-lastblaze
二、底层原理:一条点火通道加一次血雷换算
模块的机关是三段。点火段:一秒的预热通道,通道里玩家不可移动、红色预警圈画给所有人看——同归爆不是瞬发,点火期是给队友的信号、也是给玩家的反悔窗(本模块的反悔窗做成了不可退:点了就炸,狠就狠在这里)。换算段:通道结束时读当前血量,烧到剩一,烧掉的差额乘三就是伤害——乘三是这套机制的杠杆,杠杆的高低直接决定它是一场仗的底牌还是常规输出。清算段:炸出的范围伤害按距离全额给主目标,玩家自己进入"虚脱态"——血上限不发虚、但被怪的普攻一碰就见底。三段共用模块唯一的一条定时器节拍,点火、清算、虚脱三本账不并表,各走各的分段。
三、核心代码:完整模块(上·骨架)
--------------------------------------------------------------------------------
-- @file LastBlaze.lua
-- @brief 同归爆 —— 烧到只剩一口气,炸它一整片
-- 客户端表现模块:配置表 / 预警圈构件 / 血雷换算 / 定时器
--------------------------------------------------------------------------------
local LastBlaze = {}
--------------------------------------------------------------------------------
-- 配置与常量
--------------------------------------------------------------------------------
local CONST = {
FUSE_LIFE = 1.0, -- 点火一秒
BLAZE_CD = 15.0, -- 冷却十五秒
LEFT_HP = 1, -- 炸完剩一
BLAZE_RATE = 3.0, -- 烧一炸三
BLAZE_RADIUS = 160, -- 半屏火圈
-- 颜色
COLOR_BLAZE = "#f85149", -- 烈焰
COLOR_DEEP = "#7a1d1d", -- 余烬
COLOR_FLASH = "#ffe08a", -- 爆白
ZORDER_GROUND = 118,
ZORDER_WARN = 119,
ZORDER_EFFECT = 135,
AUTOINC_BASE = 929000,
}
--------------------------------------------------------------------------------
-- 模块内部状态
--------------------------------------------------------------------------------
local _fuseT = 0 -- 点火余时
local _cdLeft = 0
local _burning = false
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 "LBZ", CONST.AUTOINC_BASE + _autoInc)
end
local function GetMyPos()
local x = SL:GetValue("ACTOR_POSITION_X", SL:GetValue("USER_ID"))
local y = SL:GetValue("ACTOR_POSITION_Y", SL:GetValue("USER_ID"))
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 CreateWarnRing()
local mp = GetMyPos()
if not mp then return end
local node = GUI:Layout_Create(GUI:Attach_SceneF(), GenID("Warn"),
mp.x, mp.y - 30, 0, 0, false)
GUI:setLocalZOrder(node, CONST.ZORDER_WARN)
for i = 1, 36 do
local a1 = (i - 1) / 36 * 6.28
local a2 = i / 36 * 6.28
GUI:DrawLine_Create(node, string.format("w_%d", i), 0, 0, 3,
m_cos(a1) * CONST.BLAZE_RADIUS, m_sin(a1) * CONST.BLAZE_RADIUS * 0.4,
m_cos(a2) * CONST.BLAZE_RADIUS, m_sin(a2) * CONST.BLAZE_RADIUS * 0.4,
CONST.COLOR_BLAZE, 180)
end
GUI:setScale(node, 1.0)
GUI:runAction(node, GUI:ActionSequence(
GUI:ActionScaleTo(CONST.FUSE_LIFE, 0.12, 0.12),
GUI:CallFunc(function() SafeRemove(node) end)
))
return node
end
骨架的三处立规。_burning 布尔加 _fuseT 倒计时成对出现——点火期的一切判定先查布尔再查余时,两个都查的版本永远不会在点火中途再点一次火。预警圈的收缩用动作序列的 ActionScaleTo 直接从一缩到零点一二——圈收拢的速度就是倒计时,玩家读圈比读数字快。BLAZE_RATE 用三不用二:二倍的杠杆配十五秒冷却,机制会沦为常规输出;三倍加"剩一口"的代价,它才是一场仗只有一发的那声雷。
四、核心代码:完整模块(下·定时器与血雷换算)
--------------------------------------------------------------------------------
-- 点火与清算
--------------------------------------------------------------------------------
local function Blaze_Ignite(warnBag)
_burning = true
_fuseT = CONST.FUSE_LIFE
warnBag[#warnBag + 1] = CreateWarnRing()
ShowTip("点了——一秒后炸,半屏都是火")
end
local function Blaze_Detonate(targetID)
local myID = SL:GetValue("USER_ID")
local hp = SL:GetValue("ACTOR_HP", myID)
local spent = (hp or 0) - CONST.LEFT_HP
if spent <= 0 then
_burning = false
return
end
SL:SetHp(myID, CONST.LEFT_HP)
local vd = math.round(spent * CONST.BLAZE_RATE)
local mp = GetMyPos()
local tp = GetActorPos(targetID)
if tp and mp and math.abs(tp.x - mp.x) <= CONST.BLAZE_RADIUS then
SL:ActorHurt(targetID, vd)
SL:TipAbove(targetID, "-" .. vd)
end
SL:PlayBlazeBurst(mp.x, mp.y)
SL:ScreenShake(7, 0.42)
SL:EnterWeakState(myID, CONST.BLAZE_CD)
ShowTip("炸了" .. vd .. "——你现在比它先脆,撤着打")
_burning = false
end
--------------------------------------------------------------------------------
-- 公共接口
--------------------------------------------------------------------------------
function LastBlaze.Cast(targetID, warnBag)
if _cdLeft > 0 or _burning then return end
local hp = SL:GetValue("ACTOR_HP", SL:GetValue("USER_ID"))
if not hp or hp <= 30 then
ShowTip("血不够烧——留着这口喘气")
return
end
Blaze_Ignite(warnBag)
SL:ScheduleOnce(function()
Blaze_Detonate(targetID)
end, CONST.FUSE_LIFE)
end
--------------------------------------------------------------------------------
-- 定时器与调试
--------------------------------------------------------------------------------
if not _scheduler then
_scheduler = SL:Schedule(function(dt)
_cdLeft = math.max(0, _cdLeft - dt)
end, 0.02)
end
SL:RegisterLUAEvent(LUA_EVENT_ACTOR_DEAD, "LBZ_Dead", function(data)
if data and data.id == SL:GetValue("USER_ID") and _burning then
_burning = false
end
end)
SL:ScheduleOnce(function()
ShowTip("技能已加载: 同归爆 (调试按钮触发)")
end, 1.0)
return LastBlaze
下半场的清算链是全模块的雷管:Blaze_Detonate 的顺序是读血、烧血、算雷、落雷、进虚脱——五步一步都不能换,先落雷后烧血的版本玩家能炸出不属于自己的血。点火的延时清算挂 ScheduleOnce 一条延时任务,点火一秒到点即炸——把清算写在模块定时器的分支里也可以,但延时任务让"点火"和"炸"在代码上隔着一整段,想改引信只动一处。死亡钩子把燃烧旗标按灭——点火期被怪的刀先撂倒,雷就不响了,人死账清。
五、调参指南与商业服怎么用
调参的雷管在三处。乘三是杠杆的甜区:烧三百炸九百,一发顶三十秒普攻——杠杆拉到四倍以上,玩家会刻意养血不点,机制变成挂在墙上的装饰;两倍以下,没人值得为它烧到剩一。点火一秒是勇气的成本:瞬发的同归是逃生技的反面教材,两秒的点火又长到怪必然打断——一秒卡在"反应得过来、犹豫来不及"的窄缝里。剩一口的虚脱态要配一条退出通道——药水、治疗、脱战回血都行,没有退出通道的虚脱态就是判死刑。常见坑三个:点火期玩家死亡,雷按原计划炸出,死人放雷的账面成了笑话;虚脱态没有视觉标注,队友不知道该护着谁;血量刚好剩一的时候点火,零差额的雷空响一声。点火期的移动封锁也要在演示里演明白——红圈收拢的那一秒里玩家的位移键是灰的,这秒的不能动就是引信的分量。
商业服里同归爆是"热血时刻"的制造商:世界头目战的最后一成血,全场同归爆齐鸣的那一帧就是宣传片的截帧。行会攻城里它是破门队员的勋章——烧光自己炸开城门,战报里这行永远加粗。变体做成血雷品级:下品乘二点五、上品乘四,血雷的定价就是玩命的价格。这一篇的演示和整套模块照抄能跑,要改的就是 CONST 那一张表。
写完留一句给做爆发系的同学:同归卖的是"最后一发"的分量——血雷的换算写在明处,玩家点火的每一根手指才有底气。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
【游戏功能】 if _shadowT 0 then spd = noShadow and 12 or 24 end ——一行…
【游戏功能】 魂卫的全机制就一句:杀掉小怪化一盏魂火跟着你走,每盏魂火两秒自动劈最近的大怪一口八点,至多三盏——「引魂!」按…
【游戏功能】 一道咒飞过来,硬吃是四秒里一秒十的钝疼——有没有第三条路?纸人替灾给的就是第三条路:贴一个纸人在身后,八秒里头…
【游戏功能】 挨打还能赚钱?水镜式的答案是:挨的刀七成存进镜里不扣血、三成照常疼,六秒后点「还镜」,存量乘一点五放成水炮——…
【游戏功能】 if _mirrorT 0 then SL:TipAboveMe("免疫") return end ——一道写…
【游戏功能】 远近战的矛盾怎么解?远战的答案是把怪挡在射程外,近战的答案是把人拖进射程内——缩地阵给的第三个答案最蛮横:圈只…