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

回响:一刀出手两秒后,余音还在收账

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

【游戏功能】

M.hp = M.hp - (hit + echo) —— 结算行里多出来的那个回响项,就是这道题的全部答案:一刀的价值不止出手的这一瞬,还有两秒后落回原地的余音。回响把每一次重击都变成两笔账:眼前十六点,两秒后原地再收八点——前提是它还站在音环里。这篇把整套模块拆开:配置表、音环构件、回放结算、定时器、调试按钮,一段一段照抄能跑。

一、效果演示:一刀两笔账,余音也收钱

演示场点「鸣!」:一记紫色的重击拍在怪身上,十六点的紫字蹦出来,它脚下同时落下一枚淡紫的音环——环里挂着两秒的倒计时。这两秒是它的选择题:站着硬扛,倒计时归零的瞬间余音炸开,再收八点;往旁边挪出音环,余音落空,地上只留一圈散掉的紫纹。演示里故意引它走位:余音落空的那一次,账面上就亏了八点——回响教的不是输出,是"让它在哪儿挨第二刀"的布置。会玩的人用普攻把怪往音环里赶,一刀变两刀,位置就是伤害。

demo
 fx-echoquake

二、底层原理:一枚留地的音环加一次延时重放

模块的机关是一对搭档。留地音环:重击命中的那一帧,命中坐标落进回放表,挂两秒倒计时——音环认地不认人,怪跑了环不动,走与不走是它的题。延时重放:倒计时归零的那一拍,在环心做一次范围校验——怪还在环里就重放半价的一击,出圈了只演一圈散纹。和延迟爆炸类技能的分野在"重放的是刚打过的这一刀":延迟爆是新的伤害包,回响是旧刀的余韵——半价的数值和两秒的间隔,让余音永远是"刚才那一下的回声"而不是第二发炮弹。

重放为什么认地不认人?认人的版本怪怎么走都躲不掉,余音变成必定命中的免费加伤;认地的版本走位能破,玩家要用普攻和走位把怪"送"回音环——一道必须双方动脑的几何题,比一张必中的支票值钱得多。

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

lua
-- @file EchoQuake.lua
-- 回响 —— 一刀出手两秒后,余音还在收账

local EchoQuake = {}

local CONST = {
    STRIKE_DMG    = 16,
    ECHO_DMG      = 8,
    ECHO_DELAY    = 2.0,
    ECHO_RADIUS   = 44,
    STRIKE_CD     = 3.0,

    COLOR_ECHO    = "#b878e0",
    COLOR_DEEP    = "#3e1a5e",
    COLOR_GHOST   = "#e0c8f8",

    ZORDER_RING   = 129,
    ZORDER_FX     = 135,
    AUTOINC_BASE  = 1001000,
}

local _echoes    = {}
local _cdLeft    = 0
local _scheduler = nil
local _autoInc   = 0

local function GenID(prefix)
    _autoInc = _autoInc + 1
    return string.format("%s_%d", prefix or "EQK",
        CONST.AUTOINC_BASE + _autoInc)
end

local function GetActorPos(id)
    if not id then return nil end
    local x = SL:GetValue("ACTOR_POSITION_X", id)
    local y = SL:GetValue("ACTOR_POSITION_Y", 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 DropEchoRing(x, y)
    local node = GUI:Layout_Create(GUI:Attach_SceneF(),
        GenID("Ring"), x, y, 0, 0, false)
    GUI:setLocalZOrder(node, CONST.ZORDER_RING)
    GUI:DrawCircle_Create(node, "ring", 0, 0, 34,
        CONST.COLOR_ECHO, 2, 200)
    return node
end

function EchoQuake.Strike()
    if _cdLeft > 0 then
        ShowTip("音在荡——" .. string.format("%.1f", _cdLeft) .. "秒")
        return
    end
    local tid = SL:GetValue("MARK_TARGET_ID")
    local tp = GetActorPos(tid)
    if not tid or not tp then return end
    _cdLeft = CONST.STRIKE_CD
    SL:ActorHurt(tid, CONST.STRIKE_DMG)
    SL:TipAbove(tid, "-" .. CONST.STRIKE_DMG)
    SL:PlayStrikeFx(tid)
    SL:ScreenShake(2.4, 0.16)
    SafeRemove(_ringFx)
    _ringFx = DropEchoRing(tp.x, tp.y)
    table.insert(_echoes, { x = tp.x, t = CONST.ECHO_DELAY })
    ShowTip("一刀十六留了枚音环——两秒后原地重放八点")
end

四、核心代码:完整模块(下·定时器与延时重放)

lua
-- 延时重放:倒计时归零,环心结算
local function ReplayEcho(ek)
    local myID = SL:GetValue("USER_ID")
    SL:PlayEchoBurstFx(ek.x, myID)
    local tid = SL:GetValue("MARK_TARGET_ID")
    local tp = tid and GetActorPos(tid)
    if tp and math.abs(tp.x - ek.x) <= CONST.ECHO_RADIUS then
        SL:ActorHurt(tid, CONST.ECHO_DMG)
        SL:TipAbove(tid, "余-8")
        ShowTip("余音收账——八点入账")
        if SL:GetValue("ACTOR_DEAD", tid) then
            SafeRemove(_ringFx)
        end
    else
        SafeRemove(_ringFx)
        ShowTip("它走出了音环——这一笔收不回了")
    end
end

-- 定时器:回放表推进与音环跟数
if not _scheduler then
    _scheduler = SL:Schedule(function(dt)
        _cdLeft = math.max(0, _cdLeft - dt)
        for i = #_echoes, 1, -1 do
            local ek = _echoes[i]
            ek.t = ek.t - dt
            if ek.t <= 0 then
                table.remove(_echoes, i)
                ReplayEcho(ek)
            end
        end
    end, 0.02)
end

SL:ScheduleOnce(function()
    SL:BindDebugButton("鸣", function()
        EchoQuake.Strike()
    end)
    ShowTip("技能已加载: 回响 (调试按钮触发)")
end, 1.0)

function EchoQuake.Unload()
    if _scheduler then SL:Unschedule(_scheduler) end
    SafeRemove(_ringFx)
    _echoes = {}
end

return EchoQuake

五、机制问答

问:音环能同时留两枚吗?
答:能——冷却三秒对延迟两秒允许两枚并存,两枚音环叠在同一点就是两段余音连炸,老玩家的阵型讲究全在这排环上。

问:余音能暴击吗?
答:能——重放走正常结算,暴击的余音照样暴,半价的一刀偶尔比正价疼。

问:怪被推出音环算破吗?
答:算且只算走位破——用推掌把怪挪出环和它自己走出环是同一回事, 几何面前不分谁动的手,破环就是破环。

问:重放的八点吃增伤吗?
答:吃——余音是完整的一刀,破势迟滞照常参与,半价是它的出身,不是它的天花板。

问:怪死了余音还炸吗?
答:炸给下一只——音环认地,旧怪倒下新怪站进来,余音照收,音环铺路是清怪关的进阶课。

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

第四笔是半价的比例:八对十六是一半——半价以下的余音像装饰,八成以上像连招,一半刚好是"值得布置、不值得硬凑"的心理线。第三笔是延迟的长度:两秒对怪的走位速度是"来得及躲、舍不得躲"的窗口——一秒躲不掉等于必中,三秒玩家自己都忘了。第二笔是环的半径:四十四步对怪的模型宽是"站得住但站不踏实"的紧度——环太大余音变成范围必中,太小勉强站进去也吃不安稳。第一笔是环的呼吸:音环的亮度和倒计时同步收拢——玩家余光扫一眼就知道余音还剩几拍,环是钟,不是贴纸。常见坑三个:回放表的坐标在怪传送后不校验地形;同一点落两枚环只结算一枚;余音打死怪的击杀归属挂在玩家名下却没进统计,账面平白少一块。

商业服里回响是"乐师流派"的主旋律:一刀两笔账,节奏全在两秒的间隔里——商城里音环的样式做成品级,紫环、金环、琴纹环,地上一排音环就是乐师谱好的曲。运营落地还有两笔:一段是走位破环的教学——第一课教怪怎么躲,玩家才知道怎么把环布在它躲不掉的地方,知己知彼一页讲完;一段是收账榜——按余音命中总数排名,乐师的每一次"它站住了"都有账可查。变体做成余音绕梁:重放的余音若命中,再留一枚半价的环——回响里套回响,琴音一段接一段,上限留给最会谱曲的人。这一篇的演示和整套模块照抄能跑,改的就是 CONST 那张表。

还有一拍要记住:环是死的,怪是活的,活人才有资格给死环上菜。

写完留一句给做延时系的同学:回响卖的是"这一刀还没完"——地上那枚倒计时的紫环,是你两秒前写好的账单,它站多久,就付多久。

作者履历与出处

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

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

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

LATEST ARTICLES

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

进阶实战游戏功能

赊账:这一刀双倍先赊着,三秒后连本带息还

【游戏功能】 先消费后还款这事儿,战场上也行得通?赊账的答案是行得通,但有利息:点一下赊账,下一刀双倍——多出来的那十点伤害…

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

全垒:把小怪挑上天,一记扣杀双倍入账

【游戏功能】 为什么棒球里全垒打最值钱?因为球在天上的那一秒,全场的眼睛都仰着头。全垒把这份仰头搬进了打架:一记挑空把小怪送…

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

迟箭:把它的箭慢放成蜗牛,箭雨里都能散步

【游戏功能】 后台埋点抓到一个怪数据:某位玩家的承伤记录里,被远程命中数是零——不是躲得快,是他挨的每一箭都"消失了"。翻录…

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

借刀:站到它队友身后,借它自己的刀劈它

【游戏功能】 P.x, C.x = C.x, P.x —— 一行换位,借刀的全部机关就藏在这一笔里:玩家和小怪换个位置,怪的…

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

搬兵:抓一只小的抡起来,砸得大的直哆嗦

【游戏功能】 打群架的最高境界是什么?是一个人打,让对面自己人打自己人。搬兵把这句话演成了动作:抓住一只小怪举过头顶,抡圆了…

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

越战:开战越久劲越足,三十秒练出一口气

【游戏功能】 同样的装备,为什么老玩家打得越来越疼?新手第一刀十点,第一百刀还是十点;老玩家第一刀十点,第一百刀已经十四——…

2026-10-01 12:59 996 技术组