关于 roblox-simulator-economy
面向 Roblox 模拟器、放置类等游戏的 Luau 经济设计与实现技能,结合节奏计算、服务器控制的交易模式及可测试的数学模块。
主要功能
- 01计算升级与重生节奏
- 02实现服务器控制的购买
- 03处理离线收益与存档修复
- 04格式化大数并计算概率
- 05运行 Luau 经济数学测试
适用场景
- 01调整升级成本与重生时长
- 02实现批量购买和离线奖励
- 03防止客户端伪造货币购买
- 04显示大额余额与付费物品概率
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ gamedev-skills/ awesome-gamedev-agent-skills --skill roblox-simulator-economy安装后在 Claude Code 中输入/roblox-simulator-economy确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlreferences/formulas.mdserver-patterns.mdscripts/balance.luaueconomy_math.luautest_economy_math.luau详细介绍
Roblox 模拟经营游戏经济系统
编写游戏玩法代码前,先用节奏表确定经济数值,然后再实现,确保所有数值都由服务器管理。代码面向 Roblox 滚动更新的平台 API,随附的脚本均为纯 Luau,并在 Studio 外使用 Lune 0.11.0 运行。
适用场景
- 为模拟经营游戏、 tycoon、点击游戏或放置游戏选择或审查
baseCost、costGrowth、重生要求与倍率,或离线收益上限和效率。 - 使用 Luau 编写升级、最大购买、货币、重生或离线收益代码。
- 显示大数,或会损失精度的约
1e15以上数值。 - 添加使用 Robux 购买的蛋、箱子或转盘次数,或使用可通过 Robux 购买的货币购买的物品。
不适用场景: DataStore 读取、写入、会话锁定和重试 → roblox-datastores。深入设计远程协议和速率限制 → roblox-networking。商店和 HUD 布局 → roblox-ui + game-ui-ux。波次防御游戏的经济系统 → tower-defense。与引擎无关的存档格式问题 → save-systems。
工作流
- 检查。 找出当前存放货币、升级和重生数值的位置,以及会修改它们的脚本。列出所有涉及货币的 RemoteEvent 及其发送内容。
- 将数值写入一个配置表: 基础收入;每项升级的
baseCost、costGrowth、效果和maxLevel;重生的baseRequirement、requirementGrowth、multiplierPerRebirth;离线收益的maxHours、efficiency。服务器和客户端都读取该配置表。 - 运行节奏计算器(路径相对于技能目录):
lune run scripts/balance.luau --print-defaults > economy.json,编辑文件,然后运行lune run scripts/balance.luau economy.json。查看wait和vs prev列,并调整数值,直到符合下方目标。--help会列出所有字段及其允许范围;文件缺失、JSON 无效或字段超出范围时,会打印错误并以状态码 1 退出。 - 在服务器上实现下方的模式,并参考 references/server-patterns.md。将
scripts/economy_math.luau原样复制到 ModuleScript,确保实际运行的数学逻辑与测试过的一致。 - 验证。 使用
lune run scripts/test_economy_math.luau(失败时以状态码 1 退出)验证数学逻辑;在 Studio 中使用 Server & Clients 进行游戏测试,检查购买、重生、退出和重新加入,以及无效远程参数。
公式
| 数量 | 公式 | 说明 |
|---|---|---|
| 下一级价格 | floor(baseCost * costGrowth ^ owned) | 对于会购买很多次的升级,取 1.07-1.15;对于稀有的大型升级,取 1.5-3 |
| 从等级 a 升到 b 的花费 | baseCost * g^a * (g^(b-a) - 1) / (g - 1) | 玩家实际支付的是各级价格向下取整后的总和,因此略低 |
| 最大购买 | 按实际价格逐级计算,直到下一级价格超过余额或达到 maxLevel | 比使用对已向下取整价格不准确的对数公式更安全 |
| 重生要求 k | baseRequirement * requirementGrowth ^ k | |
| 重生倍率 | 1 + k * multiplierPerRebirth | 加法增长缓慢;乘法增长(q ^ k)则呈指数增长 |
| 离线收入 | floor(min(away, maxHours * 3600) * rate * efficiency) | 离线时间为 0 或更少(时钟倒退)时,收益为 0 |
推导过程、重生等待时间比例公式及完整示例: references/formulas.md。
节奏目标(起点,而非规则)
- 前期升级只需几秒。 在默认配置中,前 10 级每级需要 3–10 秒。
- 每次重生所需时间只应比上次略长,例如 x1.2–x1.5。计算器的
vs prev列显示这一比例。采用加法倍率时,该比例会随时间趋近于requirementGrowth,因此requirementGrowth = 3时,比例会从 x2.0 增至 x2.7,按默认收入计算,第 8 次重生需要 137 天。requirementGrowth = 1.8时,比例会从 x1.2 增至 x1.6。 - 离线收益低于在线收益。 将效率设为 0.25–0.5,并将上限设为 8–12 小时,这样持续游玩仍比挂机更有价值,同时也不会让下线的玩家一无所获。
由服务端处理购买
RemoteEvent 只传递玩家想做什么(“购买升级 Income”),绝不传递数量或价格。服务端查询价格、检查余额、扣款并发放,期间不得让出执行权。
-- ServerScriptService/Economy.server.luau (excerpt; full version in references/server-patterns.md)
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local EconomyMath = require(ReplicatedStorage.Shared.EconomyMath)
local Config = require(ReplicatedStorage.Shared.EconomyConfig)
ReplicatedStorage.Remotes.BuyUpgrade.OnServerEvent:Connect(function(player: Player, upgradeId: unknown)
local session = sessions[player]
if not session or type(upgradeId) ~= "string" then return end
local upgrade = Config.upgrades[upgradeId]
if not upgrade then return end -- unknown id
local owned = session.levels[upgradeId] or 0
if owned >= upgrade.maxLevel then return end
local price = EconomyMath.levelCost(upgrade.baseCost, upgrade.costGrowth, owned)
if EconomyMath.trySpend(session.wallet, { [upgrade.currency] = price }) then
session.levels[upgradeId] = owned + 1
end
end)
trySpend会在扣除任何货币前检查多货币费用中的每一种货币,并拒绝负数或非有限值费用。- 由服务端处理重生:将服务端余额与要求进行比较,然后重置钱包和等级并增加重生次数。绝不接受来自客户端的“我已重生”或余额。
- 使用令牌桶为每位玩家的每个远程事件设置速率限制(
roblox-networking)。
存档数据和离线时间
- 加载时修复;绝不报错。 使用
sanitizeAmount(非数字、NaN、无穷大和负数均变为 0;小数向下取整)和sanitizeLevel(还会限制到当前的maxLevel)。丢弃未知升级 ID,并返回已修复内容的列表,以便旧版本和经过编辑的数据也能正常加载。 - 绝不保存 NaN 或无穷大。 若除以零的结果进入钱包,应由同一套清理函数在保存前捕获。
- 离线时间只能来自服务端时钟:玩家离开时由服务端保存
os.time();玩家加入时计算away = os.time() - lastSeen。缺少lastSeen或其时间在未来时,均按当前时间处理,不发放收益。 - 精度: Luau 数字是双精度数,可精确表示最大为
2^53(约9e15)的整数。如果余额可能超过约1e15,请改用尾数/指数对或以 10 为底的对数存储。
大数显示
EconomyMath.formatNumber(value, decimals?) 使用后缀 K、M、B、T、Qa、Qi、Sx、Sp、Oc、No、Dc、Ud、Dd、Td、Qad、Qid、Sxd、Spd、Ocd、Nod、Vg(1e63),之后使用科学计数法。
- 进位错误:
999950 / 1000 = 999.95,四舍五入后会变成"1000.0K"。先四舍五入;如果舍入后的值达到 1000,就切换到下一个后缀("1.0M")。测试覆盖了这种情况。 - 仅在客户端格式化显示;绝不要将格式化后的字符串解析回数字。
付费随机物品(例如,蛋、箱子、抽奖)
当随机物品通过 Robux 直接购买,或通过用 Robux 购买的游戏内货币购买时,适用 Roblox 的付费随机物品指南。根据该页面:
- 购买前展示所有可能的结果及其实际数值概率,以百分比表示,且总和恰好为 100%(较长的小数可以四舍五入,但需注明显示的总和可能不恰好为 100%)。
- 概率修正因素(例如幸运加成和保底系统)也在适用范围内:购买前以数值说明其效果,并在加成生效期间实时更新显示的概率。
- 如果完整列表无法全部显示,应通过购买前可见且标有“信息”或“详情”的控件打开列表;只有“(i)”图标而没有文字并不足够。
PolicyService:GetPolicyInfoForPlayerAsync()会返回ArePaidRandomItemsRestricted;对于受限制的玩家,请采用该页面列出的其中一种处理方式。
使用 EconomyMath.oddsPercent(outcomes) 构建概率面板,并在服务端使用 EconomyMath.pickWeighted(outcomes, rng:NextNumber()) 从同一份列表中抽取(应用任何加成后),这样显示的概率和实际概率就不会出现偏差。
常见问题
- 第 6 次重生需要数周 →
requirementGrowth远高于乘数的增长;查看vs prev列,并降低requirementGrowth,或改用乘法乘数。 - 升级价格在约 20 级后超过收入 → 对于预期购买 50 次的升级,
costGrowth达到 1.5 以上(50 级价格约为 0 级的 6.37 亿倍);请使用 1.07-1.15。 - 几次重生后,后期游戏失衡 → 使用乘法乘数(
1.5 ^ k),却没有相匹配的需求曲线;让requirementGrowth / q接近你想要的比率。 - 玩家获得了自己并未赚取的货币 → 远程调用接受金额或价格,或者只在客户端检查;发送 ID,在服务端计算价格。
- 两次购买都通过了余额检查 → 处理程序在检查和扣款之间发生了让出;在任何
task.wait、DataStore 调用或其他让出操作之前扣款。 - 最大购买功能导致服务端卡死 → 循环没有上限,或价格为 0;传入
maxLevel,并确保baseCost >= 1(maxAffordable会报错,而不是无限循环)。 - 离线收益相当于数天的收入 → 使用了客户端时间戳、没有上限,或
lastSeen已损坏;使用服务端时钟、设置上限,并将未来时间视为当前时间。 - HUD 显示“1000.0K” → 在选择后缀前使用
math.floor(x * 10) / 10;请使用formatNumber。 - 存档失败或加载出乱码 → NaN 或无穷大进入了钱包;保存前和加载时都要清理数据。
资源
scripts/balance.luau— 节奏计算器:每级价格、总额、收入和等待时间;每次重生的需求、乘数、等待时间和比率;离线收益上限。请先使用--help。scripts/economy_math.luau— 纯 Luau 实现的公式、trySpend、清理函数、概率和formatNumber;可在 Lune 和 Roblox ModuleScript 中运行。scripts/test_economy_math.luau— 每个函数的测试(lune run,失败时退出码为 1)。- references/formulas.md — 推导过程、重生比率和示例。
- references/server-patterns.md — 配置布局、收入计时、最大购买、重生、离线收益加载修复,以及付费随机物品抽取。
相关技能
roblox-luau— 服务、ModuleScript 和客户端/服务端划分。roblox-networking— 远程调用验证和令牌桶速率限制。roblox-datastores— 加载和保存此技能所修复的会话。roblox-ui— 商店、升级和概率面板。roblox-studio-workflow— Server & Clients 游戏测试。
主要参考资料
https://create.roblox.com/docs/production/monetization/paid-random-itemshttps://create.roblox.com/docs/scripting/events/remotehttps://create.roblox.com/docs/scripting/security/client-server-boundaryhttps://create.roblox.com/docs/reference/engine/classes/PolicyServicehttps://create.roblox.com/docs/reference/engine/datatypes/Randomhttps://lune-org.github.io/docs