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

Lua帧率无关:按秒算账的步长折算

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

【语法算法】

上一版留了个高配机才能看见的隐蔽报错:同一个移动逻辑,高帧率的新机走得飞快,低帧率的旧机走得慢半拍——移动速度明明写的是同一个数。追到底不是机器快慢的问题,是移动写法按帧算账:每帧走两步,帧率翻倍步数翻倍,速度就被帧率绑架了。修法是把账改成按秒算:每帧先折算这一帧耗了几秒,位移等于速度乘秒数——帧率多少都不掉速。这篇把整改后的整套写法拆开:配置表、步长折算、按秒推进、追赶封顶、定时器、调试按钮,一段一段照抄能跑。

一、效果演示:帧率一掉见分晓

演示场两颗球同时起跑:橙球按帧走——每帧固定挪两步;蓝球按秒走——每秒固定走一百二十步。三档帧率随便切:六十帧时两球齐头并进;切三十帧,橙球立刻慢下来;切十帧,橙球几乎原地踏步,蓝球照常冲线。左上角实时播报两球的差距——差距就是按帧算账欠下的债。演示里试一笔账:十帧的橙球和六十帧的橙球,走的是同一个"每帧两步",可每秒差了五倍——帧率不是速度,秒才是。帧率无关教的是记账:时间用秒量,不用帧量——帧是机器的呼吸,秒是世界的钟,跟着呼吸走的世界在旧机器上会窒息。

mermaid
flowchart TD
A[每拍累计真实耗时] --> B{攒够一帧的时长}
B -- 是 --> C[按帧走的走一步]
B -- 否 --> D[跳过]
C --> E[按秒走的走 耗时乘速度]
D --> E
E --> A
demo
 fx-deltatime

二、底层原理:一次步长折算加一次按秒推进

模块的机关是一对搭档。步长折算:每一拍先量真实耗了多久——把耗时分给按帧走的逻辑当帧长,帧率掉它就自动拉长帧间隔。按秒推进:位移等于速度乘真实秒数——秒是硬通货,帧率涨跌与它无关,两台机器跑同一个数走同一段路。和按帧写法的分野在"按帧的速度被帧率绑架":每帧走两步在六十帧就是每秒一百二十步,在十帧就是每秒二十步——写的是速度,跑出来的是帧率的奴隶——同一份代码在两台机器上跑出两种速度,玩家不会懂帧率,只会说这游戏做得糙。

帧率掉了帧间隔为什么会自己变大?一步的耗时是实测出来的——机器卡了这一步就长,机器顺了这一步就短——步长贴着真实时间,写法才能在高配低配上一个样,步长是贴着真实时间走的,账才不会跟帧率跑偏——这一条是所有运动写法的地基,地基歪一寸上面的手感全歪。

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

lua
-- @file DeltaTime.lua
-- 帧率无关 —— 按秒算账的步长折算

local DeltaTime = {}

local CONST = {
    SPEED         = 120,
    FRAME_FPS     = 60,
    FRAME_STEP    = 2,
    WORLD_MAX     = 620,

    COLOR_BYSEC   = "#58a6ff",
    COLOR_BYFRAME = "#f0883e",

    AUTOINC_BASE  = 1151000,
}

local _fps       = 60
local _acc       = 0
local _bySec     = 40
local _byFrame   = 40

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

function DeltaTime.SetFps(fps)
    _fps = fps
    ShowTip("帧率切成" .. fps .. "——看两球分家")
end

function DeltaTime.Reset()
    _bySec = 40
    _byFrame = 40
    _acc = 0
end

function DeltaTime.Pos()
    return _bySec, _byFrame
end

四、核心代码:完整模块(下·帧长折算与双轨推进)

lua
-- 帧长折算与双轨推进:每拍给两条账各记各的
if not _scheduler then
    _scheduler = SL:Schedule(function(dt)
        _acc = _acc + dt
        local frameLen = 1 / _fps
        while _acc >= frameLen do
            _acc = _acc - frameLen
            _byFrame = _byFrame + CONST.FRAME_STEP
            if _byFrame > CONST.WORLD_MAX then
                _byFrame = 40
                _bySec = 40
            end
        end
        _bySec = _bySec + CONST.SPEED * dt
        if _bySec > CONST.WORLD_MAX then
            _bySec = 40
            _byFrame = 40
        end
    end, 0.02)
end

SL:ScheduleOnce(function()
    SL:BindDebugButton("切十帧", function()
        DeltaTime.SetFps(10)
    end)
    ShowTip("技能已加载: 帧率无关 (调试按钮触发)")
end, 1.0)

function DeltaTime.Unload()
    if _scheduler then SL:Unschedule(_scheduler) end
    _scheduler = nil
end

return DeltaTime

五、机制问答

问:按秒走的球在十帧下会一秒跳一大步吗?
答:会跳但不多——帧长内攒的速度一次算总账,位置一拍更新一次,跳的是更新频率不是速度。

问:帧间隔会不会攒出超大步长?
答:会封顶——断线重连回来一帧攒了三十秒,不封顶的角色一秒穿屏,步长封一个上限是保险丝。

问:按帧走的逻辑必须全改吗?
答:改玩法层的——渲染抖动、界面呼吸这类纯视觉的可以按帧,凡是位置速度血条时间一律按秒。

问:帧率无关和弹簧跟随冲突吗?
答:不冲突——弹簧的系数本来就乘步长,两套写法在"按时间算账"这一条上是同一个祖宗。

问:模拟帧率的那条球为什么自己会循环?
答:演示需要——走到边界回起点重跑,两球各自回各自的,差距的读数看得更清楚。

六、调参与实战怎么用

第四笔是折算的位置:帧长折算要放在推进之前——先折算再算账,顺序一颠倒帧间隔就丢一拍,这是整套写法的时序根。第三笔是步长的封顶:攒帧的上限是保险丝——上限设一秒足够宽也足够安全,超过一秒的帧间隔按一秒算,穿屏和爆表都拦在门外。第二笔是双轨的对照:按帧和按秒各跑一条是演示的说服力——只讲道理不放对照,读的人永远觉得危言耸听。第一笔是常数的语义:一百二十写的是"每秒一百二十"不是"每帧一百二"——常数的单位写进名字里,后来的人不会再犯按帧的错。常见坑三个:帧长折算放在推进之后的顺序错;断线重连的巨帧没封顶穿屏;常数命名不带单位导致后来人按帧改。

实战里按秒算账是所有运动写法的地基:弹簧、惯性、缓动、计时,全部站在这一块地基上。组里的约定是:新写的运动类模块第一行先写步长折算——地基打好,上面盖什么都稳。这篇的模块照抄能跑,改的就是 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 技术组