文章配图:指数得分公式的设计

页面预览

前言

在「猫猫大作战」中,得分公式是整个游戏激励机制的核心。玩家合成的猫咪等级越高,获得的分数越有"爆发感"。如果采用线性增长,高级猫咪的合成动力不足;如果增长太快,低级猫咪就失去意义。最终我们选择了指数增长方案——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. 低等级阶段(1-3)两者差异不大,给新手平滑的学习曲线
  2. 中等级阶段(4-5)指数开始拉开差距,给中级玩家成就感
  3. 高等级阶段(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 的三重意义

  1. 三合一的规则匹配:3 只同级合 1 只→底数为 3→奖励与投入成正比
  2. 10 倍阈值:玩家从合成传奇猫获得 2430 分 ≈ 243 次小猫合并,成就感强
  3. 分段增速:低等级平缓,高等级爆发,形成「前期攒资源、后期冲高分」的策略节奏

三、连击倍率系统

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 刺激玩家策略

  1. 不要贪快,要贪连击:等连续合并机会比快速投放收益大
  2. 优先合成高等级:一个传奇猫 (2430) > 243 个小猫 (2430),但节省了大量操作
  3. 控制节奏:连击窗口 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 连锁反应实现级联消除。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐