谁是卧底词语生成器 — 鸿蒙 HarmonyOS 应用开发实战

一、项目背景

"谁是卧底"是一款非常受欢迎的线下聚会游戏。游戏中,每位玩家会获得一个词语,其中大部分玩家的词语相同(平民词),而少数玩家的词语不同(卧底词)。玩家需要通过描述自己的词语来找出卧底,同时卧底需要隐藏自己的身份。

这个游戏的核心乐趣在于词语的相似性——比如"高跟鞋"和"增高鞋"、"牛奶"和"豆浆"这样的近义词对。然而,每次玩游戏都需要有人提前准备词语,这在实际聚会中往往是个麻烦。

为了解决这个痛点,我决定开发一款谁是卧底词语生成器应用,运行在鸿蒙 HarmonyOS 平台上,支持 API 24 版本,能够随机生成平民词和卧底词,让游戏随时开玩。

二、技术选型

为什么选择 HarmonyOS?

鸿蒙系统作为新一代的国产操作系统,其生态正在快速发展。选择 HarmonyOS 作为开发平台,主要有以下考虑:

  1. 跨设备能力:HarmonyOS 支持手机、平板、智慧屏等多设备协同
  2. 性能优异:ArkTS 编译方案性能接近原生
  3. 开发体验:ArkTS 语言基于 TypeScript,学习成本低
  4. 生态前景:随着鸿蒙生态的完善,用户群体会越来越大

开发技术栈

技术 版本/说明
开发语言 ArkTS(鸿蒙原生声明式 UI 语言)
框架 HarmonyOS ArkUI 声明式框架
构建工具 Hvigor(鸿蒙构建系统)
API 版本 6.1.0(23) 兼容 API 24
项目结构 Stage 模型,单页面应用

三、应用设计

界面设计理念

应用采用深色主题风格,主色调为深蓝色背景(#1a1a2e)搭配红色(#e94560)强调色。整体设计遵循以下原则:

  • 简洁直观:三页面交互流程,用户无需学习即可上手
  • 视觉聚焦:词语和角色信息居中展示,减少干扰元素
  • 色彩编码:绿色代表平民,红色代表卧底,一目了然
  • 安全隐私:词语查看前需要点击"查看"按钮,避免他人偷看

交互流程

首页 → 游戏页(逐人查看) → 结果页 → 再来一局

整个应用只有三个页面,每个页面的功能单一明确:

  1. 首页:设置玩家人数(3-16人),点击"开始游戏"
  2. 游戏页:每位玩家依次查看自己的角色和词语
  3. 结果页:展示词对对照,揭示卧底身份

四、核心功能实现

4.1 词语库设计

词语库是应用的核心数据。我精心收集了 160 余组 经典"谁是卧底"词对,涵盖日常生活的各个方面:

// 词对数据结构
interface WordPair {
  civilian: string   // 平民词
  undercover: string // 卧底词
}

// 示例词对
const WORD_PAIRS: WordPair[] = [
  { civilian: '高跟鞋', undercover: '增高鞋' },  // 鞋类
  { civilian: '牛奶', undercover: '豆浆' },       // 饮品
  { civilian: '火锅', undercover: '麻辣香锅' },   // 美食
  { civilian: '熊猫', undercover: '考拉' },       // 动物
  { civilian: '吉他', undercover: '尤克里里' },   // 乐器
  // ... 共 160+ 组
]

词语分类包括:

  • 🍜 美食类:火锅/麻辣香锅、包子/饺子、薯条/薯片等
  • 👔 服饰类:西装/中山装、拖鞋/凉鞋、高跟鞋/增高鞋等
  • 🐾 动物类:老虎/狮子、熊猫/考拉、蝴蝶/蜻蜓等
  • 🏠 家居类:台灯/吊灯、沙发/躺椅、枕头/抱枕等
  • 🎵 文艺类:钢琴/电子琴、吉他/尤克里里、笛子/箫等
  • 🌿 自然类:山峰/丘陵、河流/小溪、彩虹/晚霞等
  • 🚗 交通类:火车/高铁、自行车/电动车、地铁/轻轨等
  • 📱 科技类:手机/平板、电脑/笔记本、鼠标/触摸板等

4.2 游戏逻辑

游戏的核心逻辑非常简洁但完整:

startGame(): void {
  // 1. 从不重复的词对池中随机选取一组
  let available: number[] = []
  for (let i = 0; i < WORD_PAIRS.length; i++) {
    if (!this.usedIndices.has(i)) {
      available.push(i)
    }
  }
  // 如果所有词对都用过,重置池子
  if (available.length === 0) {
    this.usedIndices.clear()
    available = WORD_PAIRS.map((_, i) => i)
  }
  
  // 2. 随机选取词对
  this.pairIndex = available[Math.floor(Math.random() * available.length)]
  this.usedIndices.add(this.pairIndex)
  this.currentPair = WORD_PAIRS[this.pairIndex]

  // 3. 随机指定卧底
  this.undercoverIndex = Math.floor(Math.random() * this.playerCount)

  // 4. 重置游戏状态
  this.currentViewingPlayer = 0
  this.isRevealed = false
  this.currentPage = 'game'
}

关键设计点:

  • 防重复机制:使用 Set<number> 记录已使用的词对索引,确保连续多局不会重复
  • 自动重置:当所有词对都用完后,自动清空记录重新开始
  • 随机安全:使用 Math.random() 确保每次分配结果不可预测
  • 状态管理:通过 @State 装饰器管理页面状态,ArkUI 自动响应式渲染

4.3 页面状态管理

应用使用 @State 装饰器管理三个页面的状态切换:

@State currentPage: string = 'home' // 'home' | 'game' | 'result'

这种设计的好处:

  • 单页面应用,减少页面跳转开销
  • 状态集中管理,逻辑清晰
  • 使用 @Builder 装饰器拆分页面组件,代码模块化

4.4 UI 组件实现

每个页面都用 @Builder 装饰器拆分为独立的构建函数:

@Entry
@Component
struct Index {
  @State currentPage: string = 'home'

  build() {
    Column() {
      if (this.currentPage === 'home') {
        this.homePage()
      } else if (this.currentPage === 'game') {
        this.gamePage()
      } else if (this.currentPage === 'result') {
        this.resultPage()
      }
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#1a1a2e')
  }

  @Builder
  homePage() { /* 首页 UI */ }

  @Builder
  gamePage() { /* 游戏页 UI */ }

  @Builder
  resultPage() { /* 结果页 UI */ }
}

五、页面详解

5.1 首页

首页是用户进入应用的第一个界面,包含三个核心元素:

标题区域:使用放大镜 emoji(🔍)配合"谁是卧底"和"词语生成器"中英文标题,营造游戏氛围。

人数选择器:采用左右加减按钮的交互方式,支持 3-16 人范围。人数过少(<3人)游戏无法进行,人数过多(>16人)卧底体验会下降,因此做了边界限制。

[-]  6  [+]

开始按钮:醒目的红色渐变按钮,带有阴影效果,吸引用户点击。

5.2 游戏页

游戏页是最核心的交互页面,设计上格外注重隐私保护

进度指示器:顶部的圆点进度条直观展示当前是第几位玩家。已查看的玩家用红色标记,未查看的用灰色标记。

查看前状态:显示"请点击查看你的身份"提示,并警告"请确保其他玩家没有偷看"。这个设计非常重要——在实际聚会场景中,手机通常在多位玩家间传递,必须确保词语不被他人看到。

查看后状态:点击"查看"按钮后,显示角色身份(“你是平民"或"你是卧底”)和对应的词语。平民词和卧底词分别用绿色和红色标识,视觉上强化角色区分。

传递引导:查看完成后,显示"记住你的词语后,将手机传给下一位玩家"的引导文字。最后一位玩家点击时,按钮变为"查看结果"。

revealWord(): void {
  this.isRevealed = true
  this.viewedPlayers[this.currentViewingPlayer] = true
}

nextPlayer(): void {
  if (this.currentViewingPlayer < this.playerCount - 1) {
    this.currentViewingPlayer++
    this.isRevealed = false
  } else {
    this.currentPage = 'result'
  }
}

5.3 结果页

所有玩家查看完毕后,进入结果页:

  • 词语对照区:用两个色块卡片分别展示平民词(绿色背景)和卧底词(红色背景)
  • 卧底揭示区:显示卧底是第几位玩家
  • 操作按钮:"再来一局"和"返回首页"两个按钮

结果页的作用不仅是揭示答案,更是游戏讨论环节的视觉辅助——大家可以看到具体的词对,讨论刚才的描述是否暴露了身份。

六、视觉风格与用户体验

6.1 色彩体系

用途 颜色 色值
主背景 深蓝色 #1a1a2e
卡片背景 深蓝色变体 #16213e
强调色 红色 #e94560
平民词 绿色 #4caf50
卧底词 红色 #f44336
次要文字 灰紫色 #a0a0c0
弱化文字 暗灰 #606080

6.2 卡片式布局

每个页面都使用卡片式布局(Card UI),这是当前移动端最受欢迎的布局方式之一:

  • 圆角矩形:20px 的圆角半径
  • 投影效果:使用 shadow 属性添加阴影层次感
  • 内边距:合理的 padding 保证内容呼吸感

6.3 响应式适配

页面使用 layoutWeight(1) 实现弹性空间分配,确保在不同屏幕尺寸上都能合理布局。底部按钮使用固定的百分比宽度(75%),兼顾美观和易用性。

七、开发踩坑与经验分享

7.1 Set 类型兼容性

在 ArkTS 中使用 Set<number> 时,需要注意版本兼容性。虽然 ES6 的 Set 在 ArkTS 中受支持,但早期版本可能存在兼容问题。如果遇到问题,可以改用普通数组实现去重:

// 替代方案:使用数组代替 Set
usedIndices: number[] = []

isUsed(index: number): boolean {
  return this.usedIndices.indexOf(index) !== -1
}

7.2 @Builder 中的条件渲染

@Builder 函数中使用条件渲染时,需要将条件放在容器组件的 children 闭包内,而不是在 @Builder 的顶层使用链式调用:

// ✅ 正确写法
@Builder
myBuilder() {
  Column() {
    if (condition) {
      Text('A')
    } else {
      Text('B')
    }
  }
}

// ❌ 错误写法
@Builder
myBuilder() {
  if (condition) {   // 不能在 builder 顶层直接 if
    Text('A')
  }
}

7.3 API 版本配置

项目配置中需要指定兼容的 SDK 版本。在 build-profile.json5 中配置:

{
  "app": {
    "products": [{
      "targetSdkVersion": "6.1.0(23)",
      "compatibleSdkVersion": "6.1.0(23)",
      "runtimeOS": "HarmonyOS"
    }]
  }
}

API 24 是 HarmonyOS 的一个重要版本,支持更多新特性。在配置时需要注意 SDK 是否已安装,否则构建会报错。

7.4 构建与签名

使用 Hvigor 构建系统,通过命令行即可完成构建:

hvigorw assembleHap --mode module -p product=default -p buildMode=debug

构建后会在 entry/build/default/outputs/default/ 目录下生成 .hap 文件。调试模式下生成的 HAP 未签名,如需部署到真机,需要配置签名证书或在 DevEco Studio 中直接运行。

八、完整代码结构

entry/src/main/ets/
├── entryability/
│   └── EntryAbility.ets          # 应用入口 Ability
├── entrybackupability/
│   └── EntryBackupAbility.ets    # 备份扩展
└── pages/
    └── Index.ets                 # 主页面(含全部逻辑)

应用采用单页面架构,所有功能和 UI 集中在 Index.ets 中:

  • 数据结构(~5 行):WordPair 接口定义
  • 数据层(~150 行):160+ 组词对数据
  • 逻辑层(~100 行):游戏状态管理、角色分配
  • UI 层(~450 行):三个页面的 UI 构建函数

这种架构对于小型应用非常合适——所有代码在一个文件中,便于阅读和维护。当应用功能增多时,可以按以下方式拆分:

pages/
├── Index.ets         # 路由入口
├── HomePage.ets      # 首页组件
├── GamePage.ets      # 游戏页组件
├── ResultPage.ets    # 结果页组件
└── data/
    └── WordPairs.ets # 词语数据

九、应用亮点总结

  1. 即开即用:下载安装后直接使用,无需联网
  2. 超大词库:160+ 组精心设计的词对,长期游戏不重复
  3. 防偷看设计:点击才显示词语,保护游戏公平性
  4. 视觉友好:深色护眼主题,色彩编码清晰
  5. 简单纯粹:聚焦核心功能,无广告无干扰

十、未来可扩展方向

虽然当前版本已经可以满足基本游戏需求,但还有很多可以扩展的方向:

  1. 自定义词库:允许用户添加自己的词对
  2. 多人离线:通过蓝牙或 Wi-Fi Direct 实现多人同步
  3. 计时功能:增加发言计时器,规范游戏流程
  4. 投票系统:内置投票计票功能
  5. 主题切换:支持浅色/深色主题切换
  6. 历史记录:记录已玩过的词对和数据统计

十一、结语

通过这个项目,我完整地体验了鸿蒙 HarmonyOS 应用从设计到开发再到构建上线的全过程。ArkTS 语言的声明式 UI 编程模型与 SwiftUI、Jetpack Compose 等现代框架一脉相承,学习曲线平缓。

"谁是卧底词语生成器"虽然是一个轻量级应用,但它涵盖了移动应用开发的诸多核心概念:状态管理、条件渲染、列表渲染、用户交互、UI 设计等。对于想要入门鸿蒙开发的开发者来说,这是一个非常适合练手的项目。

希望这篇博客能够帮助到正在学习鸿蒙开发的你。如果你对这个项目感兴趣,欢迎在评论区交流讨论!

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Logo

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

更多推荐