下载 App

分析排行榜技术

09/0451 浏览开发交流
排行榜这个坑我以前遇到过,ai也会遇到,下面贴出代码,直接让ai严格按代码配置,保准成功。

修仙榜 · 代码与配置提取

本文件将「修仙排行榜」功能相关的全部代码与配置从项目各 lua 文件中单独提取汇总,便于集中查看与维护。 原始来源:scripts/LeaderboardSystem.lua(核心系统)、scripts/main.lua(提交集成)、scripts/Views/CultivationView.lua(UI 弹窗)、scripts/GameState.lua(数据字段)。
注意:本文件为代码摘录副本,运行时仍以 scripts/ 下的源文件为准。
horizontal linehorizontal line

一、配置项总览

配置项说明来源
综合分数键 SCORE_KEY"cult_rank_score"排行榜主排序键LeaderboardSystem.lua
境界ID附加键 REALM_KEY"cult_realm_id"展示用附加字段LeaderboardSystem.lua
境界小阶附加键 STAGE_KEY"cult_realm_stage"展示用附加字段LeaderboardSystem.lua
提交冷却 SUBMIT_COOLDOWN30(秒)最低 30 秒提交一次,避免频繁写入LeaderboardSystem.lua
主循环定期提交间隔300(秒 = 5 分钟)main.lua 计时器main.lua
分数公式score = realm * 100000000 + spiritrealm(1-10) 主排序,spirit 次排序;上限约 1.025B,适配 32 位整数LeaderboardSystem.lua
前三名称号#1 仙尊 / #2 仙帝 / #3 仙王由排名返回称号LeaderboardSystem.lua
昵称默认值"隐世修士"昵称查询失败时使用LeaderboardSystem.lua
排行榜拉取条数50(默认 topN)GetRankList(50, ...)CultivationView.lua
horizontal linehorizontal line

二、核心系统源码 — scripts/LeaderboardSystem.lua

lua
-- ============================================================================ -- LeaderboardSystem.lua - 官方排行榜系统 (clientCloud) -- ---------------------------------------------------------------------------- -- 职责: -- 1. 提交综合分数 (境界 × 100M + 修为) -- 2. 查询排行榜列表 (带昵称) -- 3. 查询我的排名 -- 4. 查询排行榜总人数 -- -- 分数公式: score = realm * 100000000 + spirit -- - realm (1-10) 为主排序键, 确保境界高的玩家始终排在前面 -- - spirit 为次排序键, 同境界内修为高的排在前面 -- - 最大值约 10*100M + 25M = 1.025B, 适配 32 位整数 -- -- 前三名称号: -- #1 仙尊 #2 仙帝 #3 仙王 -- ============================================================================ local LeaderboardSystem = {} -- 排行榜 iscore key local SCORE_KEY = "cult_rank_score" -- 综合分数 (主排序) local STAGE_KEY = "cult_realm_stage" -- 境界小阶 (附加字段, 用于显示) local REALM_KEY = "cult_realm_id" -- 境界ID (附加字段, 用于显示) -- 提交节流 (避免频繁写入, 最低 30 秒一次) local lastSubmitTime_ = 0 local SUBMIT_COOLDOWN = 30 -- ============================================================================ -- 1. 计算综合分数 -- ============================================================================ function LeaderboardSystem.CalculateScore() local GameState = require("scripts.GameState") local realm = GameState.data.realm or 1 local spirit = GameState.data.spirit or 0 return realm * 100000000 + spirit end -- ============================================================================ -- 2. 提交分数 -- ============================================================================ -- 提交综合分数到云端 (带节流, 默认 30 秒冷却) -- @param force boolean 强制提交 (忽略冷却) function LeaderboardSystem.SubmitScore(force) -- 节流检查 local now = os.time() if not force and (now - lastSubmitTime_) < SUBMIT_COOLDOWN then return end lastSubmitTime_ = now local GameState = require("scripts.GameState") local score = LeaderboardSystem.CalculateScore() local realm = GameState.data.realm or 1 local stage = GameState.data.realmStage or 1 -- 批量写入: 综合分数 + 境界ID + 境界小阶 clientCloud:BatchSet() :SetInt(SCORE_KEY, score) :SetInt(REALM_KEY, realm) :SetInt(STAGE_KEY, stage) :Save("提交修仙排行", { ok = function() print("[LeaderboardSystem] 提交分数成功: score=" .. score .. " realm=" .. realm .. " stage=" .. stage) end, error = function(code, reason) print("[LeaderboardSystem] 提交分数失败: code=" .. tostring(code) .. " reason=" .. tostring(reason)) end }) end -- ============================================================================ -- 3. 查询排行榜列表 -- ============================================================================ -- 获取排行榜列表 (带昵称) -- @param topN number 获取前 N 名 (默认 50) -- @param callback function 回调, 参数: leaderboard (数组), total (总人数) -- leaderboard[i] = { rank, userId, nickname, score, realm, stage, isMe } function LeaderboardSystem.GetRankList(topN, callback) topN = topN or 50 clientCloud:GetRankList(SCORE_KEY, 0, topN, { ok = function(rankList) local leaderboard = {} local userIds = {} for i, item in ipairs(rankList) do local score = item.iscore[SCORE_KEY] or 0 local realm = item.iscore[REALM_KEY] or 1 local stage = item.iscore[STAGE_KEY] or 1 leaderboard[#leaderboard + 1] = { rank = i, userId = item.userId, nickname = nil, score = score, realm = realm, stage = stage, isMe = item.userId == clientCloud.userId, } userIds[#userIds + 1] = item.userId end -- 无数据, 直接回调 if #userIds == 0 then if callback then callback(leaderboard, 0) end return end -- 查询总人数 LeaderboardSystem.GetRankTotal(function(total) -- 查询昵称 GetUserNickname({ userIds = userIds, onSuccess = function(nicknames) local map = {} for _, info in ipairs(nicknames) do map[info.userId] = info.nickname or "" end for _, entry in ipairs(leaderboard) do entry.nickname = map[entry.userId] or "隐世修士" end if callback then callback(leaderboard, total or 0) end end, onError = function(errorCode) -- 昵称查询失败, 仍返回排行榜 (昵称用默认值) for _, entry in ipairs(leaderboard) do entry.nickname = "隐世修士" end if callback then callback(leaderboard, total or 0) end end }) end) end, error = function(code, reason) print("[LeaderboardSystem] 获取排行榜失败: code=" .. tostring(code) .. " reason=" .. tostring(reason)) if callback then callback({}, 0) end end }, STAGE_KEY, REALM_KEY) -- 附加字段: 同时获取 stage 和 realm end -- ============================================================================ -- 4. 查询我的排名 -- ============================================================================ function LeaderboardSystem.GetMyRank(callback) clientCloud:GetUserRank(clientCloud.userId, SCORE_KEY, { ok = function(rank, scoreValue) if callback then callback(rank, scoreValue or 0) end end, error = function(code, reason) print("[LeaderboardSystem] 获取我的排名失败: code=" .. tostring(code) .. " reason=" .. tostring(reason)) if callback then callback(nil, 0) end end }) end -- ============================================================================ -- 5. 查询排行榜总人数 -- ============================================================================ function LeaderboardSystem.GetRankTotal(callback) clientCloud:GetRankTotal(SCORE_KEY, { ok = function(total) if callback then callback(total or 0) end end, error = function(code, reason) print("[LeaderboardSystem] 获取总人数失败: code=" .. tostring(code) .. " reason=" .. tostring(reason)) if callback then callback(0) end end }) end -- ============================================================================ -- 6. 前三名称号 -- ============================================================================ local TOP_TITLES = { [1] = "仙尊", [2] = "仙帝", [3] = "仙王", } function LeaderboardSystem.GetTitle(rank) return TOP_TITLES[rank] end -- ============================================================================ -- 7. 格式化分数为显示文本 -- ============================================================================ -- 从综合分数中解析出境界ID和修为 function LeaderboardSystem.ParseScore(score) if not score or score <= 0 then return 1, 0 end local realm = math.floor(score / 100000000) local spirit = score % 100000000 return realm, spirit end return LeaderboardSystem
horizontal linehorizontal line

三、依赖的数据字段 — scripts/GameState.lua

排行榜分数依赖以下玩家存档字段:
lua
-- 修仙榜相关字段 (GameState.data) realm = 1, -- 当前境界 ID (1-10), 决定分数主排序 realmStage = 1, -- 境界小阶 (1-4), 展示用附加字段 spirit = 0, -- 修为, 决定分数次排序 (上限约 2500万)
境界名称展示通过 Config.GetRealmName(realmId, stage)scripts/GameConfig.lua)转换。
horizontal linehorizontal line

四、主循环集成 — scripts/main.lua

1) 提交计时器声明(第 49 行)

lua
local leaderboardSubmitTimer_ = 0 -- 排行榜提交计时器

2) 初始化完成后首次提交(第 349-351 行)

lua
-- 初始化完成后提交一次排行榜分数 local LeaderboardSystem = require("scripts.LeaderboardSystem") LeaderboardSystem.SubmitScore(true)

3) 小阶提升后强制提交(第 495-498 行)

lua
-- 小阶提升后提交排行榜分数 local LeaderboardSystem = require("scripts.LeaderboardSystem") LeaderboardSystem.SubmitScore(true)

4) 定期提交(每 5 分钟,第 500-506 行)

lua
-- 排行榜定期提交 (每 5 分钟) leaderboardSubmitTimer_ = leaderboardSubmitTimer_ + timeStep if leaderboardSubmitTimer_ >= 300 then leaderboardSubmitTimer_ = 0 local LeaderboardSystem = require("scripts.LeaderboardSystem") LeaderboardSystem.SubmitScore() end
horizontal linehorizontal line

五、UI 实现 — scripts/Views/CultivationView.lua

1) 境界区「修仙排行榜」入口按钮(第 81-92 行)

lua
-- 排行榜入口 (境界名称后) UI.Button { text = "修仙排行榜", variant = "secondary", fontSize = 12, height = 28, borderRadius = 14, fontColor = C.accentGold, onClick = function(self) CultivationView.ShowLeaderboard() end, },

2) 排行榜弹窗布局(第 379-491 行)

lua
-- 排行榜弹窗 UI.Panel { id = "leaderboardModal", position = "absolute", top = 0, left = 0, right = 0, bottom = 0, justifyContent = "center", alignItems = "center", backgroundColor = { 0, 0, 0, 160 }, visible = false, children = { UI.Panel { width = "92%", maxWidth = 400, maxHeight = "85%", flexDirection = "column", gap = 8, padding = 16, backgroundColor = C.bgPanel, borderRadius = 16, borderWidth = 2, borderColor = C.accentGold, children = { -- 标题栏 UI.Panel { width = "100%", flexDirection = "row", justifyContent = "space-between", alignItems = "center", children = { UI.Label { text = "修仙排行榜", fontSize = 18, fontWeight = "bold", fontColor = C.accentGold, }, UI.Button { text = "✕", variant = "secondary", fontSize = 16, width = 36, height = 36, borderRadius = 18, fontColor = C.textGray, onClick = function(self) CultivationView.HideLeaderboard() end, }, } }, -- 副标题: 按境界与修为综合排名 UI.Label { text = "综合境界与修为, 前三名获赐称号", fontSize = 11, fontColor = C.textDim, textAlign = "center", width = "100%", }, -- 排行榜列表 (ScrollView) UI.ScrollView { id = "leaderboardList", width = "100%", flexGrow = 1, flexBasis = 0, gap = 4, scrollY = true, children = { UI.Label { text = "加载中...", fontSize = 13, fontColor = C.textGray, textAlign = "center", width = "100%", marginTop = 20, }, } }, -- 我的排名 UI.Panel { id = "myRankRow", width = "100%", padding = 10, backgroundColor = C.bgDark, borderRadius = 8, borderWidth = 1, borderColor = C.accentGold, visible = false, children = { UI.Label { id = "myRankLabel", text = "", fontSize = 13, fontWeight = "bold", fontColor = C.accentGold, textAlign = "center", width = "100%", }, } }, -- 刷新按钮 UI.Button { text = "刷新排行榜", variant = "primary", fontSize = 13, height = 36, borderRadius = 18, onClick = function(self) CultivationView.RefreshLeaderboard() end, }, } } } },

3) 弹窗控制与数据刷新(第 977-1028 行)

lua
-- 显示排行榜弹窗 function CultivationView.ShowLeaderboard() AudioManager.PlaySFX("click") local modal = Shared.uiRoot:FindById("leaderboardModal") if modal then modal:SetVisible(true) end CultivationView.RefreshLeaderboard() end -- 隐藏排行榜弹窗 function CultivationView.HideLeaderboard() local modal = Shared.uiRoot:FindById("leaderboardModal") if modal then modal:SetVisible(false) end end -- 刷新排行榜数据 function CultivationView.RefreshLeaderboard() local LeaderboardSystem = require("scripts.LeaderboardSystem") local C = Shared.C -- 显示加载中 local list = Shared.uiRoot:FindById("leaderboardList") local myRankRow = Shared.uiRoot:FindById("myRankRow") if list then list:ClearChildren() list:AddChild(UI.Label { text = "加载中...", fontSize = 13, fontColor = C.textGray, textAlign = "center", width = "100%", marginTop = 20, }) end if myRankRow then myRankRow:SetVisible(false) end -- 先提交一次分数 (确保自己上榜) LeaderboardSystem.SubmitScore(true) -- 拉取排行榜 LeaderboardSystem.GetRankList(50, function(leaderboard, total) CultivationView.RenderLeaderboard(leaderboard, total) end) -- 拉取我的排名 LeaderboardSystem.GetMyRank(function(rank, scoreValue) if myRankRow and rank then myRankRow:SetVisible(true) local myRankLabel = Shared.uiRoot:FindById("myRankLabel") if myRankLabel then local realmName = Config.GetRealmName(GameState.data.realm, GameState.data.realmStage) myRankLabel:SetText(string.format("我的排名: #%d %s 修为:%d", rank, realmName, GameState.data.spirit)) end end end) end

4) 列表渲染(第 1030-1122 行)

lua
-- 渲染排行榜列表 function CultivationView.RenderLeaderboard(leaderboard, total) local C = Shared.C local Config = require("scripts.GameConfig") local LeaderboardSystem = require("scripts.LeaderboardSystem") local list = Shared.uiRoot:FindById("leaderboardList") if not list then return end list:ClearChildren() if #leaderboard == 0 then list:AddChild(UI.Label { text = "暂无上榜修士\n快来成为第一人!", fontSize = 14, fontColor = C.textGray, textAlign = "center", width = "100%", marginTop = 30, }) return end -- 总人数提示 list:AddChild(UI.Label { text = "共 " .. total .. " 名修士上榜", fontSize = 11, fontColor = C.textDim, textAlign = "center", width = "100%", marginBottom = 4, }) -- 前三名称号颜色 local titleColors = { [1] = { 255, 215, 0, 255 }, -- 金 [2] = { 192, 192, 192, 255 }, -- 银 [3] = { 205, 127, 50, 255 }, -- 铜 } for _, entry in ipairs(leaderboard) do local realmName = Config.GetRealmName(entry.realm, entry.stage) local title = LeaderboardSystem.GetTitle(entry.rank) local rankColor = titleColors[entry.rank] or C.textWhite local isMe = entry.isMe -- 排名 + 称号 (前三名) local rankText = "#" .. entry.rank if title then rankText = "#" .. entry.rank .. " " .. title end list:AddChild(UI.Panel { width = "100%", flexDirection = "row", alignItems = "center", padding = 8, gap = 8, backgroundColor = isMe and { 60, 50, 30, 120 } or { 30, 28, 24, 80 }, borderRadius = 8, borderWidth = isMe and 1 or 0, borderColor = isMe and C.accentGold or nil, children = { -- 排名 UI.Label { text = rankText, fontSize = 12, fontWeight = "bold", fontColor = rankColor, width = 60, flexShrink = 0, }, -- 昵称 UI.Label { text = entry.nickname or "隐世修士", fontSize = 13, fontColor = isMe and C.accentGold or C.textWhite, flexGrow = 1, flexShrink = 1, minWidth = 0, overflow = "hidden", }, -- 境界 UI.Label { text = realmName, fontSize = 11, fontColor = C.accentQing, flexShrink = 0, }, -- 修为 UI.Label { text = tostring(entry.score % 100000000), fontSize = 11, fontColor = C.textGray, flexShrink = 0, }, } }) end end
horizontal linehorizontal line

六、调用关系图(文字)

main.lua (Start/Update 主循环)
  └─ LeaderboardSystem.SubmitScore(force)
        ├─ CalculateScore()  →  realm*100000000 + spirit
        └─ clientCloud:BatchSet() → 写入 cult_rank_score / cult_realm_id / cult_realm_stage

CultivationView.lua
  ├─ 入口按钮 "修仙排行榜"  →  ShowLeaderboard()
  ├─ ShowLeaderboard()      →  RefreshLeaderboard()
  ├─ RefreshLeaderboard()   →  SubmitScore(true) + GetRankList(50,...) + GetMyRank(...)
  └─ RenderLeaderboard()    →  渲染列表 (称号/境界/修为)

LeaderboardSystem.lua (clientCloud 云榜)
  ├─ CalculateScore()
  ├─ SubmitScore(force)
  ├─ GetRankList(topN, cb)   →  GetRankTotal + GetUserNickname
  ├─ GetMyRank(cb) / GetRankTotal(cb)
  └─ GetTitle(rank) / ParseScore(score)
horizontal linehorizontal line
提取时间:2026-07-24 | 源文件以 scripts/ 下为准
别再烧积分了!从每次 2000 到每次 50 的血泪经验截图
别再烧积分了!从每次 2000 到每次 50 的血泪经验
适用场景:所有在用 TapTap Code 开发游戏的小白 难度:★☆☆☆☆ 背景最近群里总有人"炫耀"一次操作花了几千积分,说实话这不是值得高兴的事——这是在告诉所有人你的开发方式有根本性问题。我也走过这条弯路,所以来说说怎么改。 积分消耗的本质是什么积分 = AI 处理的 token 数量 = 你发给 AI 的内容 + AI 回给你的内容所以烧积分的本质只有两种: 你让 AI 做了大量无效/重
精华
67 赞
20 回复
开发心得-界面布局心得截图
开发心得-界面布局心得
大家好,我正在用 TapTap 制造制作一款2D 治愈林间徒步旅行游戏《徒步荒野》。 我分享一下我的开发心得,希望能有用,下面是一些界面布局的心得。 第一步:定版式、操作 先确定游戏是横版还是竖版、需要哪些操作按钮,敲定整体玩法思路。 我的玩法灵感参考《边境之旅》,主打散步看风景、沿途触发随机事件。 原版是 3D,考虑到自己是新手,选择2D 横版街机式来做,制作更简单、好上手。 第二步:敲定全局美
6 赞
3 回复
如何提升你游戏中的UI美术水平截图
如何提升你游戏中的UI美术水平
一、请为你的游戏挑选一款合适的字体 很多开发者没有注意到其实UI界面中最重要的元素是字体,一款合适的字体能给整个游戏的界面感官带来蜕变。 请看案例 那么如何挑选适合自己的字体呢? 我总结出了一些小经验可供参考: 黑体:通用 宋体:古风、武侠、修仙 楷体:古风、武侠、修仙 圆体:卡通、动漫、Q版 科技:科幻、未来、电子 顺手分享一个免费可商用字体网站: 当然 如果你不知道自己的游戏适合什么风格
精华
122 赞
44 回复
2D 等轴测视角:完整理论截图
2D 等轴测视角:完整理论
2D 等轴测视角:完整理论 一、视角的本质 什么是等轴测 人站在高处斜着往下看地面,地面上的方格子不再是正方形,而变成了菱形。这就是等轴测的视觉本质。 俯视(正上方看下去): 等轴测(斜上方看下去): ┌──┬──┬──┐ ◇ ├──┼──┼──┤ ◇ ◇ ├──┼──┼──┤ ◇ ◇ ◇ └──┴──┴──┘ ◇ ◇ ◇ 正方形网格经过旋转 + 压缩,变成了菱形网格。 为什么是 2:1
6 赞
一个类LOL带有合成树的装备商店系统文档截图
一个类LOL带有合成树的装备商店系统文档
可复用于其他需要类似功能的项目,减少沟通的积分消耗,分享给大家: 1. 整体架构equip_defs.lua 数据层 — 装备定义、合成配方、价格、属性、工具函数 equip_shop.lua UI 层 — NanoVG 渲染、交互逻辑、合成树可视化 2.2 装备分类类型值名称说明1武器—2衣甲—3头盔—4腰带—5靴子—6项链—7戒指—8饰品—2.3 阶级体系阶级颜色说明T1灰白 (180,180
精华
6 赞
2 回复
关于制作出质量很高的横版战斗角色的方法截图
关于制作出质量很高的横版战斗角色的方法
其实全篇就一句话,角色为啥做起来这么好看,因为我一帧一帧K的。 在做角色之前,我们需要一个角色的设计稿,这个东西很简单,你把人设写好剩下的交给AI就行了,所有图片,序列帧都可以让AI绘制和处理,学会绘图是你要制作高质量游戏的第一课。 这里拿我在做的角色举例,他的参考图是这样: 当你拥有了一个角色以后,就要想办法让她动起来了。 那么如何让她动起来,答案是序列帧。 在此之前你需要知道,最容易出现一个误
40 赞
12 回复
塔拉拉20万分经验分享截图
塔拉拉20万分经验分享
前言 不是教程也不是官方,只是分享一下自己开发过程中遇到的问题和经验。 自上个月拿到资格后,便废寝忘食开始了塔拉拉的无代码做游戏探索,一开始想做一个简单的游戏先试试效果,然后就开始了一个本来是小游戏却消耗近20w分的项目,先说说这其中遇到的问题和积分消耗大户。 一、开始开发 本地新建文件夹,写好你这个游戏的策划案,主文件介绍核心玩法(重中之重)、美术风格,然后分文件介绍游戏中的各种功能/系统,做好
74 赞
19 回复
03:06
为了不被斩杀,我只能做到这些了截图
为了不被斩杀,我只能做到这些了
之前一直申请不到计划3,之前说太花哨,后面说体量完成度不足,在我一番小作文下,编辑终于给了我解答,什么原生质感,玩家开局体验啥的。 本来计划2也够用,准备以后再优化了,结果计划2赠送的积分要砍半了,学生党实在消费不起,于是只能再冲一波计划3了 从周六中午到现在一天半时间,优化了一遍角色卡,战斗卡,还有抽卡界面,优化了新手教程,该说不说确实比之前要舒服些。 前半部分为新版,后半部分为旧版。 明天再次
32 赞
6 回复
UI 组件速查指南-TapMaker大学习截图
UI 组件速查指南-TapMaker大学习
在设计游戏UI的过程中,你是否存在和ai讨论UI设计时AI出现指东打西的红温时刻。本文致力于介绍常见的UI组件,让你在开发过程中可以做到精确制导! 这是一份UI 组件的速查手册。 新手用 AI 做游戏 UI 最大的卡点,不是"AI 写不出来",而是——你说不出那个东西叫什么。 为了让你能准确的说出你需要的组件的名字,我整理出了这篇UI组件指南。 每个组件我都写了三件事:它是什么、它长什么样、它在游
精华
36 赞
6 回复
游戏自荐《少女终焉契约》截图
游戏自荐《少女终焉契约》
之前玩放置类型的rpg游戏的时候我就在想,现在游戏的操作有的太过于繁琐了,有没有一款休闲一点的,想上线就上线,离线的时候角色能自动行动的游戏呢?感谢TapTap制造,我按照我的想法开发出了现在这款游戏。 一、故事背景和UI 游戏的故事背景是传统的异世界穿越故事,玩家被女神召唤到异世界,随后组建工会,招募美少女,打怪升级探索世界。所以我选择了更加二次元萌系画风的UI风格,主页为各个主要的功能,点开来
8 赞
3 回复