UI 表现优化
客户端卡顿八成出在 UI 上。UI 从注册到显示要经历几个阶段,把它们拆开、错峰执行,是避免卡顿的核心思路。
UI 的四个阶段
| 阶段 | API | 耗时特征 |
|---|---|---|
| 注册 | RegisterUI | 与界面复杂度无关,稳定均值,同一 UI 只注册一次 |
| 创建 | CreateUI | 受控件数量、图片总尺寸影响大,一般 10~40ms |
| 显示 | SetScreenVisible | 已创建的界面显示只要 ~1ms |
| 销毁 | SetRemove | 1~3ms,销毁后需重新 CreateUI |
关键洞察:显示很快,创建很慢。把"创建"提前或错峰,只在需要时"显示",就不会卡。
用 UI 管理器分离各阶段
基于 Create On Use 原则封装一个 UIMgr:初始化时统一注册所有 UI(客户端启动本来就要几秒,多花百来毫秒无感);首次 GetUI 时才创建并缓存;之后重复显示直接命中缓存。
python
class UIMgr(object):
def __init__(self):
self.mUIDict = {}
def Init(self, system):
self.mClientSystem = system
for uiKey, config in UIData.iteritems(): # 启动时统一注册
clientApi.RegisterUI(self.mModName, uiKey, config["cls"], config["screen"])
def GetUI(self, uiKey):
ui = self.mUIDict.get(uiKey) # 优先命中缓存
return ui if ui else self.CreateSingleUI(uiKey) # 没有才创建
def ShowUI(self, uiKey):
ui = self.GetUI(uiKey)
if ui: ui.Show()
def CleanCacheUI(self): # 合适时机释放内存
for ui in self.mUIDict.values():
ui.SetRemove()
self.mUIDict.clear()这样能保证同一时间只创建一个 UI、每个 UI 只创建一次,避免同时大量创建导致的卡顿。
其他关键技巧
pushScreen异步创建:整合创建+显示且分时完成,最大限度防卡顿。但只能同时显示一个界面,别与CreateUI混用。- 九宫贴图代替大图:一张 32×64 小图九宫拉伸即可铺出 297×198 背景,省内存。
- 拆分复杂分页界面:控件总数越多创建越慢。像领地插件那样,把每个分页做成独立子界面,切分页=隐藏一个/显示另一个。
- 分时执行 Clone:Clone 100 个组合控件要 867ms(而普通界面才 36ms)。先显示空界面,再每帧 Clone 5~10 个,几十帧内建完。
- 过渡加载界面预建 UI:进游戏时用带进度条的全屏界面,每帧注册+创建一个后续要用的 UI,游戏中就只剩秒开的显示/隐藏。
性能红线
| 项 | 建议上限 |
|---|---|
| 单界面控件总数 | 超过 1000 个明显卡顿 |
| ScrollView 中 Clone 单元 | 不超过 50 个 |
| 贴图分辨率 | 1024×1024 是 512×512 的 4 倍开销,能小则小 |
不可见 ≠ 不消耗
SetVisible(False) 只是隐藏,控件仍占 UI 性能。ScrollView 里滚出视窗的控件才是重灾区——从数量上控制它。
下一篇多账号协同与控制台调试。回到基岩版网络游戏首页。
