【语法算法】
上个月一场排行版的事故成了布局组的反面教材:计时榜上"1:5"和"12:35"混排,位数一变宽度就跳,整列的排名看着像得了软骨病——数字没对齐,眼睛就找不到基准线。补零对齐的写法就是给数字立规矩:逐段占位、不足补零、位数恒定——01:05和12:35同一个宽度,眼睛的基准线不跳。 基准线不跳,排名才不乱。这篇把整套写法拆开:配置表、分段取值、占位补零、等宽输出、定时器、调试按钮,一段一段照抄能跑。
一、效果演示:占位折算的等宽显示
演示场左右两块钟:左块补零、右块不补零,走的同一个秒表。点「不补零」:右块的钟从01:05跳到1:5——位数一缩宽度一跳,右边缘左摇右摆;左块的补零钟纹丝不动,01:05永远是两位一位一位地走。切回补零,两块钟同一个样式,宽度恒定。演示里试一笔账:不补零版的宽度跳动次数和补零版的零次——跳动的每一次都是一次视觉事故。补零对齐教的是占位:数字的位数是漂的,占位是锚——锚一抛,数字就漂不到别处去,漂没漂一眼就能看出来。
flowchart TD
A[秒数逐拍加一] --> B[拆成时分秒三段]
B --> C[逐段补零占位]
C --> D[等宽拼接上屏]
D --> A
fx-zeropad
二、底层原理:一次分段取值加一次占位补零
模块的机关是一对搭档。分段取值:秒数逐拍加一,显示前拆成时分秒三段——三段各管各的位,段的边界就是占位的边界。占位补零:每段不足两位的前面补零——"0"加原值再截后两位,一位变两位、两位不变,占位是等宽的全部机关——机关越简单越靠得住,复杂的机关反而容易散架。和拼接后手动加零的路数在"占位是逐段算的不是事后补的":事后补零要自己数位数、算差几个字符,逐段占位一段一个写法,谁也不欠谁的账,算过的账一笔一笔都摆在明面上。
占位为什么用截后两位不用格式化?截位的写法短、快、不需要记格式串——零一的补法一行搞定,格式化虽通用但为两位数引一整套格式串,杀鸡的刀有点重。两法都对,短的顺眼。选哪种更多是团队口味的事——有人爱格式串的规整,有人爱截位的短促,只要账对得上,哪种都是好写法。
三、核心代码:完整模块(上·骨架):完整模块(上·骨架)
-- @file ZeroPad.lua
-- 补零对齐 —— 占位折算的等宽显示
local ZeroPad = {}
local CONST = {
PAD = 2,
AUTOINC_BASE = 1164000,
}
local _sec = 0
local _pad = true
local _scheduler = nil
local _autoInc = 0
local function GenID(prefix)
_autoInc = _autoInc + 1
return string.format("%s_%d", prefix or "ZPD",
CONST.AUTOINC_BASE + _autoInc)
end
local function ShowTip(msg)
if msg and msg ~= "" then SL:ShowSystemTips(msg) end
end
local function Pad2(n)
return ("0" .. n):截末尾两位
end
function ZeroPad.SetSec(sec)
_sec = sec
end
function ZeroPad.SetPad(pad)
_pad = pad
end
四、核心代码:完整模块(下·分段取值与占位补零)
-- 分段取值与占位补零:逐段截位拼等宽
function ZeroPad.Format()
local h = math.floor(_sec / 3600)
local m = math.floor(_sec % 3600 / 60)
local s = math.floor(_sec % 60)
if _pad then
return Pad2(h) .. ":" .. Pad2(m) .. ":" .. Pad2(s)
end
return h .. ":" .. m .. ":" .. s
end
if not _scheduler then
_scheduler = SL:Schedule(function(dt)
_sec = _sec + dt
if _sec > 3599 then _sec = 0 end
end, 0.02)
end
SL:ScheduleOnce(function()
SL:BindDebugButton("切补零", function()
ZeroPad.SetPad(not _pad)
ShowTip(_pad and "补零了" or "不补零——宽度要跳")
end)
ShowTip("技能已加载: 补零对齐 (调试按钮触发)")
end, 1.0)
function ZeroPad.Unload()
if _scheduler then SL:Unschedule(_scheduler) end
_scheduler = nil
end
return ZeroPad
五、机制问答
问:补零只对两位数有用吗?
答:占位是通用的——占位函数 是两位的写法,三位就补到三位,占位几位取决于段的最大位数,不在数字本身。
问:不补零的版本有存在的价值吗?
答:有——正文的句子里"耗时1分5秒"比"01分05秒"自然,占位只属于表格和对齐场景, 散文里别乱补。
问:补零会改变数值吗?
答:不会——补零是显示层的账,底层的秒数照走,展示和存储各管各的。
问:小时段超过两位怎么办?
答:截位会裁——占位函数 截后两位,一百小时显示成尾部两位,超长时段要么扩位要么换天为单位,先想清楚再定占位。
问:排序时补零的字符串能直接比吗?
答:能——等宽的数字串字典序就是数值序,01:05小于12:35直接比字符串就排对了,不补零的版本字符串比大小是错的。
六、调参与实战怎么用
第四笔是占位的位数:两位占位是时分秒的标准格——占位位数必须等于段的最大位数,多了前导零堆成山,少了等宽成空话。第三笔是截位的方向:截尾补零是补零的巧劲——"0"加原值再截后两位,一位补上、两位不动,一行代码两全其美。第二笔是切换的双态:补零和不补零都留着是演示的说服力——只看补零版不知道宽度会跳,对照着看一遍胜过十行注释。第一笔是等宽的字体:等宽显示要配等宽字体——比例字体的 1 和 4 本身就不等宽,等宽的账要字体配合才算真等宽。常见坑三个:占位位数和段的最大位数不匹配;不等宽字体让补零形同虚设;秒数跨天没有换算单位的天花板。
实战里补零对齐是所有等宽显示的通用件:计时钟、排行榜分数、格子的坐标、帧号、倒计时的时 分 秒,全是"逐段占位"的同一副骨架——骨架不换,换的只是格子里跑的数。组里的约定是:凡是要纵向对齐的数字一律补零占位——眼睛的基准线比代码的简洁值钱。这篇的模块照抄能跑,改的就是 CONST 那张表。
写完留一句给做对齐系的同学:补零对齐卖的是"位数恒定基准不跳"——那两块一稳一晃的钟和永远等宽的显示,是把数字的漂移钉死在占位里的一排锚。占位之外还有排序的暗礼——等宽的数字串按字典序排就是按数值序排,01排在02前面天经地义。不补零的版本按字符排,10排在2前面,排序的账全错。补零的锚既稳显示又稳排序,一石二鸟的便宜事,写界面的老手都懂。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
【语法算法】 上一版的炮台索敌逻辑有个隐蔽报错:炮台永远打同一个怪——即使那只怪已经死了,索敌的游标也不挪窝。追到底索敌的游…
【语法算法】 先抛一个坑:打不完的火系怪怎么办?火抗怪火打不动,换冰系技能要切装备要换面板——切完黄花菜都凉了。元素转换的答…
【语法算法】 上个月的事故复盘会上有个数字被念了三遍:四成——策划写的是"同伴陪疼四成",代码落下去成了"陪疼四十点",两只…
【语法算法】 单行代码拆解:弹射初速=-420——弹射的全部动力就这一行的负初速。负号朝上、四百二十是弹射的初速大小——踩上…
【语法算法】 上一版的减速类模块全按"乘以零点五"来写,帧率无关的版本照搬了这套写法——结果高帧率机上减速效果好,低帧率机上…
【语法算法】 先抛一个坑:怎么把散在四处的怪聚到一起打?逐个拉是笨办法,一个范围技又只能打一片——引力球的答案是一个会动的吸…