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

Lua波浪排布:相位错开的错落动画

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

【语法算法】

上一版留了排"齐步走"的图标的隐蔽报错:一排波浪排布的图标同起同落——设计稿上是此起彼伏的波浪,实机上整排图标像心跳一样齐刷刷地蹦——蹦得越齐越显瘆人,设计稿上那条活波浪死活出不来。追到底相位没按下标错开:九个图标共用一个正弦,振幅调得再花也是整齐划一的蹦迪。修完给每个图标按下标加一份相位偏移,波浪才活过来——活过来的波浪一寸一寸地荡,荡出来的全是错拍的功夫。这篇把整改后的整套写法拆开:配置表、错落相位、正弦排布、参数轮换、定时器、调试按钮,一段一段照抄能跑。

一、效果演示:相位错开的错落动画

演示场九枚图标排成一行。开场就是波浪:每枚图标按自己的相位上下浮——左边的刚升到顶,右边的还在谷底,此起彼伏。点「换波幅」:波幅在六、十二、二十二之间轮换——波幅越大起伏越夸张。点「换流速」:流速在三档轮换——慢速像水草,快速像沸腾。演示里试一笔账:相位错开前后的对比——同起同落的一排是心跳图,错开的一排才是波浪,一字之差天壤之别。波浪排布教的是错拍:排布的活气全在相位的错落里,同一个公式,错开一拍就是另一个世界——世界换得便宜,才值得反复换。

mermaid
flowchart TD
A[每一拍读时钟] --> B[逐个图标算相位]
B --> C[相位 = 时钟乘流速 加下标乘错距]
C --> D[纵偏 = 正弦乘波幅]
D --> E[图标落在基准加纵偏]
E --> A
demo
 fx-wavelayout

二、底层原理:一份错落相位加一列正弦排布

模块的机关是一对搭档。错落相位:每个图标的相位是时钟乘流速再加下标乘错距——下标就是相位的错开量,相邻图标永远差着半个拍子,波浪的起伏就是这么错出来的。正弦排布:每个图标的纵偏是相位走正弦乘波幅——正弦的平滑保住起伏的体面,波幅定起伏的深浅。和随机抖动的分野在"波浪的错落是秩序的错落":随机抖动是各自乱蹦,波浪是错拍但同律——相位错开、频率一致,此起彼伏里藏着一条看不见的队形——队形看不见但摸得着,乱中有序三个字全给它。

相位错距为什么是零点五五?错距取整倍数会退化成两两组队齐跳,取整圆则整排同相——零点五五不是整圆的分数,相邻图标永远差着小半拍,波浪才有绵延不断的推进感。

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

lua
-- @file WaveLayout.lua
-- 波浪排布 —— 相位错开的错落动画

local WaveLayout = {}

local CONST = {
    ITEM_COUNT    = 9,
    ITEM_GAP      = 65,
    BASE_Y        = 150,
    AMPS          = { 6, 12, 22 },
    SPEEDS        = { 1.5, 3, 6 },
    PHASE_STEP    = 0.55,

    AUTOINC_BASE  = 1159000,
}

local _ampIdx    = 2
local _spdIdx    = 2
local _icons     = {}
local _scheduler = nil
local _autoInc   = 0

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

local function ShowTip(msg)
    if msg and msg ~= "" then SL:ShowSystemTips(msg) end
end

function WaveLayout.Amp()
    return CONST.AMPS[_ampIdx]
end

function WaveLayout.Speed()
    return CONST.SPEEDS[_spdIdx]
end

function WaveLayout.OffsetY(idx, clock)
    local phase = clock * WaveLayout.Speed()
        + idx * CONST.PHASE_STEP
    return math.sin(phase) * WaveLayout.Amp()
end

四、核心代码:完整模块(下·逐个排布与参数轮换)

lua
-- 逐个排布:每个图标按自己的相位落位
if not _scheduler then
    _scheduler = SL:Schedule(function(dt)
        pt = pt + dt
        for idx = 0, CONST.ITEM_COUNT - 1 do
            local node = _icons[idx]
            if node and not GUI:Widget_IsNull(node) then
                local off = WaveLayout.OffsetY(idx, pt)
                GUI:setPosition(node,
                    70 + idx * CONST.ITEM_GAP,
                    CONST.BASE_Y + off)
            end
        end
    end, 0.02)
end

function WaveLayout.CycleAmp()
    _ampIdx = _ampIdx % #CONST.AMPS + 1
    ShowTip("波幅换成" .. WaveLayout.Amp())
end

function WaveLayout.CycleSpeed()
    _spdIdx = _spdIdx % #CONST.SPEEDS + 1
    ShowTip("流速换成" .. WaveLayout.Speed())
end

SL:ScheduleOnce(function()
    for idx = 0, CONST.ITEM_COUNT - 1 do
        local node = GUI:Layout_Create(GUI:GetRootWindow(),
            GenID("Icon"), 70 + idx * CONST.ITEM_GAP,
            CONST.BASE_Y, 48, 48, false)
        _icons[idx] = node
    end
    ShowTip("技能已加载: 波浪排布 (调试按钮触发)")
end, 1.0)

function WaveLayout.Unload()
    if _scheduler then SL:Unschedule(_scheduler) end
    for _, node in pairs(_icons) do
        if node and not GUI:Widget_IsNull(node) then
            GUI:removeFromParent(node)
        end
    end
    _icons = {}
end

return WaveLayout

五、机制问答

问:错距取整会怎样?
答:队形分裂——错距取整倍数时图标两两同相,波浪退化成两组齐跳,半拍的距离才是错落的命。

问:波幅和流速哪个改起来风险大?
答:流速——流速快到一定程度相邻图标会在视觉上抖成频闪,波幅只管深浅不管乱,动流速前先降一档波幅。

问:图标多了排不下怎么办?
答:流水折行——一行摆满折到下一行接着错相位,相位的下标是全局连着的,折行折不断波浪。

问:波浪的基准线要动吗?
答:可以动——基准线缓升缓降,整排图标像浮在水面上随水位走,基准是波浪的船,波浪是船上的旗。

问:错落能换成脉冲吗?
答:能但变味——正弦换脉冲波,此起彼伏变成一闪一闪的告警,脉冲留给告警,波浪留给排布。

六、调参与实战怎么用

第四笔是相位的错距:零点五五的错距是波浪的命根——错距写死为零的版本就是那排齐步走的图标事故,每一份错距都在给波浪上发条。第三笔是波幅的档:六、十二、二十二三档覆盖"微动、常规、夸张"三档气质——波幅一大基准线要下移,免得图标跳出上边界。第二笔是流速的档:一点五到六的流速是从水草到沸腾的范围——流速动之前先看波幅,大波幅配快流速画面会闹。第一笔是排布的基准:图标挂在基准线上下浮——基准线是波浪的船,基准一动整排跟着走,动基准比动波幅更适合做过场。常见坑三个:相位没按下标错开的齐步走事故;流速过快引发的视觉频闪;折行后相位的下标没有接续导致两段波浪各行其是。

实战里波浪排布是"让一排东西活起来"的通用答案:技能栏的呼吸、按钮组的待机、奖励列表的展示,全是"同律错拍"的同一副骨架。组里的约定是:凡是一排同类元素的待机动画,一律加相位错距——齐步走是事故,错拍才是排布。这篇的模块照抄能跑,改的就是 CONST 那张表。

写完留一句给做排布系的同学:波浪排布卖的是"错开半拍才叫波浪"——那排此起彼伏的图标和按下标错开的相位,是把整齐划一升级成此起彼伏的一份错拍表。

作者履历与出处

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

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

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

LATEST ARTICLES

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

进阶实战游戏功能

Lua自动炮台:架一个自动索敌开火

【语法算法】 上一版的炮台索敌逻辑有个隐蔽报错:炮台永远打同一个怪——即使那只怪已经死了,索敌的游标也不挪窝。追到底索敌的游…

2026-10-02 04:50 996 技术组
进阶实战游戏功能

Lua元素转换:火伤转冰伤附带减速

【语法算法】 先抛一个坑:打不完的火系怪怎么办?火抗怪火打不动,换冰系技能要切装备要换面板——切完黄花菜都凉了。元素转换的答…

2026-10-02 04:50 996 技术组
进阶实战游戏功能

Lua连锁引燃:一个着火引燃下一个

【语法算法】 上个月的事故复盘会上有个数字被念了三遍:四成——策划写的是"同伴陪疼四成",代码落下去成了"陪疼四十点",两只…

2026-10-02 04:50 996 技术组
进阶实战游戏功能

Lua弹射地垫:踩上去弹飞到空中

【语法算法】 单行代码拆解:弹射初速=-420——弹射的全部动力就这一行的负初速。负号朝上、四百二十是弹射的初速大小——踩上…

2026-10-02 04:50 996 技术组
进阶实战游戏功能

Lua时间减缓:流速减半的局部时差

【语法算法】 上一版的减速类模块全按"乘以零点五"来写,帧率无关的版本照搬了这套写法——结果高帧率机上减速效果好,低帧率机上…

2026-10-02 04:50 996 技术组
进阶实战游戏功能

Lua引力球:丢出去把怪吸过来

【语法算法】 先抛一个坑:怎么把散在四处的怪聚到一起打?逐个拉是笨办法,一个范围技又只能打一片——引力球的答案是一个会动的吸…

2026-10-02 04:50 996 技术组