HarmonyOS应用开发实战:猫猫大作战-指数得分公式的设计


前言
在「猫猫大作战」中,得分公式是整个游戏激励机制的核心。玩家合成的猫咪等级越高,获得的分数越有"爆发感"。如果采用线性增长,高级猫咪的合成动力不足;如果增长太快,低级猫咪就失去意义。最终我们选择了指数增长方案——3^(level-1) × 10,再叠加连击倍率,让每一组合成都充满期待。
本文以 GameEngine.tryMergeAt() 中的得分计算为锚点,讲解指数得分公式的设计思路、数学原理、连击倍率的叠加机制、以及这套公式在游戏平衡性上的考量。
提示:本系列不讲 ArkTS 基础语法与环境搭建,假设你已跟完第 1–128 篇。本篇是阶段四第 129 篇。
一、核心得分公式
1.1 公式定义
// 来源:entry/src/main/ets/components/GameEngine.ets
private calculateMergeScore(catLevel: number, comboMultiplier: number): number {
const baseScore = CatConfig[catLevel].score;
return baseScore * comboMultiplier;
}
CatConfig 中预定义的各等级基础分:
export const CatConfig: Record<CatLevel, CatConfigItem> = {
[CatLevel.SMALL]: { name: '小猫', score: 10, size: 40, color: '#FF9800' },
[CatLevel.MEDIUM]: { name: '中猫', score: 30, size: 50, color: '#F57C00' },
[CatLevel.LARGE]: { name: '大猫', score: 90, size: 60, color: '#E65100' },
[CatLevel.XLARGE]: { name: '特大猫', score: 270, size: 70, color: '#D84315' },
[CatLevel.SUPER]: { name: '超级猫', score: 810, size: 80, color: '#BF360C' },
[CatLevel.LEGENDARY]:{ name: '传奇猫', score: 2430,size: 90, color: '#8E24AA' },
};
1.2 背后的指数公式
// 基础分 = 3^(level-1) × 10
// 其中 level 从 1 开始(SMALL = 1)
const baseScore = Math.pow(3, level - 1) * 10;
| 等级 | level | 公式 | 基础分 | 倍率×2 | 倍率×5 | 倍率×8 |
|---|---|---|---|---|---|---|
| SMALL(1) | 1 | 3^0 × 10 | 10 | 20 | 50 | 80 |
| MEDIUM(2) | 2 | 3^1 × 10 | 30 | 60 | 150 | 240 |
| LARGE(3) | 3 | 3^2 × 10 | 90 | 180 | 450 | 720 |
| XLARGE(4) | 4 | 3^3 × 10 | 270 | 540 | 1350 | 2160 |
| SUPER(5) | 5 | 3^4 × 10 | 810 | 1620 | 4050 | 6480 |
| LEGENDARY(6) | 6 | 3^5 × 10 | 2430 | 4860 | 12150 | 19440 |
提示:
Math.pow(3, level - 1)的底数 3 对应「三只同级合成一只高级」的合并规则。每次合成投入 3 只猫咪,产出 1 只高级猫,得分恰好成指数增长,形成「投入产出比」的正反馈。
二、为什么选择指数增长
2.1 线性 vs 指数对比
// 线性增长方案(已弃用)
const linearScore = 40 * level - 30;
// level 1 → 10, level 2 → 50, level 3 → 90, level 4 → 130...
// 指数增长方案(当前使用)
const expScore = Math.pow(3, level - 1) * 10;
// level 1 → 10, level 2 → 30, level 3 → 90, level 4 → 270...
| level | 线性 (40n-30) | 指数 (3^(n-1)×10) | 差距 |
|---|---|---|---|
| 1 | 10 | 10 | 1x |
| 2 | 50 | 30 | 0.6x |
| 3 | 90 | 90 | 1x |
| 4 | 130 | 270 | 2.1x |
| 5 | 170 | 810 | 4.8x |
| 6 | 210 | 2430 | 11.6x |
关键观察:
- 低等级阶段(1-3)两者差异不大,给新手平滑的学习曲线
- 中等级阶段(4-5)指数开始拉开差距,给中级玩家成就感
- 高等级阶段(6)指数爆发,给核心玩家终极目标
2.2 底数 3 的选择理由
// 底数 2(增长太慢)
Math.pow(2, level - 1) * 10;
// 1→10, 2→20, 3→40, 4→80, 5→160... 传奇猫仅 160 分,缺乏吸引力
// 底数 3(当前选择)
Math.pow(3, level - 1) * 10;
// 1→10, 2→30, 3→90, 4→270, 5→810, 6→2430... 每 3 级 27 倍,正反馈强
// 底数 4(增长太快)
Math.pow(4, level - 1) * 10;
// 1→10, 2→40, 3→160, 4→640, 5→2560... 中猫合成奖励太高,失衡
底数 3 的三重意义:
- 三合一的规则匹配:3 只同级合 1 只→底数为 3→奖励与投入成正比
- 10 倍阈值:玩家从合成传奇猫获得 2430 分 ≈ 243 次小猫合并,成就感强
- 分段增速:低等级平缓,高等级爆发,形成「前期攒资源、后期冲高分」的策略节奏
三、连击倍率系统
3.1 连击机制
// 来源:GameEngine.ets — combo 状态管理
interface ComboInfo {
count: number; // 连击次数
multiplier: number; // 当前倍率
lastMergeTime: number; // 上次合并时间戳(ms)
}
private onMerge(x: number, y: number): void {
const now = Date.now();
const comboWindow = 2000; // 2 秒内连续合并算连击
if (now - this.combo.lastMergeTime < comboWindow) {
// 连击递增
this.combo.count++;
this.combo.multiplier = Math.min(this.combo.count, 5); // 最大 5 倍
} else {
// 超时重置
this.combo.count = 1;
this.combo.multiplier = 1;
}
this.combo.lastMergeTime = now;
// 计算本次合并得分
const mergeScore = this.calculateMergeScore(cat.level, this.combo.multiplier);
this.score += mergeScore;
}
3.2 倍率与得分累积
// 连续合并示例
// 时间轴:t=0ms → t=500ms → t=1000ms → t=1500ms → t=3000ms(超时)
// 倍率: 1x → 2x → 3x → 4x → 1x(重置)
// 合并等级不同组合示例:
// 场景:连续 3 次合成小猫(每次间隔 < 2s)
// 第 1 次:基础 10 分 × 1x = 10 分
// 第 2 次:基础 10 分 × 2x = 20 分
// 第 3 次:基础 10 分 × 3x = 30 分
// 总计:60 分 | 无连击:30 分 → 提升 2 倍
// 场景:连续 3 次合成大猫(间隔 < 2s)
// 第 1 次:基础 90 分 × 1x = 90 分
// 第 2 次:基础 90 分 × 2x = 180 分
// 第 3 次:基础 90 分 × 3x = 270 分
// 总计:540 分 | 无连击:270 分 → 提升 2 倍
| 操作 | 连击次数 | 倍率 | 小猫合并 | 大猫合并 | 传奇合并 |
|---|---|---|---|---|---|
| 第 1 次合并 | 1 | 1x | 10 | 90 | 2430 |
| 第 2 次连击 | 2 | 2x | 20 | 180 | 4860 |
| 第 3 次连击 | 3 | 3x | 30 | 270 | 7290 |
| 第 4 次连击 | 4 | 4x | 40 | 360 | 9720 |
| 第 5+ 次连击 | 5 | 5x(最高) | 50 | 450 | 12150 |
提示:连击倍率上限为 5 倍。这是经过测试后确定的平衡值——倍率太高会导致玩家"只堆连击不看等级",太低则连击系统缺乏吸引力。5 倍上限下,一次 5 连击传奇合并可获得 12150 分,占单局总分相当比例。
四、递归合并中的得分累积
4.1 链式合并得分
当一次合并触发递归合并链时,每次合并都单独计算得分:
// 来源:GameEngine.ets — 递归合并链
private tryMergeAt(x: number, y: number): boolean {
const cat = this.board[y][x];
if (!cat || cat.falling) return false;
// 查找相邻同级猫咪
const neighbors = this.findSameLevelNeighbors(x, y, cat.level);
if (neighbors.length < 2) return false;
// 移除 3 只、创建高级猫
this.removeCats([{ x, y }, ...neighbors.slice(0, 2)]);
const newLevel = cat.level + 1;
const newCat = this.createCatAt(x, y, newLevel);
// 得分计算(本轮的连击倍率)
this.score += this.calculateMergeScore(cat.level, this.combo.multiplier);
// 递归检测:新创建的猫是否能继续合并
if (this.tryMergeAt(x, y)) {
// 递归链继续...
}
return true;
}
4.2 链式合并得分示例
初始棋盘:
(2,3): 小猫(Lv.1)
(2,4): 小猫(Lv.1)
(2,5): 小猫(Lv.1)
(2,6): 中猫(Lv.2)
(2,7): 中猫(Lv.2)
步骤 1:投放在 (2,3) 处掉落一个小猫(Lv.1)
→ (2,3) (2,4) (2,5) 三只小猫相邻 → 合并为中猫(Lv.2)
→ 得分: 10 × 1x = 10
步骤 2:新中猫(Lv.2) 与 (2,6) (2,7) 的中猫相邻 → 递归合并
→ 3 只中猫合并为大猫(Lv.3)
→ 得分: 30 × 1x = 30
总得分: 10 + 30 = 40 分
(如果步骤 1→2 在 2 秒内完成,则步骤 2 享受 2x 倍率 = 60 分,总分 70)
五、得分系统的 UI 展示
5.1 实时得分显示
// 来源:entry/src/main/ets/pages/Index.ets
build() {
Column() {
if (this.gameState === GameState.PLAYING) {
GameHUD({
score: this.score,
combo: this.combo,
highScore: this.highScore
})
GameBoard({
cats: this.cats,
onColumnClick: (col) => this.onColumnClick(col)
})
}
}
}
5.2 合并动画时的浮动得分
// 合并时弹出 "+XX" 浮动文字
@Builder
ScorePopup(score: number, multiplier: number) {
Text(`+${score}`)
.fontSize(score > 100 ? 24 : 18)
.fontWeight(FontWeight.Bold)
.fontColor(score > 500 ? '#F39C12' : '#E74C3C')
.transition({ type: TransitionType.Insert, opacity: 0 })
}
// 连击提示
@Builder
ComboBadge(count: number) {
if (count >= 3) {
Text(`${count}x 连击!`)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor('#E74C3C')
.shadow({ radius: 4, color: '#FF6B6B', offsetY: 2 })
}
}
六、得分公式验证
6.1 单元测试
// 得分计算验证
function testScoreFormula() {
// 小猫基础分
assert.strictEqual(
calculateMergeScore(CatLevel.SMALL, 1), 10
);
// 传奇猫基础分
assert.strictEqual(
calculateMergeScore(CatLevel.LEGENDARY, 1), 2430
);
// 5 倍连击
assert.strictEqual(
calculateMergeScore(CatLevel.SUPER, 5), 4050
);
}
6.2 边界情况
| 场景 | 预期行为 | 验证方法 |
|---|---|---|
| 倍率为 0 | 得分为 0 | 实际倍率最小为 1 |
| 倍率超过上限 | 截断到 5x | Math.min(count, 5) |
| 合并等级 0 | 数组越界 | CatConfig 从 level 1 开始 |
| 连击超时 | 重置为 1x | now - last < 2000 判定 |
| 递归合并 | 每次合并独立算分 | 链式回调累积 |
七、游戏平衡性分析
7.1 得分分布模型
单局典型得分分布(假设 3 分钟游戏时长):
合并次数:约 30-50 次
小猫合并占比:60% → 约 300 分
中猫合并占比:20% → 约 180 分
大猫合并占比:12% → 约 324 分
特大猫合并占比:5% → 约 405 分
超级猫合并占比:2% → 约 486 分
传奇猫合并占比:1% → 约 729 分
──────────────────────────
预计单局平均总分:约 2424 分
7.2 刺激玩家策略
- 不要贪快,要贪连击:等连续合并机会比快速投放收益大
- 优先合成高等级:一个传奇猫 (2430) > 243 个小猫 (2430),但节省了大量操作
- 控制节奏:连击窗口 2 秒,规划好再投放
八、其他游戏得分方案参考
| 方案 | 公式 | 特点 | 典型游戏 |
|---|---|---|---|
| 线性 | a × level + b |
可预测、缺惊喜 | 传统消除 |
| 指数(本游戏) | 3^(n-1) × 10 |
越高级越爽 | 猫猫大作战 |
| 斐波那契 | F(n) × k |
自然增长曲线 | 合成类游戏 |
| 对数 | log(n) × k |
等级越高增长越缓 | 放置类游戏 |
提示:指数方案最适合「合并进化」类游戏——合成本身就是指数行为(3 只变 1 只),用指数得分匹配指数合成,玩家直观感受「越合越赚」。
九、性能考量
// Math.pow 的性能在游戏循环中可接受
// 但更好的做法是预计算级别分(已经在 CatConfig 中预定义)
const precomputedScores = [0, 10, 30, 90, 270, 810, 2430];
// 运行时直接查表,避免每次调用 Math.pow
function getBaseScore(level: number): number {
return precomputedScores[level] ?? 0;
}
十、完整代码示例
// GameEngine.ets 中的完整得分逻辑
export class GameEngine {
private score: number = 0;
private combo: ComboInfo = { count: 0, multiplier: 1, lastMergeTime: 0 };
private readonly COMBO_WINDOW = 2000; // 2s 连击窗口
private readonly MAX_MULTIPLIER = 5; // 最高 5 倍
private calculateMergeScore(catLevel: number, comboMultiplier: number): number {
return CatConfig[catLevel].score * comboMultiplier;
}
private updateCombo(): void {
const now = Date.now();
if (now - this.combo.lastMergeTime < this.COMBO_WINDOW) {
this.combo.count++;
this.combo.multiplier = Math.min(this.combo.count, this.MAX_MULTIPLIER);
} else {
this.combo.count = 1;
this.combo.multiplier = 1;
}
this.combo.lastMergeTime = now;
}
tryMergeAt(x: number, y: number): boolean {
// ... 合并逻辑 ...
this.updateCombo();
this.score += this.calculateMergeScore(cat.level, this.combo.multiplier);
// ... 递归合并 ...
}
getScore(): number { return this.score; }
getCombo(): ComboInfo { return { ...this.combo }; }
resetScore(): void {
this.score = 0;
this.combo = { count: 0, multiplier: 1, lastMergeTime: 0 };
}
}
总结
「猫猫大作战」的得分公式 3^(level-1) × 10 采用指数增长 + 连击倍率双重机制。指数增长与三合一规则匹配,让高级合成收益远超低级;连击倍率(上限 5 倍)激励玩家连续操作,形成紧张的策略节奏。核心要点:Math.pow(3, level-1) 底数 3 对应三合一规则、 连击 2 秒窗口 + 倍率上限 5 防失衡、 递归链每次合并独立算分累积、 预计算查表优于运行时 Math.pow。
下一篇将深入循环合并链——while merged 连锁反应实现级联消除。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
更多推荐


所有评论(0)