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

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

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

【游戏功能】

一道咒飞过来,硬吃是四秒里一秒十的钝疼——有没有第三条路?纸人替灾给的就是第三条路:贴一个纸人在身后,八秒里头一道飞来的咒半路拐弯,转嫁到纸人身上,纸人烧掉、咒就断,你毫发无伤。这篇的核心代码照引擎技能脚本的全规格写:配置表、纸人构件、转嫁钩子、定时器、调试按钮。

一、效果演示:一个纸人,一道断掉的咒

演示场里大怪每五秒下一道咒:中咒者一秒十疼四秒,紫雾缠身。点「贴纸人!」:一个纸白的小纸人浮到玩家肩后,头顶挂出"纸人 八秒"——八秒里大怪的第一道咒飞到半途突然拐弯,一头扎进纸人:纸人卷成火团烧成灰,咒的紫光在灰烬里断成几截落地,你身上干干净净。紫光在灰烬里断成几截落地,你身上干干净净——转嫁最讲究的就是"干净"二字,玩家的血条和状态栏都读不到一点咒的痕迹。纸人化灰后咒恢复实价——下一道咒再中就得实打实疼四秒,除非再贴一张。演示里先裸吃一道咒看看钝疼的滋味,再贴纸人看转嫁的利落——第三条路的答案写在两段血条的差值里。

demo
 fx-paperdoll

二、底层原理:一个替身位加一次转嫁结算

模块的机关是一对搭档。替身位:贴纸人的八秒里玩家身后多一个"替灾位"——它不吃伤害只吃异常,而且只吃一道,吃满即化灰。转嫁钩子:怪的咒在命中判定前先查替灾位——纸人在场,咒的目标改写到纸人、纸人执行一次"燃烧出表"、咒的剩余效果整段截断。转嫁和减免的分野是这套机制的性格:减免是伤害打折照常落账,转嫁是账本易主——咒的扣数跳在纸人头上,玩家的血条纹丝不动。纸人的一次性写在化灰里:替完即走,不存在一个纸人替八道咒的常驻护符。

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

lua
--------------------------------------------------------------------------------
-- @file        PaperDoll.lua
-- @brief       纸人替灾 —— 贴一个纸人,下一道咒它替你挨
--              客户端表现模块:配置表 / 纸人构件 / 转嫁钩子 / 定时器
--------------------------------------------------------------------------------

local PaperDoll = {}

--------------------------------------------------------------------------------
-- 配置与常量
--------------------------------------------------------------------------------
local CONST = {
    DOLL_LIFE     = 8.0,        -- 纸人贴八秒
    DOLL_CD       = 6.0,        -- 贴纸冷却
    CURSE_GAP     = 5.0,        -- 咒五秒一道
    CURSE_LIFE    = 4.0,        -- 中咒疼四秒
    CURSE_DPS     = 10,         -- 一秒十疼

    -- 颜色
    COLOR_PAPER   = "#f0e8d8",  -- 纸白
    COLOR_DEEP    = "#7a5a2b",  -- 深褐
    COLOR_CURSE   = "#a371f7",  -- 灾紫

    ZORDER_GROUND = 118,
    ZORDER_DOLL   = 132,
    ZORDER_EFFECT = 135,

    AUTOINC_BASE  = 941000,
}

--------------------------------------------------------------------------------
-- 模块内部状态
--------------------------------------------------------------------------------
local _dollT      = 0              -- 纸人余时
local _cdLeft     = 0
local _curseT     = 0              -- 中咒余时
local _curseTick  = 0              -- 咒的跳秒
local _curseGap   = CONST.CURSE_GAP
local _scheduler  = nil
local _autoInc    = 0

local m_rand = math.random

--------------------------------------------------------------------------------
-- 辅助函数
--------------------------------------------------------------------------------
local function GenID(prefix)
    _autoInc = _autoInc + 1
    return string.format("%s_%d", prefix or "PPD", 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 CreateDollNode()
    local mp = GetMyPos()
    if not mp then return end
    local node = GUI:Layout_Create(GUI:Attach_SceneF(), GenID("Doll"),
        mp.x + 16, mp.y - 62, 0, 0, false)
    GUI:setLocalZOrder(node, CONST.ZORDER_DOLL)
    GUI:DrawLine_Create(node, "head", 0, 0, 5, 0, -8, 0, -8, CONST.COLOR_PAPER, 240)
    GUI:DrawLine_Create(node, "body", 0, 0, 8, 0, -3, 0, 11, CONST.COLOR_PAPER, 240)
    GUI:DrawLine_Create(node, "arm_l", 0, 0, 2, -4, 0, -8, 8, CONST.COLOR_PAPER, 240)
    GUI:DrawLine_Create(node, "arm_r", 0, 0, 2, 4, 0, 8, 8, CONST.COLOR_PAPER, 240)
    return node
end

骨架的两处立规。替灾位是单例——纸人只有一张,第二张的请求在入口拦下,双纸人轮流替灾的玩法从根上不允许。纸人构件用六笔线画一个火柴纸人——纸人的质感来自"简",画得太精细反而像召唤兽,简笔的纸人一眼就是替死的。简笔的纸人一眼就是替死的。纸人的位置挂在玩家肩后偏上——替灾的一瞬紫咒拐弯扎向肩后的画面,是全模块最值钱的一帧。

四、核心代码:完整模块(下·定时器与转嫁钩子)

lua
--------------------------------------------------------------------------------
-- 贴纸人
--------------------------------------------------------------------------------
function PaperDoll.Cast()
    if _cdLeft > 0 or _dollT > 0 then return end
    _cdLeft = CONST.DOLL_CD
    _dollT = CONST.DOLL_LIFE
    CreateDollNode()
    ShowTip("纸人贴上了——八秒里头一道咒它替你挨")
end

--------------------------------------------------------------------------------
-- 转嫁钩子:咒的命中判定前查替灾位
--------------------------------------------------------------------------------
local function OnCurseIncoming()
    if _dollT > 0 then
        _dollT = 0
        SL:PlayDollBurn()
        SL:TipAboveMe("纸人替灾!")
        SL:ScreenShake(2.5, 0.18)
        return true
    end
    return false
end

--------------------------------------------------------------------------------
-- 中咒结算
--------------------------------------------------------------------------------
local function Curse_Apply()
    _curseT = CONST.CURSE_LIFE
    _curseTick = 0
    SL:TipAboveMe("中咒!")
end

--------------------------------------------------------------------------------
-- 定时器:纸人寿、咒的节拍与跳秒
--------------------------------------------------------------------------------
if not _scheduler then
    _scheduler = SL:Schedule(function(dt)
        _cdLeft = math.max(0, _cdLeft - dt)
        if _dollT > 0 then
            _dollT = _dollT - dt
            if _dollT <= 0 then
                ShowTip("纸人自己化灰了——这一场它没白贴")
            end
        end
        if _curseT > 0 then
            _curseT = _curseT - dt
            _curseTick = _curseTick + dt
            if _curseTick >= 1.0 then
                _curseTick = _curseTick - 1.0
                SL:PlayerHurt(CONST.CURSE_DPS)
                if _curseT <= 0 then
                    ShowTip("咒劲散了")
                end
            end
            return
        end
        _curseGap = _curseGap - dt
        if _curseGap <= 0 then
            _curseGap = CONST.CURSE_GAP
            if not OnCurseIncoming() then
                Curse_Apply()
            end
        end
    end, 0.02)
end

SL:RegisterLUAEvent(LUA_EVENT_SCENE_CLEAR, "PPD_Clear", function()
    _dollT, _curseT, _curseGap = 0, 0, CONST.CURSE_GAP
end)

SL:ScheduleOnce(function()
    ShowTip("技能已加载: 纸人替灾 (调试按钮触发)")
end, 1.0)

return PaperDoll

下半场的分流在定时器的咒节拍里:咒到点的第一件事是查替灾位——纸人在,咒的流程整段截断、纸人燃烧出表;纸人不在,才走到 Curse_Apply 的中咒结算。中咒的跳秒独立计时、一秒一跳十点,跳完四秒咒劲自散——咒和中咒后的跳秒写进同一个分支的两段,中间用 return 隔开,中咒期怪再下咒也不叠加,一本咒账一条命。场景清空把纸人、咒、节拍三样全复原,下一场从干净的账本开始。

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

调参三笔账。纸人八秒对咒周期五秒是"必接一道咒"的配置——纸人寿短于咒周期,贴了也白贴;长于两个周期又变成咒咒都替,一次性的性格就散了。咒的一秒十疼四秒是四十点的钝疼——疼到玩家愿意花一个技能位带纸人,又不至于两道咒就致命。贴纸冷却六秒对纸人八秒有两秒重叠——重叠期纸人常驻,冷却改十秒就是纯手艺活。贴纸冷却六秒对纸人八秒有两秒重叠——重叠期纸人常驻,冷却改十秒就是纯手艺活。替灾成功后的那一秒硬直也是节奏的一部分——纸人烧完玩家愣半拍,再拔腿走位,戏剧性全在这半拍里。常见坑三个:纸人替了咒但纸人的化灰特效慢半拍,玩家以为咒还会追过来;中咒期贴纸人,纸人白贴一道已经到账的咒;替灾位和免伤类效果互相冲突的结算顺序没写清。

商业服里纸人替灾是"咒术对抗"的入场券:咒术师职业的强度全靠诅咒压场,纸人一出场,咒术的每道咒都要先过纸人这一关,职业制衡的链子扣上了。商城里纸人外观是变现最快的品类——纸人从素纸到金箔,替灾的那一瞬烧的是玩家的排面。纸人从素纸到金箔,替灾的那一瞬烧的是玩家的排面。转嫁的咒色也可以随纸人品级换——素纸替白咒、朱纸替紫咒,咒的品阶和纸的品阶在半空对上号,对抗的仪式感全在这一眼。变体做成纸人多灾:金箔纸人替两道咒,替一道烧一层——耐咒度和品阶明码标价。这一篇的演示和整套模块照抄能跑,改的就是 CONST 那张表。

写完留一句给做替身系的同学:替灾卖的是"断"字——咒拐弯扎进纸人的那一瞬,玩家的血条学会了事不关己。

作者履历与出处

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

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

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

LATEST ARTICLES

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

进阶实战游戏功能

迷魂香:一炉香点着,圈里的怪掉头打转

【游戏功能】 怪的仇恨为什么永远追着你?因为它看得见你。迷魂香把"看得见"这三个字没收了:一炉香落在它脚下,烟圈六秒——圈里…

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

气势:连击涨势 挨打掉势 提气回血五十

【游戏功能】 连击值攒着有什么用?多数战斗的答案是攒个伤害加成——气势给了第二个答案:攒的是一支军队的士气。每一刀涨十二点、…

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

崩血:伤口一动就崩,跑得越快掉血越凶

【游戏功能】 一道割裂挂上去,一秒一跳——它站着跳四,追你的时候崩成八:伤口一动就崩,跑得越快掉得越凶。崩血把"放风筝"从走…

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

燕回式:突进穿它一遭,原路飞回起手点

【游戏功能】 突进出去了,回不回得来?多数突进的答案是"不回"——人留在怪堆里听天由命。燕回式给突进装了归途:穿身而过去时一…

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

破招式:它抡重刀你抢半拍,招克招

【游戏功能】 读条变红的那一秒,全世界都在等一个决定。破招式把这一秒做成整场战斗的心跳:怪交替出红劈和蓝刺,红劈读条时按下破…

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

连招谱:三招按谱出,谱尾一击翻倍

【游戏功能】 出招的顺序算不算伤害?大多数战斗里不算——三招乱按和按谱出,账面一个样。连招谱把顺序变成了伤害本身:「劈→撩→…

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