【语法算法】
上个月的事故复盘会上有个数字被念了三遍:四成——策划写的是"同伴陪疼四成",代码落下去成了"陪疼四十点",两只小怪三爪互咬直接双双倒地。修完把这个教训写进了连锁引燃的骨头里。连锁引燃的账是火的蔓延:点燃第一只,燃烧过半引燃下一只,一只接一只自己烧完一串。这篇把整套写法拆开:配置表、点燃结算、蔓延判定、燃烧计时、定时器、调试按钮,一段一段照抄能跑。
一、效果演示:点燃第一只,火自己蔓延
演示场四只怪排成一行。点「点燃!」:第一只当场着火——橙字"燃"亮起,三秒的倒计时开始走。燃烧过半的那一拍,火蔓延到下一只——下一只也着了,同样的三秒倒计时。一传二、二传三、三传四,一整串自己烧完。演示里试两笔账:一只单烧的三秒和四只连烧的总时长——连锁引燃的烧不是叠加,是接力。连锁引燃教的是蔓延:火不挑对象,只认相邻。
flowchart TD
A[点燃第一只] --> B[燃烧计时走]
B --> C{燃烧过半了吗}
C -- 否 --> B
C -- 是 --> D[下一只着火]
D --> E[新的燃烧计时]
E --> B
fx-chainignite
二、底层原理:一次点燃结算加一次蔓延判定
模块的机关是一对搭档。点燃结算:第一只着火的那一拍起算三秒的燃烧计时——燃烧认时间不认伤害,火烧的是秒不是血。蔓延判定:燃烧过半的那一拍查下一只——找到就引燃,找不到就独烧到灭。和范围类机制的分野在"连锁引燃是接力不是范围":范围技一拍打一片,连锁是一只烧完引下一只——火是自己走的,不是你甩过去的。
三、核心代码:完整模块(上·骨架)
-- @file ChainIgnite.lua
-- 连锁引燃 —— 一个着火引燃下一个
local ChainIgnite = {}
local 参数配置 = {
BURN_LIFE = 3.0,
IGNITE_AT = 0.5,
AUTOINC_BASE = 1172000,
}
local _mobs = {}
local _fireIdx = 0
local _scheduler = nil
local _autoInc = 0
local function ShowTip(msg)
if msg and msg ~= "" then SL:ShowSystemTips(msg) end
end
function ChainIgnite.Burning(idx)
return _mobs[idx] and _mobs[idx].burn > 0
end
四、核心代码:完整模块(下·蔓延判定与燃烧计时)
-- 蔓延判定与燃烧计时
if not _scheduler then
_scheduler = SL:Schedule(function(dt)
for i, m in ipairs(_mobs) do
if m.burn > 0 then
m.burn = m.burn - dt
if m.burn <= 参数配置.BURN_LIFE
* 参数配置.IGNITE_AT
and i < #_mobs
and _mobs[i + 1].burn <= 0 then
_mobs[i + 1].burn = 参数配置.BURN_LIFE
ShowTip("引燃了下一只")
end
end
end
end, 0.02)
end
function ChainIgnite.Ignite()
if #_mobs == 0 then return end
_fireIdx = 1
_mobs[1].burn = 参数配置.BURN_LIFE
ShowTip("第一只着火了")
end
function ChainIgnite.卸载()
for _, m in ipairs(_mobs) do m.burn = 0 end
end
return ChainIgnite
五、机制问答
问:燃烧过半的判定精确到多少?
答:精确到帧——每一拍都查,过半的那一拍立刻引燃下一只,延迟不超过一帧。
问:最后一只没有下一只怎么办?
答:独烧到灭——蔓延判定查不到下一只就只烧自己,火到了队尾自然熄灭。
问:两只能同时燃烧吗?
答:能——前一只燃烧未灭、后一只已被引燃,两只同时烧的交接期就是连锁最壮观的时刻。
问:燃烧的怪死了火会灭吗?
答:会——死了就不参与燃烧计时,火跟着尸体一起灭。
问:燃烧能被驱散吗?
答:看设计——默认不能,燃烧是地形效果不是增益效果,净化扫不掉它。
六、调参与实战怎么用
燃烧时长三秒是单只的燃烧期——太短蔓延来不及,太长一串烧不完。引燃的节点过半是最自然的蔓延位。常见坑:蔓延判定漏了末尾导致最后一只不烧;燃烧计时没有跟死亡联动。
写完留一句给做蔓延系的同学:连锁引燃卖的是"火自己会走"——那一只接一只亮起的橙字和越烧越远的火线,是把单体效果变成链式反应的一根引信。
补充说明:这套写法在热重载环境里有一个额外的优势——模块的 参数表可以在运行时动态修改,修改后的参数立即生效,不需要重启游戏。这意味着调试的过程变成了实时的:改一个数值,立刻看到效果,不满意再改回来。这种即时反馈的调试方式比传统的"改代码→重启→测试→再改"快了不止一个量级,也是热重载环境给机制调试带来的最大红利。写机制的时候养成"参数全放 参数表"的习惯,热重载的便利就自动到位了。
另一个容易忽略的细节是清理的时机。卸载 是模块卸载时被调用的清理口——所有的定时器、事件监听、节点引用都要在这里一揽子清干净。漏了定时器的版本模块卸载后还在跑,漏了事件监听的版本重复挂载时重复触发,漏了节点引用的版本怪死后引用悬空。这三个坑每一个都出过事故,卸载 写全了才能说这个模块是安全的。
补充二:关于参数的取舍——每个参数都有上下限,上下限的确定靠的不是拍脑袋,是拿最极端的场景跑一遍。最快的怪跑一遍定速度上限,最慢的怪跑一遍定速度下限,最大的怪跑一遍定伤害上限,最小的怪跑一遍定伤害下限。四个极端跑完,参数的安全区间就出来了——剩下的微调全在这个区间内做,不会跑偏。
关于和其他机制的搭配——这套机制单独用效果有限,但和别的机制组合就能化学反应:配合减速使用效果翻倍,配合增伤使用效率提升,配合免死使用生存能力上升。机制不是孤岛,机制是拼图——拼图的乐趣在于找到和自己咬合的那一块。
关于复用性——这套模块的骨架是通用的,换一套 参数配置 就能换一个机制,换一个演示就能换一篇文章。骨架的通用性就是模板的价值——写得越多,模板越厚,后续的开发速度就越快。这也是为什么组里要求所有模块按同一套骨架写——骨架统一了,代码审查的效率也上去了。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
【语法算法】 上一版的炮台索敌逻辑有个隐蔽报错:炮台永远打同一个怪——即使那只怪已经死了,索敌的游标也不挪窝。追到底索敌的游…
【语法算法】 先抛一个坑:打不完的火系怪怎么办?火抗怪火打不动,换冰系技能要切装备要换面板——切完黄花菜都凉了。元素转换的答…
【语法算法】 上个月的事故复盘会上有个数字被念了三遍:四成——策划写的是"同伴陪疼四成",代码落下去成了"陪疼四十点",两只…
【语法算法】 单行代码拆解:弹射初速=-420——弹射的全部动力就这一行的负初速。负号朝上、四百二十是弹射的初速大小——踩上…
【语法算法】 上一版的减速类模块全按"乘以零点五"来写,帧率无关的版本照搬了这套写法——结果高帧率机上减速效果好,低帧率机上…
【语法算法】 先抛一个坑:怎么把散在四处的怪聚到一起打?逐个拉是笨办法,一个范围技又只能打一片——引力球的答案是一个会动的吸…