CHUAN2 DEV ENGINE
996 正版授权研发中心 · 360 授权合作教学中心 · 抖音传奇直播合作授权 · 快手推广运营商授权
OFFICIAL LICENSED ACADEMY 查验官方授权证书 →
// 威海旷世互娱教学基地 · 技术文章
进阶实战游戏功能996引擎

金身咒:两秒刀枪不入,但手脚也钉死

2026-10-01 04:37 作者:996 技术组 996引擎Lua教程传奇脚本进阶实战游戏功能996引擎

【游戏功能】

if _goldT > 0 then return end——一行免伤闸门的写法,撑起了金身咒全部的取舍:金身亮起的两秒里,箭雨、重锤、毒火全部弹开,可你自己的刀也一并被钉在鞘里——买命的钱是输出窗口,两秒的账一笔不差。这篇的核心代码照引擎技能脚本的全规格写:配置表、佛光构件、免伤闸门、定时器、调试按钮。

一、效果演示:两秒佛光,三箭弹开

演示场里大怪每四秒张一轮箭雨:三支箭错着拍子飞来,一箭二十,不躲就是六十的账。点「金身!」:玩家的周身腾起一层金光蛋壳,头顶挂出"金身 两秒"——第一支箭撞在蛋壳上只蹦出"免疫"两个字,第二支、第三支一样;同一时间你的攻击键是灰的,两秒里一刀不出。演示里让箭雨撞一次金身、再走位躲一次箭雨,两种躲法的账摆在一起:走位不花钱但可能躲不干净,金身万无一失但要还两秒的输出债。

demo
 fx-goldbody

二、底层原理:一道免伤闸门加一份冻结代价

模块的机关是一对互锁的账,锁芯就是 _goldT 这一个字段。免伤侧:金身期是扣血入口最前面的一道闸,闸开着,一切伤害在预演之前就被弹回,连毒这样的持续账也进不来——金身免的是"所有",留一个后门的金身会被玩家找出万能解。代价侧:金身期攻击循环被冻结——不是减速是冻结,普攻计时器整个停摆、技能入口直接拦下——金身的两秒是纯支出,玩家花这两秒买的是下一轮箭雨的零账——买命的账要两页对读:这页是支出,下页是省下的血。两侧的互锁写在同一个开关上:_goldT 大于零就是免伤加冻结的同一个状态,不存在"能打的金身",那叫护盾,是另一种商品。

三、核心代码:完整模块(上·骨架)

lua
--------------------------------------------------------------------------------
-- @file        GoldBody.lua
-- @brief       金身咒 —— 两秒刀枪不入,但手脚也钉死
--              客户端表现模块:配置表 / 佛光构件 / 免伤冻结 / 定时器
--------------------------------------------------------------------------------

local GoldBody = {}

--------------------------------------------------------------------------------
-- 配置与常量
--------------------------------------------------------------------------------
local CONST = {
    GOLD_LIFE     = 2.0,        -- 金身两秒
    GOLD_CD       = 9.0,        -- 冷却九秒
    FREEZE_ATK    = true,       -- 金身期冻结攻击

    -- 颜色
    COLOR_GOLD    = "#e3b341",  -- 身金
    COLOR_DEEP    = "#7a5a12",  -- 佛金
    COLOR_LIGHT   = "#fff8e1",  -- 光白

    ZORDER_GROUND = 118,
    ZORDER_SHELL  = 134,
    ZORDER_EFFECT = 135,

    AUTOINC_BASE  = 928000,
}

--------------------------------------------------------------------------------
-- 模块内部状态
--------------------------------------------------------------------------------
local _goldT     = 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 "GBD", 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 CreateShellNode()
    local mp = GetMyPos()
    if not mp then return end
    local node = GUI:Layout_Create(GUI:Attach_SceneF(), GenID("Shell"),
        mp.x, mp.y - 48, 0, 0, false)
    GUI:setLocalZOrder(node, CONST.ZORDER_SHELL)
    for i = 1, 30 do
        local a1 = (i - 1) / 30 * 6.28
        local a2 = i / 30 * 6.28
        GUI:DrawLine_Create(node, string.format("in_%d", i), 0, 0, 2,
            m_cos(a1) * 30, m_sin(a1) * 58, m_cos(a2) * 30, m_sin(a2) * 58,
            CONST.COLOR_LIGHT, 190)
    end
    for i = 1, 20 do
        local a1 = (i - 1) / 20 * 6.28
        local a2 = i / 20 * 6.28
        GUI:DrawLine_Create(node, string.format("out_%d", i), 0, 0, 3,
            m_cos(a1) * 34, m_sin(a1) * 64, m_cos(a2) * 34, m_sin(a2) * 64,
            CONST.COLOR_GOLD, 150)
    end
    return node
end

骨架的定调在两层壳的画法:内层亮线是蛋壳的主体,外层淡线是金光的辉——两层错半圈的椭圆叠出来的才是"佛光",单层椭圆像玻璃罩。免伤的闸门写在扣血入口的最前面,这个位置是金身的生命线——写进扣血函数内部的版本,遇上有穿透词条的刀就得一处一处补丁。FREEZE_ATK 做成常量开关而不是写死——策划哪天要给金身开攻击的口子,改开关不改结构,这是配置表存在的意义。

四、核心代码:完整模块(下·定时器与免伤冻结)

lua
--------------------------------------------------------------------------------
-- 金身开关
--------------------------------------------------------------------------------
local function Gold_Open(shellBag)
    _goldT = CONST.GOLD_LIFE
    _cdLeft = CONST.GOLD_CD
    shellBag[#shellBag + 1] = CreateShellNode()
    SL:TipAboveMe("金身!")
    SL:ScreenShake(2.5, 0.18)
end

--------------------------------------------------------------------------------
-- 免伤闸门:扣血入口最前的一道关
--------------------------------------------------------------------------------
local function OnPlayerHurt(raw)
    if _goldT > 0 then
        SL:TipAboveMe("免疫")
        return
    end
    SL:PlayerHurt(raw)
end

--------------------------------------------------------------------------------
-- 攻击冻结:攻击入口的对称闸门
--------------------------------------------------------------------------------
local function Attack_Gate()
    if CONST.FREEZE_ATK and _goldT > 0 then
        return false
    end
    return true
end

function GoldBody.CanAttack()
    return Attack_Gate()
end

function GoldBody.Cast(shellBag)
    if _cdLeft > 0 or _goldT > 0 then return end
    Gold_Open(shellBag)
end

--------------------------------------------------------------------------------
-- 定时器与调试
--------------------------------------------------------------------------------
if not _scheduler then
    _scheduler = SL:Schedule(function(dt)
        _cdLeft = math.max(0, _cdLeft - dt)
        if _goldT > 0 then
            _goldT = _goldT - dt
            if _goldT <= 0 then
                ShowTip("金身散了——这两秒的输出账要补回来")
            end
        end
    end, 0.02)
end

SL:RegisterLUAEvent(LUA_EVENT_LOCAL_HURT, "GBD_Hurt", function(data)
    if data and data.raw then
        OnPlayerHurt(data.raw)
    end
end)

SL:ScheduleOnce(function()
    ShowTip("技能已加载: 金身咒 (调试按钮触发)")
end, 1.0)

return GoldBody

下半场的对称结构是全模块的课:扣血入口有一道免伤闸,攻击入口有一道冻结闸,两道闸由同一个 _goldT 拉动——玩家的账两头同时停,谁也不欠谁。免伤写在 OnPlayerHurt 的最前面,连日志都不留地弹回;冻结的 CanAttack 做成查询接口,技能系统每帧来问一句"能打吗",比在三个技能里各写一遍金身判断干净十倍。金身到期的提示要落在散光的那一帧,晚一拍,玩家会再等一个不存在的免疫。

五、调参指南与商业服怎么用

调参三笔账。金身两秒对箭雨三箭的节奏是"一轮全免"的配置——箭雨密到四箭五箭,金身就要往三秒抬,全免变半免的手感立刻碎。冷却九秒对箭雨四秒是两轮一开——每轮都开金身的玩法会退化成站桩挨打流,空出一轮逼玩家在金身和走位之间做选择。冻结攻击是代价的骨线:这一条拿掉,金身从保命技变成无敌输出窗,全职业的平衡跟着塌。常见坑三个:持续伤害每帧扣血,金身期每帧弹"免疫",免疫的小字糊了半屏——持续类账要走静默弹回;金身期的位移没有被冻住,玩家顶着蛋壳走位,"钉死"名不副实;冷却从开启起算,金身两秒加九秒冷却实际十一秒一轮,界面却按九秒转。金身期的受击要留一层弹开的白光反馈——静默免疫像断线,弹光的免疫才像壳在替你挨。

商业服里金身咒是"反应速度"的商品化:金身的触发做成手动键就是操作流的尊严,做成自动挡就是月卡的卖点——同一道闸,两种卖法。副本里它是救场技的教科书:全队残血那一轮箭雨,一个金身换三秒的奶量窗口,指挥的麦克风里永远有它。变体做成金身共享:一人开金身全队免半秒,个人技长成团队技,行会战的价码翻着翻地涨。金身的判定顺序也要在文档里写死——免伤闸门排在减伤链之前还是之后,决定了它和石肤、修盾叠用时的结算先后,文档不写清,玩家与客服的战争就没完。这一篇的演示和整套模块照抄能跑,改的就是 CONST 那张表。

写完留一句给做免伤系的同学:金身卖的是"停下来的勇气"——两秒里你什么都做不了,所以这两秒免的一切都理直气壮。

作者履历与出处

本文由 996 技术组基于 996 引擎官方知识库与浮生梦老师课程体系整理。团队长期从事传奇类引擎 Lua 后端逻辑、客户端界面与商业版本交付,内容以官方知识库与真实项目为出处,按版本持续修订。

← 返回文章地图返回研学路径

幂尔框架 · 实战干货 · 接口调用

LATEST ARTICLES

全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →

进阶实战游戏功能

偷影:偷走它的影子,没了影子的怪刀都虚

【游戏功能】 if _shadowT 0 then spd = noShadow and 12 or 24 end ——一行…

2026-10-01 06:03 996 技术组
进阶实战游戏功能

魂卫:杀一葬一,魂火替你出手

【游戏功能】 魂卫的全机制就一句:杀掉小怪化一盏魂火跟着你走,每盏魂火两秒自动劈最近的大怪一口八点,至多三盏——「引魂!」按…

2026-10-01 06:03 996 技术组
进阶实战游戏功能

纸人替灾:贴一个纸人,下一道咒它替你挨

【游戏功能】 一道咒飞过来,硬吃是四秒里一秒十的钝疼——有没有第三条路?纸人替灾给的就是第三条路:贴一个纸人在身后,八秒里头…

2026-10-01 06:03 996 技术组
进阶实战游戏功能

水镜式:挨的刀存进镜里,连本带利还回去

【游戏功能】 挨打还能赚钱?水镜式的答案是:挨的刀七成存进镜里不扣血、三成照常疼,六秒后点「还镜」,存量乘一点五放成水炮——…

2026-10-01 06:03 996 技术组
进阶实战游戏功能

弹反镜:架起一面镜,箭从哪来回哪去

【游戏功能】 if _mirrorT 0 then SL:TipAboveMe("免疫") return end ——一道写…

2026-10-01 06:03 996 技术组
进阶实战游戏功能

缩地阵:圈越缩越小,逼它和你贴身

【游戏功能】 远近战的矛盾怎么解?远战的答案是把怪挡在射程外,近战的答案是把人拖进射程内——缩地阵给的第三个答案最蛮横:圈只…

2026-10-01 06:03 996 技术组