【游戏功能】
不屈志的全机制就一句:被打到该死的那个瞬间,志气发作——血剩一口、三秒免伤、刀速翻倍,一场仗只发作一次——这是玩家和死亡之间签的第一份合同。它是玩家和死亡之间的一纸合同:死亡可以来,但第一次得空手而归。这篇的核心代码照引擎技能脚本的全规格写:配置表、金环构件、触发钩子、定时器、调试按钮,一根骨头不少,从头到尾一个模块讲透。
一、效果演示:一口血,三口气
演示场里玩家血条旁挂着一颗金色的"志气未发"小条。大怪的刀一刀二十六、每六秒一记五十的大抡——血线一路往下走,跌到该死的那个瞬间,金环当场炸开:血钉在一、头顶蹦出十七号大字的"不屈!"、周身金色光环转起来;三秒里所有落刀只蹦"免疫",你的普攻从一秒一口提速到一口十五,把刚才挨的刀一口口讨回去。三秒一过金光散掉,"志气已尽"四个灰字挂上——这一场,命只有一条底牌。演示里故意让大怪的第二记五十落地在志气已尽之后,同样的刀,这次是真的疼。
fx-undying
二、底层原理:一个死亡拦截钩子加一份一次性旗标
模块的全部机关是一对搭档。触发钩子挂在玩家的扣血入口上:每一次伤害先做死亡预演——血量减去这一刀会不会归零——会,且志气旗标还立着,就把这一刀改判成"剩一口",旗标倒下、三秒免伤层和攻速层同时挂上。旗标是一次性的:发作过就永远立不起来,这一场仗的合同已经兑现。免伤层写在扣血入口的判链最前端,志气期的每一刀在预演之前就被拦下蹦"免疫"——拦截、改判、免伤三层逻辑共用一个入口,是这套机制账目永远平的原因。
三、核心代码:完整模块(上·骨架)
--------------------------------------------------------------------------------
-- @file Undying.lua
-- @brief 不屈志 —— 致命一刀剩一口,三秒金身讨回来
-- 客户端表现模块:配置表 / 金环构件 / 死亡拦截 / 定时器
--------------------------------------------------------------------------------
local Undying = {}
--------------------------------------------------------------------------------
-- 配置与常量
--------------------------------------------------------------------------------
local CONST = {
GLOW_LIFE = 3.0, -- 志气三秒
GLOW_AMP = 2.0, -- 志气期刀速乘二
IMMUNE_TEXT = "免疫",
LEFT_HP = 1, -- 剩一口血
-- 颜色
COLOR_WILL = "#ffd866", -- 意志金
COLOR_DEEP = "#7a5a12", -- 深金
COLOR_GHOST = "#fff3c4", -- 残光
ZORDER_GROUND = 118,
ZORDER_RING = 134,
ZORDER_EFFECT = 135,
AUTOINC_BASE = 926000,
}
--------------------------------------------------------------------------------
-- 模块内部状态
--------------------------------------------------------------------------------
local _will = true -- 志气旗标:一场仗只发作一次
local _glowT = 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 "UDY", 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 CreateWillRing()
local mp = GetMyPos()
if not mp then return end
local node = GUI:Layout_Create(GUI:Attach_SceneF(), GenID("Ring"),
mp.x, mp.y - 46, 0, 0, false)
GUI:setLocalZOrder(node, CONST.ZORDER_RING)
for i = 1, 28 do
local a1 = (i - 1) / 28 * 6.28
local a2 = i / 28 * 6.28
GUI:DrawLine_Create(node, string.format("g_%d", i), 0, 0, 3,
m_cos(a1) * 30, m_sin(a1) * 56, m_cos(a2) * 30, m_sin(a2) * 56,
CONST.COLOR_WILL, 210)
end
GUI:runAction(node, GUI:ActionSequence(
GUI:ActionFadeIn(0.10),
GUI:DelayTime(2.4),
GUI:ActionFadeOut(0.5),
GUI:CallFunc(function() SafeRemove(node) end)
))
return node
end
骨架先立两块基石。_will 是布尔旗标不是计数器——一场一次的机制用计数器写,迟早有人把它改成"两次",机制的尊严就在"只此一次"。金环构件的椭圆用纵轴五十六横轴三十的比例画——贴着人形的高宽比画环,环才是长在人身上的,正圆的环是结界不是志气。
四、核心代码:完整模块(下·定时器与死亡拦截)
--------------------------------------------------------------------------------
-- 死亡拦截:扣血入口的第一道关
--------------------------------------------------------------------------------
local function OnPlayerHurt(raw)
if _glowT > 0 then
SL:TipAboveMe(CONST.IMMUNE_TEXT)
return
end
local hp = SL:GetValue("ACTOR_HP", SL:GetValue("USER_ID"))
if _will and hp and hp - raw <= 0 then
_will = false
_glowT = CONST.GLOW_LIFE
SL:SetHp(SL:GetValue("USER_ID"), CONST.LEFT_HP)
SL:SetAttackSpeedAmp(CONST.GLOW_AMP)
CreateWillRing()
SL:TipAboveMe("不屈!")
SL:ScreenShake(5, 0.30)
return
end
SL:PlayerHurt(raw)
end
--------------------------------------------------------------------------------
-- 攻速层的挂载与卸载
--------------------------------------------------------------------------------
local function Glow_Update(dt)
if _glowT <= 0 then return end
_glowT = _glowT - dt
if _glowT <= 0 then
SL:SetAttackSpeedAmp(1.0)
ShowTip("志气散了——接下来的刀要自己挡")
end
end
--------------------------------------------------------------------------------
-- 定时器与调试
--------------------------------------------------------------------------------
if not _scheduler then
_scheduler = SL:Schedule(function(dt)
Glow_Update(dt)
end, 0.02)
end
SL:RegisterLUAEvent(LUA_EVENT_LOCAL_HURT, "UDY_Hurt", function(data)
if data and data.raw then
OnPlayerHurt(data.raw)
end
end)
SL:RegisterLUAEvent(LUA_EVENT_SCENE_CLEAR, "UDY_Clear", function()
_will = true
_glowT = 0
SL:SetAttackSpeedAmp(1.0)
end)
SL:ScheduleOnce(function()
ShowTip("技能已加载: 不屈志 (调试按钮触发)")
end, 1.0)
return Undying
下半场的题眼是 OnPlayerHurt 这道三段闸门:免伤判志气期、改判看旗标、落账走原路——三段的顺序不能动,免伤写在最前,志气期的刀永远进不了死亡预演。改判分支里 SetHp 和攻速层同帧挂上,发作的每一件事都在同一帧完成——分帧的版本会出现"剩了一口血但刀还是慢的"半残状态。金环构件挂的是动作序列的自毁——构件自己管自己的寿命,志气散了环自然淡出,清零逻辑不用追着视觉跑。场景清空钩子把旗标复原成真:新的一场仗,合同重新签,这是"一场一次"能被玩家信任的前提。免伤小字的弹出频率也要管——志气期的连续快刀会连珠炮似的刷"免疫",刷屏的免疫比没有免疫更吵。
五、调参指南与商业服怎么用
调参先看三秒的结构。免伤两秒加攻速一秒是另一条路——前两秒纯粹喘息,最后一秒提速讨刀,两种节奏给两种职业;免伤三秒全免的版本最直白,适合给新手。攻速乘二对三秒是"讨回三十点"的窗口,讨回量要贴着发作前挨掉的血量设计——讨得回,玩家觉得志气有灵;讨不回,它就只是一条多出来的血。旗标的重置时机必须挂场景清空,挂在死亡复活上的版本,复活立刻又能骗死一次,机制变成一次性复活币。常见坑三个:真死亡(坠落、即死)绕过扣血入口直接触发,志气拦不住;攻速层没卸,志气散了刀还是快的;发作瞬间扣血入口被连击二次调用,免伤层没挂上就扣成了负血。
商业服里不屈志是"最后一张牌"的付费点:志气的发作特效做成品级——铜志气白光、金志气红光,死亡边缘那一眼是全游戏曝光率最高的广告位。副本里它是灭团统计的改写者:会留志气的队和不会留的队,灭团率差一半,攻略帖的标题都替你想好了。变体做成志气传承:志气发作时倒下的队友站起来一半——把个人保命做成团队翻盘,机制的地位再上一档。还有一档是志气可见化:队友头顶的志气条对全队公开,救谁让谁、一目了然,团队决策多了一层参考。这一篇的演示和整套模块照抄能跑,改的就是 CONST 那张表。
写完留一句给做保命系的同学:一次性机制卖的是"合同精神"——发作那一刻所有的账当帧结清,玩家的下一次冲锋才敢押上这条命。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
【游戏功能】 安全巡检扫出一笔可疑的挂账:玩家的"周围单位结算"列表里,同一只怪每零点八秒出现一次,可战斗记录里玩家根本没出…
【游戏功能】 困灵阵的全机制就一句:阵落在它脚下,八秒里它就是圈中之物——敢跨出圈沿,一步吃十五还被弹回去,你在圈外安安稳稳…
【游戏功能】 先泼油还是先点火?这道题答错的代价是一地白烧的火——灯点在空地上,怪还没踩上来,四秒的火一点没沾着它的毛。火油…
【游戏功能】 寻路组收到一笔诡异的工单:怪物巡逻到某个坐标段必卡三秒,像踩了看不见的门槛——排查两小时,发现那段路上有一个上…
【游戏功能】 local a, b = math.min(x1, x2), math.max(x1, x2) ——一行把两根…
【游戏功能】 测试组报过一口邪门的单:头目的读条明明被打断过,技能照样出了膛——查了半天不是打断失效,是打断只"清了"不"冻…