Roblox Guidebook知识库
简体中文 ⌄

开发 / ROBLOX

Roblox 加载画面:选择必要资源,并如实说明就绪状态

为第一个画面准备一份小资源清单,区分请求已有结果与加载成功。原创的三资源菜单练习展示失败记录和继续操作,避免把清单处理完成说成整个游戏已经就绪。

更新日期:

确定玩家的第一个动作 #

从一个具体动作开始:玩家读懂训练路线名称,看见开始按钮,知道按钮会带自己去哪里。列出这个时刻需要的图片和声音。远处商店里的大量宠物,还不属于第一个画面的必要内容。聚焦清单可以帮助讨论每项资源为什么现在就需要,而不是把整个体验都变成装饰性加载画面的前提。

本例使用虚构菜单,包含插图、按钮图标和短声音。illustration、start-icon、first-sound 是教学标识,不是已经发布的 Roblox asset ID。我们没有接入他人的图片,也没有把练习说成对作者五款游戏的测试。练习的目标是先建立诚实的结果记录,再连接真实下载和用户界面。虚构场景提供一个范围明确、方便核对的对象。

分清内容加载与游戏就绪 #

ContentProvider 提供 PreloadAsync 用于预加载内容。参考资料将该方法标为会暂停调用线程的操作,回调示例报告内容标识与 AssetFetchStatus。这些信息描述内容,不能单独确认存档读取、角色创建、服务器可用性或所有世界对象已经准备好。启动过程中的不同任务需要各自的证据,不能从单一来源推导一个通用的就绪标记。

分别记录菜单对所选图片的要求,以及开始训练路线之前必须发生的事情。图标可用但角色尚未出现,并不能证明整个游戏已加载。如果只完成了某份清单的结果记录,就明确说明这份清单。本练习采用一条表述规则:屏幕消息应准确描述系统确实能够检查的结果,并保留其他尚未完成或尚不清楚的部分。

不要把请求队列变成百分比 #

RequestQueueSize 看起来很适合做进度数字,但官方性能指南提醒,请求队列会波动。它不是你这项任务的固定分母。在观察期间,新请求可能改变队列规模。所以队列缩小不能自动表示菜单准备度的准确百分比,也不能可靠地证明所有必要资源都已经加载完成。数字容易读取,不代表它适合回答你的具体问题。

练习使用自定义、不变化的清单,包含三个不同标识。收到任何结果之前和之后,清单大小都是三。重要条件是明确知道清单条目与被计数结果之间的对应关系。先数任意对象,再把每次回调当作一个对象,不能直接得到整幅场景的有效百分比。分母必须描述与你实际核对的结果相同的单位。

建立小而必要的资源清单 #

性能指南推荐有选择地预加载,例如加载画面图片、重要菜单图片和起始区域资源。它把预加载整个 Workspace 视为会增加等待时间的不良做法。为每个条目写明用途:为什么现在需要、缺少它时玩家会看见什么、不可用时允许什么行为。这样的说明比列出游戏未来可能展示的一切更有帮助。

在虚构菜单中,可以用文字替代插图,按钮应保留可读标签,而声音缺失不应让按钮含义变得不清楚。这些只是这个原型的决定,还需要玩家测试,并不表示所有体验的所有资源都能忽略。如果某个模型是安全开始关卡的必要条件,就应把模型就绪视为独立启动要求,不能用装饰性加载画面替代。

从清单到结果打开大图 ↗
原创的所选加载任务示意图。

保留不同的结果计数器 #

原创的纯 Luau 示例保存 total、resolved、succeeded、failed。第一个是清单大小,第二个是收到结果的数量,后两个分别统计成功与失败。record 接受教学标识和布尔值。它不会调用 Roblox API,不会下载文件,也不会直接接收 Enum.AssetFetchStatus。真实适配器必须另行把已经检查的加载结果转换成所需状态。

这个例子是可以验证的记录模型。一次失败和两次成功后,计数为 resolved=3、succeeded=2、failed=1。settled 表示每个清单条目都有结果,但此时 allSucceeded 仍为 false。不要把这两种检查都叫作“就绪”。得到三次尝试的结果与成功获取三个资源,属于不同成果,即使已处理条目的数量完全相同。

-- Pure Luau bookkeeping, not a ContentProvider adapter.
-- Each manifest entry represents exactly one distinct content identifier.
local function newTracker(ids)
    assert(type(ids) == "table", "Manifest must be a table")
    local expected = {}
    local total = 0
    for _, id in ipairs(ids) do
        assert(type(id) == "string" and id ~= "", "Invalid content identifier")
        assert(not expected[id], "Duplicate content identifier")
        expected[id] = true
        total += 1
    end
    local entries = 0
    for index in pairs(ids) do
        assert(type(index) == "number" and index >= 1 and index % 1 == 0,
            "Manifest must use consecutive array indices")
        entries += 1
    end
    assert(entries == total, "Manifest cannot contain array gaps")
    local outcomes = {}
    local resolved = 0
    local succeeded = 0
    local failed = 0
    local tracker = {}

    function tracker.record(id, success)
        assert(type(success) == "boolean", "Outcome must be boolean")
        if not expected[id] or outcomes[id] ~= nil then
            return false
        end
        outcomes[id] = success
        resolved += 1
        if success then
            succeeded += 1
        else
            failed += 1
        end
        return true
    end

    function tracker.snapshot()
        return {
            total = total,
            resolved = resolved,
            succeeded = succeeded,
            failed = failed,
            settled = resolved == total,
            allSucceeded = resolved == total and failed == 0,
        }
    end

    return tracker
end

return newTracker

防止重复结果改变记录 #

处理器再次收到 start-icon 的结果时,不能让计数器再次增加。特别是偶然重复的成功结果,不应覆盖已经记录的失败。本模型只接受已知标识的第一个结果,忽略其他标识的消息。这是单次教学尝试的规则。若要有意重新下载,就需要新的尝试,以及明确决定如何更新状态和表达历史的策略。

开始之前也要验证清单:标识必须是唯一且非空的字符串,表必须构成连续、无缺口的数组。否则 ipairs 可能提前停止,产生错误分母。每次返回的 snapshot 都是新表,修改其字段不会改变内部记录。这些约束可以独立检查,但通过检查不能证明网络连接或 Roblox 引擎具有任何特定的实际加载行为。

三个结果打开大图 ↗
纯 Luau 测试结果,不是真实资源下载。

用清楚的消息解释失败 #

把进度消息与结果消息分开。“已处理所选资源中的 2 项,共 3 项”描述记录进度;“一个资源未获取”描述结果。当 failed 大于零时,不要写“全部加载完成”。没有测量时不要编造精确剩余时间。相比隐藏未知状态的平滑进度条,一个可以理解的下一步通常更有用,也更便于解释具体问题。

虚构菜单可以为缺失图片提供可读标签,并为声音缺失提供独立提示。原型检查需要确认,玩家仍能理解目的地和开始动作。重要游戏对象则需要另一种响应:解释限制,提供允许的退出或重试。不要保证重试一定成功。资源失败可能需要检查标识和访问权限,而不是无限重复发送同样的请求。

字段含义
total三个所选资源
resolved三个结果
succeeded两次成功
failed一次失败

继续操作不能伪装成取消下载 #

官方指南建议,在需要加载大量资源时提供 Skip Loading 选项。先定义按钮在本原型中的含义:关闭装饰画面并使用已有替代继续,还是进入功能有限的菜单。标签应与动作一致。这项建议并不能证明,按下按钮会自动取消正在执行的 PreloadAsync,也不能把相关资源的状态变成加载成功。

如果结果在面板关闭后到达,处理器应正确更新状态,而不是把玩家拉回加载画面。具体 GUI 与加载生命周期的连接,需要单独测试。我们的纯记录模型没有创建 GUI,也没有实现跳过按钮。它展示决策所需的数据,而不是适用于所有游戏和设备的完整取消、重试或画面切换系统。

分别测试记录与集成 #

先用人为事件验证模型:未知标识、重复结果、失败、顺序不同的两次成功,以及还有待处理条目的清单。关键是准确计数和避免错误的 allSucceeded。独立检查无需网络连接,但只证明示例所选择的逻辑。测试名称与结果报告应保持这个边界,避免让表数据测试看起来像真实 Roblox 加载器测试。

之后还需要在独立教学项目中接入自己有权限使用的资源,观察真实状态,并在目标设备上检查菜单。记录标识、环境、每次请求结果与普通动作是否可用。分别研究内容不可用和面板关闭的情形。本文尚未完成这样的集成测试;没有测量加载时间、内存变化或玩家留存效果,也不能从记录模型检查中推导它们。

检查边界
重复结果不会再次计数
其他标识忽略
空请求队列不证明全部就绪
真实 Roblox API尚未测试

保存可以复现的结论 #

有用的结论包含小清单、选择原因、resolved 与 succeeded 的区别、failed 非零时的行为,以及画面就绪的边界。“两次成功、一次失败”的记录必须明确保留失败。空清单不需要除以零:模型报告没有资源且已经处理完毕的状态。界面更适合用文字解释这种情况,而不是显示未定义的百分比。

把想法用于真实游戏之前,向另一位开发者提供代码、独立检查和仍未验证的条件。不要只为漂亮的 100% 就把整个世界放入预加载。第一个画面应帮助玩家理解预定动作,并诚实描述当前状态。文章与教学模型均为原创;请用官方来源核对最新 API 细节,并分别测量具体游戏的结果。

原始资料

Roblox Creator Hub — ContentProvider
Roblox Creator Hub — Improve performance