在这里插入图片描述

📖 引言

在知识问答学习应用中,成就服务(AchievementService)是激励用户持续学习的核心组件。它负责管理成就的解锁、进度跟踪、奖励发放等关键操作,通过设置各种成就目标,让用户在完成学习任务的同时获得成就感和满足感。

本文将详细讲解 AchievementService 的完整实现,包括成就数据管理、解锁机制、进度跟踪等核心功能。通过本文,你将掌握:

  • 如何设计成就数据管理机制
  • 如何实现成就解锁和进度跟踪
  • 如何计算成就奖励和稀有度
  • 如何在实际项目中管理成就数据

🎯 学习目标

完成本文后,你将能够:

  • ✅ 理解 AchievementService 的核心职责和功能
  • ✅ 实现成就数据的增删改查
  • ✅ 管理成就解锁和进度跟踪
  • ✅ 计算成就奖励和稀有度
  • ✅ 集成成就与用户数据的关联

💡 需求分析

功能模块设计

模块 功能描述 技术要点
成就数据管理 CRUD操作成就数据 数据持久化、缓存
解锁机制 管理成就解锁条件 连续打卡、关卡通关、正确率等
进度跟踪 跟踪用户成就完成进度 当前进度、目标、完成状态
奖励计算 计算成就奖励 积分、经验、徽章
稀有度系统 管理成就稀有度 普通、稀有、史诗、传说

🛠️ 核心实现

步骤1: AchievementService 接口设计

功能说明

定义 AchievementService 的核心接口,规范服务的方法签名和返回类型。

完整代码
// services/interfaces/AchievementServiceInterface.ts

import { ServiceResponse } from './ServiceInterface';
import { Achievement, AchievementProgress } from '../models/Achievement';
import { User } from '../models/User';

/**
 * 成就服务接口
 */
export interface AchievementServiceInterface {
  /**
   * 获取所有成就
   * @returns 成就列表
   */
  getAllAchievements(): ServiceResponse<Achievement[]>;

  /**
   * 根据ID获取成就
   * @param achievementId - 成就ID
   * @returns 成就信息
   */
  getAchievementById(achievementId: string): ServiceResponse<Achievement | undefined>;

  /**
   * 根据类型获取成就
   * @param type - 成就类型
   * @returns 成就列表
   */
  getAchievementsByType(type: string): ServiceResponse<Achievement[]>;

  /**
   * 根据稀有度获取成就
   * @param rarity - 稀有度
   * @returns 成就列表
   */
  getAchievementsByRarity(rarity: string): ServiceResponse<Achievement[]>;

  /**
   * 获取用户已解锁的成就
   * @param user - 用户对象
   * @returns 已解锁成就列表
   */
  getUnlockedAchievements(user: User): ServiceResponse<Achievement[]>;

  /**
   * 获取用户未解锁的成就(带进度)
   * @param user - 用户对象
   * @returns 未解锁成就列表(带进度)
   */
  getLockedAchievements(user: User): ServiceResponse<Array<Achievement & { progress: AchievementProgress }>>;

  /**
   * 获取成就进度
   * @param achievementId - 成就ID
   * @param user - 用户对象
   * @returns 进度信息
   */
  getAchievementProgress(achievementId: string, user: User): ServiceResponse<AchievementProgress>;

  /**
   * 检查并解锁成就
   * @param user - 用户对象
   * @returns 新解锁的成就列表
   */
  checkAndUnlockAchievements(user: User): Promise<ServiceResponse<Achievement[]>>;

  /**
   * 手动解锁成就(管理员功能)
   * @param achievementId - 成就ID
   * @param user - 用户对象
   * @returns 是否成功
   */
  unlockAchievement(achievementId: string, user: User): ServiceResponse<boolean>;

  /**
   * 获取成就奖励
   * @param achievement - 成就对象
   * @returns 奖励信息
   */
  getAchievementReward(achievement: Achievement): ServiceResponse<{ score: number; experience: number }>;

  /**
   * 计算成就完成率
   * @param user - 用户对象
   * @returns 完成率(0-100)
   */
  calculateCompletionRate(user: User): ServiceResponse<number>;

  /**
   * 添加新成就
   * @param achievement - 成就信息
   * @returns 创建的成就
   */
  addAchievement(achievement: Achievement): ServiceResponse<Achievement>;

  /**
   * 更新成就信息
   * @param achievementId - 成就ID
   * @param updates - 更新内容
   * @returns 更新后的成就
   */
  updateAchievement(achievementId: string, updates: Partial<Achievement>): ServiceResponse<Achievement>;

  /**
   * 删除成就
   * @param achievementId - 成就ID
   * @returns 是否成功
   */
  deleteAchievement(achievementId: string): ServiceResponse<boolean>;
}
代码解析

1. 接口方法分类

分类 方法 功能说明
查询 getAllAchievements(), getAchievementById() 获取成就信息
筛选 getAchievementsByType(), getAchievementsByRarity() 按类型/稀有度筛选
用户相关 getUnlockedAchievements(), getLockedAchievements() 获取用户成就状态
进度管理 getAchievementProgress(), checkAndUnlockAchievements() 进度跟踪和解锁
奖励 getAchievementReward() 获取成就奖励
统计 calculateCompletionRate() 计算完成率
数据管理 addAchievement(), updateAchievement(), deleteAchievement() 成就CRUD操作

步骤2: AchievementService 实现

功能说明

实现 AchievementService 的核心逻辑,包括成就数据管理、解锁机制、进度跟踪等功能。

完整代码
// services/AchievementService.ts

import { Singleton } from './base/BaseService';
import { BaseService } from './base/BaseService';
import { ServiceResponse, ServiceError, createSuccessResponse, createErrorResponse } from './interfaces/ServiceInterface';
import { AchievementServiceInterface } from './interfaces/AchievementServiceInterface';
import { Achievement, AchievementType, AchievementProgress, AchievementCondition, AchievementReward, Rarity } from '../models/Achievement';
import { User } from '../models/User';

/**
 * 成就服务实现
 */
@Singleton
export class AchievementService extends BaseService implements AchievementServiceInterface {
  private achievements: Achievement[] = [];

  constructor() {
    super();
    this.initializeAchievements();
  }

  /**
   * 初始化成就数据
   */
  private initializeAchievements(): void {
    this.achievements = this.loadAchievementData();
  }

  /**
   * 加载成就数据(模拟)
   */
  private loadAchievementData(): Achievement[] {
    return [
      // 连续打卡成就
      this.createConsecutiveDaysAchievement(7, Rarity.RARE),
      this.createConsecutiveDaysAchievement(14, Rarity.EPIC),
      this.createConsecutiveDaysAchievement(30, Rarity.LEGENDARY),
      this.createConsecutiveDaysAchievement(7, Rarity.RARE),
      
      // 关卡通关成就
      this.createLevelClearAchievement(5, Rarity.COMMON),
      this.createLevelClearAchievement(10, Rarity.RARE),
      this.createLevelClearAchievement(20, Rarity.EPIC),
      this.createLevelClearAchievement(40, Rarity.LEGENDARY),
      
      // 正确率成就
      this.createAccuracyAchievement(80, Rarity.COMMON),
      this.createAccuracyAchievement(90, Rarity.RARE),
      this.createAccuracyAchievement(95, Rarity.EPIC),
      this.createAccuracyAchievement(100, Rarity.LEGENDARY),
      
      // 答题数量成就
      this.createTotalQuestionsAchievement(100, Rarity.COMMON),
      this.createTotalQuestionsAchievement(500, Rarity.RARE),
      this.createTotalQuestionsAchievement(1000, Rarity.EPIC),
      this.createTotalQuestionsAchievement(5000, Rarity.LEGENDARY),
      
      // 特殊成就
      this.createSpecialAchievement('first_login', '初次见面', '完成首次登录', Rarity.COMMON),
      this.createSpecialAchievement('first_level_clear', '初战告捷', '完成首次关卡通关', Rarity.COMMON),
      this.createSpecialAchievement('first_perfect', '完美主义', '首次获得3星评价', Rarity.RARE),
      this.createSpecialAchievement('all_subjects', '全科达人', '完成所有学科的第一关', Rarity.EPIC)
    ];
  }

  /**
   * 创建连续打卡成就
   */
  private createConsecutiveDaysAchievement(days: number, rarity: Rarity): Achievement {
    const name = days === 7 ? '坚持不懈' : days === 14 ? '两周连胜' : days === 30 ? '月度冠军' : '连续打卡';
    const description = `连续学习${days}`;
    const rewards = this.getRewardsByRarity(rarity);

    return {
      id: `achievement_consecutive_${days}`,
      name,
      description,
      icon: `https://example.com/achievements/consecutive_${days}.png`,
      type: AchievementType.CONSECUTIVE_DAYS,
      condition: { type: 'consecutive_days', target: days },
      reward: rewards,
      rarity
    };
  }

  /**
   * 创建关卡通关成就
   */
  private createLevelClearAchievement(count: number, rarity: Rarity): Achievement {
    const name = count === 5 ? '初露锋芒' : count === 10 ? '渐入佳境' : count === 20 ? '登堂入室' : '通关大师';
    const description = `累计通关${count}个关卡`;
    const rewards = this.getRewardsByRarity(rarity);

    return {
      id: `achievement_level_clear_${count}`,
      name,
      description,
      icon: `https://example.com/achievements/level_clear_${count}.png`,
      type: AchievementType.LEVEL_CLEAR,
      condition: { type: 'level_clear', target: count },
      reward: rewards,
      rarity
    };
  }

  /**
   * 创建正确率成就
   */
  private createAccuracyAchievement(accuracy: number, rarity: Rarity): Achievement {
    const name = accuracy === 80 ? '百发百中' : accuracy === 90 ? '精准射手' : accuracy === 95 ? '神枪手' : '完美无缺';
    const description = `单次测验正确率达到${accuracy}%`;
    const rewards = this.getRewardsByRarity(rarity);

    return {
      id: `achievement_accuracy_${accuracy}`,
      name,
      description,
      icon: `https://example.com/achievements/accuracy_${accuracy}.png`,
      type: AchievementType.ACCURACY,
      condition: { type: 'accuracy', target: accuracy },
      reward: rewards,
      rarity
    };
  }

  /**
   * 创建答题数量成就
   */
  private createTotalQuestionsAchievement(count: number, rarity: Rarity): Achievement {
    const name = count === 100 ? '答题新手' : count === 500 ? '答题能手' : count === 1000 ? '答题高手' : '答题大师';
    const description = `累计答题${count}`;
    const rewards = this.getRewardsByRarity(rarity);

    return {
      id: `achievement_questions_${count}`,
      name,
      description,
      icon: `https://example.com/achievements/questions_${count}.png`,
      type: AchievementType.TOTAL_QUESTIONS,
      condition: { type: 'total_questions', target: count },
      reward: rewards,
      rarity
    };
  }

  /**
   * 创建特殊成就
   */
  private createSpecialAchievement(type: string, name: string, description: string, rarity: Rarity): Achievement {
    const rewards = this.getRewardsByRarity(rarity);

    return {
      id: `achievement_${type}`,
      name,
      description,
      icon: `https://example.com/achievements/${type}.png`,
      type: AchievementType.SPECIAL,
      condition: { type, target: 1 },
      reward: rewards,
      rarity
    };
  }

  /**
   * 根据稀有度获取奖励
   */
  private getRewardsByRarity(rarity: Rarity): AchievementReward {
    const baseRewards: Record<Rarity, AchievementReward> = {
      [Rarity.COMMON]: { score: 50, experience: 25, badge: '' },
      [Rarity.RARE]: { score: 100, experience: 50, badge: '' },
      [Rarity.EPIC]: { score: 200, experience: 100, badge: '' },
      [Rarity.LEGENDARY]: { score: 500, experience: 250, badge: '' }
    };
    return baseRewards[rarity];
  }

  /**
   * 获取所有成就
   */
  getAllAchievements(): ServiceResponse<Achievement[]> {
    return createSuccessResponse<Achievement[]>(this.achievements);
  }

  /**
   * 根据ID获取成就
   */
  getAchievementById(achievementId: string): ServiceResponse<Achievement | undefined> {
    const achievement = this.achievements.find(a => a.id === achievementId);
    return createSuccessResponse<Achievement | undefined>(achievement);
  }

  /**
   * 根据类型获取成就
   */
  getAchievementsByType(type: string): ServiceResponse<Achievement[]> {
    const filtered = this.achievements.filter(a => a.type === type);
    return createSuccessResponse<Achievement[]>(filtered);
  }

  /**
   * 根据稀有度获取成就
   */
  getAchievementsByRarity(rarity: string): ServiceResponse<Achievement[]> {
    const filtered = this.achievements.filter(a => a.rarity === rarity);
    return createSuccessResponse<Achievement[]>(filtered);
  }

  /**
   * 获取用户已解锁的成就
   */
  getUnlockedAchievements(user: User): ServiceResponse<Achievement[]> {
    const unlocked = this.achievements.filter(a => user.achievements.includes(a.id));
    return createSuccessResponse<Achievement[]>(unlocked);
  }

  /**
   * 获取用户未解锁的成就(带进度)
   */
  getLockedAchievements(user: User): ServiceResponse<Array<Achievement & { progress: AchievementProgress }>> {
    const locked = this.achievements
      .filter(a => !user.achievements.includes(a.id))
      .map(a => ({
        ...a,
        progress: this.calculateProgress(user, a)
      }));
    return createSuccessResponse<Array<Achievement & { progress: AchievementProgress }>>(locked);
  }

  /**
   * 获取成就进度
   */
  getAchievementProgress(achievementId: string, user: User): ServiceResponse<AchievementProgress> {
    const achievement = this.achievements.find(a => a.id === achievementId);
    if (!achievement) {
      return createErrorResponse<AchievementProgress>(ServiceError.NOT_FOUND, '成就不存在');
    }

    const progress = this.calculateProgress(user, achievement);
    return createSuccessResponse<AchievementProgress>(progress);
  }

  /**
   * 计算成就进度
   */
  private calculateProgress(user: User, achievement: Achievement): AchievementProgress {
    let current = 0;
    const target = achievement.condition.target;

    switch (achievement.type) {
      case AchievementType.CONSECUTIVE_DAYS:
        current = user.consecutiveDays;
        break;

      case AchievementType.LEVEL_CLEAR:
        current = user.completedLevels.length;
        break;

      case AchievementType.ACCURACY:
        current = Math.round(user.statistics.averageAccuracy * 100);
        break;

      case AchievementType.TOTAL_QUESTIONS:
        current = user.statistics.totalQuestions;
        break;

      case AchievementType.SPECIAL:
        current = this.calculateSpecialProgress(user, achievement);
        break;
    }

    current = Math.min(current, target);

    return {
      achievementId: achievement.id,
      current,
      target,
      isCompleted: current >= target
    };
  }

  /**
   * 计算特殊成就进度
   */
  private calculateSpecialProgress(user: User, achievement: Achievement): number {
    const conditionType = achievement.condition.type;

    switch (conditionType) {
      case 'first_login':
        return user.createdAt ? 1 : 0;

      case 'first_level_clear':
        return user.completedLevels.length > 0 ? 1 : 0;

      case 'first_perfect':
        return Array.from(user.levelStars.values()).some(stars => stars === 3) ? 1 : 0;

      case 'all_subjects':
        // 检查是否完成所有学科的第一关
        const subjects = ['math', 'geography', 'life', 'literature', 'sports'];
        const completedAllFirstLevels = subjects.every(subject => 
          user.completedLevels.includes(`${subject}_level_1`)
        );
        return completedAllFirstLevels ? 1 : 0;

      default:
        return 0;
    }
  }

  /**
   * 检查并解锁成就
   */
  async checkAndUnlockAchievements(user: User): Promise<ServiceResponse<Achievement[]>> {
    const unlocked: Achievement[] = [];

    for (const achievement of this.achievements) {
      // 跳过已解锁的成就
      if (user.achievements.includes(achievement.id)) {
        continue;
      }

      // 检查是否满足解锁条件
      const progress = this.calculateProgress(user, achievement);
      if (progress.isCompleted) {
        unlocked.push(achievement);
        user.achievements.push(achievement.id);

        // 发放奖励
        const reward = this.getAchievementReward(achievement).data;
        if (reward) {
          user.totalScore += reward.score;
          user.totalExperience += reward.experience;
        }
      }
    }

    return createSuccessResponse<Achievement[]>(unlocked);
  }

  /**
   * 手动解锁成就
   */
  unlockAchievement(achievementId: string, user: User): ServiceResponse<boolean> {
    const achievement = this.achievements.find(a => a.id === achievementId);
    if (!achievement) {
      return createErrorResponse<boolean>(ServiceError.NOT_FOUND, '成就不存在');
    }

    // 检查是否已解锁
    if (user.achievements.includes(achievementId)) {
      return createErrorResponse<boolean>(ServiceError.CONFLICT, '成就已解锁');
    }

    // 解锁成就
    user.achievements.push(achievementId);

    // 发放奖励
    const reward = this.getAchievementReward(achievement).data;
    if (reward) {
      user.totalScore += reward.score;
      user.totalExperience += reward.experience;
    }

    return createSuccessResponse<boolean>(true);
  }

  /**
   * 获取成就奖励
   */
  getAchievementReward(achievement: Achievement): ServiceResponse<{ score: number; experience: number }> {
    return createSuccessResponse<{ score: number; experience: number }>({
      score: achievement.reward.score,
      experience: achievement.reward.experience
    });
  }

  /**
   * 计算成就完成率
   */
  calculateCompletionRate(user: User): ServiceResponse<number> {
    const total = this.achievements.length;
    const unlocked = user.achievements.length;
    const rate = total > 0 ? (unlocked / total) * 100 : 0;
    return createSuccessResponse<number>(rate);
  }

  /**
   * 添加新成就
   */
  addAchievement(achievement: Achievement): ServiceResponse<Achievement> {
    // 检查ID是否已存在
    if (this.achievements.find(a => a.id === achievement.id)) {
      return createErrorResponse<Achievement>(ServiceError.CONFLICT, '成就ID已存在');
    }

    this.achievements.push(achievement);
    return createSuccessResponse<Achievement>(achievement);
  }

  /**
   * 更新成就信息
   */
  updateAchievement(achievementId: string, updates: Partial<Achievement>): ServiceResponse<Achievement> {
    const index = this.achievements.findIndex(a => a.id === achievementId);
    if (index === -1) {
      return createErrorResponse<Achievement>(ServiceError.NOT_FOUND, '成就不存在');
    }

    this.achievements[index] = { ...this.achievements[index], ...updates };
    return createSuccessResponse<Achievement>(this.achievements[index]);
  }

  /**
   * 删除成就
   */
  deleteAchievement(achievementId: string): ServiceResponse<boolean> {
    const index = this.achievements.findIndex(a => a.id === achievementId);
    if (index === -1) {
      return createErrorResponse<boolean>(ServiceError.NOT_FOUND, '成就不存在');
    }

    this.achievements.splice(index, 1);
    return createSuccessResponse<boolean>(true);
  }
}
代码解析

1. 成就类型设计

export enum AchievementType {
  CONSECUTIVE_DAYS = '连续打卡',    // 连续学习天数
  LEVEL_CLEAR = '关卡通关',        // 通关指定关卡
  ACCURACY = '正确率',              // 达到指定正确率
  SPECIAL = '特殊成就',             // 特殊条件达成
  TOTAL_QUESTIONS = '答题数量'      // 累计答题数量
}

2. 稀有度设计

export enum Rarity {
  COMMON = '普通',       // 绿色,基础奖励
  RARE = '稀有',         // 蓝色,2倍奖励
  EPIC = '史诗',         // 紫色,4倍奖励
  LEGENDARY = '传说'     // 橙色,10倍奖励
}

3. 进度计算逻辑

private calculateProgress(user: User, achievement: Achievement): AchievementProgress {
  let current = 0;
  const target = achievement.condition.target;

  switch (achievement.type) {
    case AchievementType.CONSECUTIVE_DAYS:
      current = user.consecutiveDays;
      break;

    case AchievementType.LEVEL_CLEAR:
      current = user.completedLevels.length;
      break;

    case AchievementType.ACCURACY:
      current = Math.round(user.statistics.averageAccuracy * 100);
      break;

    case AchievementType.TOTAL_QUESTIONS:
      current = user.statistics.totalQuestions;
      break;
  }

  return {
    achievementId: achievement.id,
    current: Math.min(current, target),
    target,
    isCompleted: current >= target
  };
}

4. 成就解锁流程

async checkAndUnlockAchievements(user: User): Promise<ServiceResponse<Achievement[]>> {
  const unlocked: Achievement[] = [];

  for (const achievement of this.achievements) {
    // 跳过已解锁的
    if (user.achievements.includes(achievement.id)) {
      continue;
    }

    // 检查条件
    const progress = this.calculateProgress(user, achievement);
    if (progress.isCompleted) {
      user.achievements.push(achievement.id);
      
      // 发放奖励
      user.totalScore += achievement.reward.score;
      user.totalExperience += achievement.reward.experience;
      
      unlocked.push(achievement);
    }
  }

  return createSuccessResponse<Achievement[]>(unlocked);
}

⚠️ 常见问题与解决方案

问题1: 重复解锁成就

现象:
同一成就被多次解锁,导致奖励重复发放。

错误代码:

// ❌ 错误:没有检查是否已解锁
checkAndUnlockAchievements(user: User): ServiceResponse<Achievement[]> {
  for (const achievement of this.achievements) {
    const progress = this.calculateProgress(user, achievement);
    if (progress.isCompleted) {
      user.achievements.push(achievement.id);  // 可能重复添加
    }
  }
}

正确代码:

// ✅ 正确:检查后添加
checkAndUnlockAchievements(user: User): ServiceResponse<Achievement[]> {
  for (const achievement of this.achievements) {
    // 跳过已解锁的
    if (user.achievements.includes(achievement.id)) {
      continue;
    }

    const progress = this.calculateProgress(user, achievement);
    if (progress.isCompleted) {
      user.achievements.push(achievement.id);
    }
  }
}

规则/建议:

  • 解锁前检查是否已解锁
  • 使用 includes() 或 Set 数据结构
  • 避免重复添加

问题2: 进度计算超出目标值

现象:
用户进度超过目标值,导致显示异常。

错误代码:

// ❌ 错误:进度可能超出目标
current = user.statistics.totalQuestions;  // 可能超过 target

正确代码:

// ✅ 正确:限制进度不超过目标
current = Math.min(user.statistics.totalQuestions, target);

规则/建议:

  • 使用 Math.min() 限制进度
  • 进度条显示时注意边界情况
  • 保持数据一致性

问题3: 稀有度与奖励不匹配

现象:
稀有度与奖励设置不匹配,导致奖励不公平。

错误代码:

// ❌ 错误:传说成就奖励太低
{
  rarity: Rarity.LEGENDARY,
  reward: { score: 50, experience: 25 }
}

正确代码:

// ✅ 正确:稀有度越高奖励越丰厚
{
  rarity: Rarity.LEGENDARY,
  reward: { score: 500, experience: 250 }
}

规则/建议:

  • 稀有度越高,奖励越丰厚
  • 建议比例:普通=1,稀有=2,史诗=4,传说=10
  • 保持奖励系统公平

问题4: 特殊成就条件判断不完整

现象:
特殊成就的条件判断逻辑不完整。

错误代码:

// ❌ 错误:没有处理特殊条件
case AchievementType.SPECIAL:
  current = 0;
  break;

正确代码:

// ✅ 正确:完整处理特殊条件
case AchievementType.SPECIAL:
  current = this.calculateSpecialProgress(user, achievement);
  break;

规则/建议:

  • 特殊成就需要单独实现条件判断
  • 使用 calculateSpecialProgress() 方法
  • 根据 condition.type 进行具体判断

问题5: 成就ID格式不统一

现象:
成就ID格式不统一,导致数据管理困难。

错误代码:

// ❌ 错误:ID格式不统一
const achievement1 = { id: 'achievement_1' };
const achievement2 = { id: 'consecutive_7' };

正确代码:

// ✅ 正确:ID格式统一
const achievement1 = { id: 'achievement_first_login' };
const achievement2 = { id: 'achievement_consecutive_7' };

规则/建议:

  • ID格式:achievement_{type}_{identifier}
  • 使用小写字母和下划线
  • 保持命名一致性

📝 本章小结

核心知识点

本文详细讲解了 AchievementService 成就服务的实现,主要包括:

1. 成就数据管理

  • 成就类型分类(连续打卡、关卡通关、正确率、答题数量、特殊)
  • 稀有度系统(普通、稀有、史诗、传说)

2. 解锁机制

  • 进度计算和条件判断
  • 自动解锁和手动解锁

3. 奖励系统

  • 根据稀有度计算奖励
  • 积分和经验发放

4. 进度跟踪

  • 实时计算成就进度
  • 显示完成状态

最佳实践总结

成就ID格式

id: 'achievement_consecutive_7'  // achievement_{type}_{identifier}

进度计算

current = Math.min(actualValue, target);  // 限制不超过目标

解锁检查

if (user.achievements.includes(achievement.id)) {
  continue;  // 跳过已解锁
}

稀有度奖励

const rewards = {
  [Rarity.COMMON]: { score: 50, experience: 25 },
  [Rarity.RARE]: { score: 100, experience: 50 },
  [Rarity.EPIC]: { score: 200, experience: 100 },
  [Rarity.LEGENDARY]: { score: 500, experience: 250 }
};

下一步预告

在下一篇文章中,我们将:

  • 🎨 讲解页面组件详解系列文章
  • 📚 介绍首页、关卡选择页、答题页等核心页面
  • 🏷️ 探索页面组件的设计和实现

🔗 相关链接


💡 提示: 建议结合项目源码阅读,动手实践效果更好!

Logo

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

更多推荐