【游戏功能】
先看这行代码,狼怪的自回血就这一句:
hp = math.min(hpMax, hp + regen * dt)
逐段拆:regen * dt 是这一帧该回的血量,帧率无关;hp + 是无脑往上加;math.min(hpMax, …) 是封顶。要削弱一只回血怪,改动点全在这行里——把 regen 减半是笨办法,高明的做法是让这行整体短路:重伤 buff 存在的时候,hp + regen * dt 压根不执行。这就是断血痕的全部原理。
一、回血、断血、愈合三段拉锯
狼怪自带每秒 6 点回血,画面上是绿的:细小的绿点从它身上一粒粒飘起来,头顶血条以肉眼可见的速度往回爬,血条上方常驻一行小字"回血 +6/秒"。回血必须可视——玩家得先看见"它在回血",才会想要"有东西能拦住它"。断血斩就是那个拦住的东西:一刀砍进狼怪胸口,八点伤害是次要的,主要的是留下一道深红的断血痕,绿色回血瞬间中断,飘起来的绿点换成往下滴的红点,血条上方"回血 +6/秒"变成"断血 4.2s"的倒计时,旁边一枚被红线划掉的绿色生命符。五秒一到,断血痕愈合,绿点重新飘起来,回血恢复。三段的拉锯感就出来了:回血在爬,断血在压,玩家永远在算"这五秒够不够打掉一段有效血"。
回血绿点的密度是调出来的:每半秒一粒、从狼怪身上随机位置飘起,密度刚好够玩家用余光感知"它在回血",又不至于密集到像在放技能。红滴同理,断血期间的滴血比绿点更慢更沉,下落带一点加速度——回血轻盈、滴血沉重,两种粒子一轻一重,不用任何文字玩家也能读出状态的翻转。倒计时"断血 4.2s"的数字放血条上方而不是怪物头顶,是因为它要和血条一起读:数字在减、血条不涨,两个信息挨着,玩家扫一眼就知道这五秒的意义。血条本身也要配合变色:回血期绿条、断血期浅红,颜色一换,隔半个屏幕都能看出这只狼现在能不能被磨死。
完整演示在这——先看狼怪自己回血,然后点「断血斩!」给它开一道痕:
fx-noregen
二、幂尔框架实现:buff 优先于回血
幂尔框架里回血在公共 Tick 里跑,重伤做成高优先级 buff,回血逻辑进门先查 buff:
local NoRegen = {}
local REGEN, GRIEVOUS = 6, 5
function NoRegen.Apply(target)
SL:PlayActorAct("player", "attack")
SL:ScheduleOnce(function()
SL:Damage(target, 8)
SL:AddBuff(target, "grievous_wound", GRIEVOUS) -- 断血痕: 5s
SL:PlayBurst(target, "wound_spark", 10)
SL:ShowTipAbove(target, "断血! 回血中断")
SL:Stagger(target, 0.3)
end, 0.22)
end
local function onTick(dt)
for _, m in ipairs(SL:GetMonsters()) do
if not SL:HasBuff(m, "grievous_wound") then
local hp, hpMax = SL:GetHP(m)
if hp < hpMax then
SL:Heal(m, REGEN * dt) -- 无痕: 正常回血
SL:SpawnHealMote(m, "green_plus") -- 绿点: 回血可视
end
else
SL:SpawnHealMote(m, "red_drip") -- 有痕: 换滴血
SL:ShowHealBlockedMark(m) -- 划掉的生命符
end
end
end
SL:RegTick("noregen_tick", onTick)
SL:RegClick("cut", NoRegen.Apply)
return NoRegen
顺序是命门:HasBuff 的判断必须在 Heal 之前,重伤本质上就是往回血的必经之路上放一道闸。要是写成"先回血、buff 里再扣回来",每秒会出现血量数字先涨后跌的抖动,飘字来回跳,玩家看着头晕还以为出了 bug。
这段 Tick 是框架里典型的"公共循环加对象遍历"写法:SL:GetMonsters 拿全场怪,一只只判 buff、算回血、撒粒子。粒子调用 SL:SpawnHealMote 每帧都可能发,节奏要靠外层计时器压着——半秒一粒不是粒子系统自己会数数。SL:Heal 传的是 REGEN * dt 而不是半秒 3 点,是为了和帧率解耦:30 帧和 60 帧的机器跑出来的回血速率一模一样,飘绿点的密度才有差别——速率走 dt,节奏走计时器,两套时间各管各的。
三、断血的数值就是时间乘速率
重伤不加伤害,它砍的是对方的有效血量:断血 5 秒乘回血 6 点,一口气温吞掉 30 点潜在回复——这个"5×6"就是重伤技能的全部数值,改任何一个数,强度都按乘法变。所以断血该给谁用也有讲究:打回血怪是刚需,五秒内不打穿一段血就白断;打脆皮是浪费,人家本来就不回血。断血痕的重复命中要刷新时长而不是叠加层数——伤口就一道,撒盐是重新计时,这条纪律让玩家不需要学新的叠层规则。最后回到开头那行代码:所有回血类怪物的强度,本质上都是这一行的参数在起作用;断血痕只是在它前面加了一个 if。最省钱的设计往往是这种——不新造系统,只往既有系统的必经之路上放一道闸,再给这道闸配一个足够扎眼的视觉记号。
重伤在组队语境下还有另一半身份:切治疗。对方奶妈拼命抬血,输出打上去像往漏桶里倒水,这时候一枚重伤上给奶妈,她的治疗量直接打折——这是断血痕和回血怪同一套原理在 PvP 语境的复用。实现上要留意两套判断的口径:打怪的断血痕判的是"怪物自回血",打人的重伤判的是"玩家受到的治疗",两个入口共用同一个 buff id,但结算走的字段不同,日志里要分开埋点,不然客服接到"我断血了怎么他还回血"的工单要查一上午——埋点分开了,这类工单一眼就能归因到口径差异上。断血痕被驱散也是要处理的边界:狼怪身上的痕被净化掉,回血立刻恢复、绿点重新飘起,驱散的反馈和断血的反馈用同一套粒子反着放一遍——有来有回,双方玩家的情绪才平衡。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
【游戏功能】 控制技能的镜像问题是:锁住了怪,自己是不是也闲着?影锁把这道两难摆上台面:影锁四秒,它动不了、你也动不了——它…
【游戏功能】 打断为什么只有"清读条"一种?震魂偏要反过来——不清招、不断势,打在它读条半途的那一劲顺着招震进腑——中劲十秒…
【游戏功能】 蜂群为什么总是一只一只出?蜂王偏要让它们进化:放一只蜂王出来,杀掉小怪喂它——喂三只升一阶,三阶蜂王的毒刺一秒…
【游戏功能】 技能为什么总是不扣自己的血?血刃偏要反着来:开着血刃的每一刀先扣自己二血、命中回三血——净赚一但要打得中,空刀…
【游戏功能】 bn.t = bn.t - dt ——一行旗面倒计时的代码,撑起了破军旗全部的紧迫感:旗立三秒、圈内加攻三成,…
【游戏功能】 淬毒为什么要一毒到底?淬毒刃偏要一层一层叠:一刀淬一层毒、毒层一秒六地烂,六层封顶之后一刀下去毒伤三十六——叠…