很多刚入门鸿蒙开发的同学,都会面临一个问题:看文档能看懂,写代码无从下手。单独学布局、学状态、学事件都很简单,但一旦需要整合起来做完整项目,就会逻辑混乱、代码报错。
想要快速吃透鸿蒙声明式编程思想,最好的方式就是做一个轻量化、功能闭环、逻辑简单的实战项目。
今天这篇文章,带大家从零开发鸿蒙原生石头剪刀布人机对战小游戏。项目麻雀虽小五脏俱全,涵盖状态管理、随机算法、动态样式、循环渲染、条件渲染、数据统计等鸿蒙核心知识点,非常适合新手练手、课程作业、入门复盘!
一、项目整体介绍
1.1 项目定位
本项目基于 HarmonyOS NEXT 最新版本开发,是一款极简休闲人机对战小游戏。用户手动选择石头、剪刀、布三种手势,系统随机生成电脑手势,自动判分、实时统计对局数据,支持一键重置游戏。
相比复杂的商城、社交类项目,本项目业务逻辑简单、知识点密集、调试成本极低,是鸿蒙新手从「只会抄代码」过渡到「会写逻辑」的绝佳项目。
1.2 核心功能清单
•人机随机出拳:系统算法随机生成电脑手势,对局公平随机
•智能胜负判定:严格遵循经典石头剪刀布对局规则
•动态视觉反馈:胜利绿色、失败红色、平局灰色差异化展示
•全维度数据统计:实时统计总局数、玩家胜场、电脑胜场、平局次数
•流畅动画交互:手势切换搭载过渡动画,告别生硬跳转
•智能条件渲染:无对局数据时自动隐藏统计模块,页面更整洁
•一键重置功能:快速清空所有数据,重新开启对局
1.3 开发环境与技术栈
•开发工具:DevEco Studio 5.0 及以上
•适配SDK:HarmonyOS NEXT API 23(最低兼容版本)
•目标SDK:HarmonyOS NEXT API 24(最新特性适配)
•开发语言:ArkTS(兼容TS语法,鸿蒙专属超集)
•UI框架:原生 ArkUI 声明式 UI
•运行环境:鸿蒙NEXT真机、模拟器通用
二、工程结构快速认知
本项目采用鸿蒙官方标准单模块工程结构,无冗余文件、结构规范,新手可以快速对应每个文件的作用,为后续大型项目开发打下基础。
plain text
MyApplication/
├── AppScope/ # 应用全局资源目录
├── entry/ # 核心业务主模块
│ ├── src/main/ets/
│ │ ├── entryability/ # 应用生命周期入口
│ │ └── pages/Index.ets # 游戏主页面(核心代码全部在此)
│ ├── resources/ # 静态资源(颜色、路由、文字)
│ │ └── base/profile/main_pages.json # 页面路由注册
│ └── module.json5 # 模块核心配置
├── build-profile.json5 # SDK版本编译配置
└── hvigorfile.ts # 工程构建脚本

核心文件核心作用:
Index.ets 是项目唯一业务页面,承载所有UI布局、交互事件、游戏逻辑;main_pages.json 负责页面注册,不注册页面无法预览运行;module.json5 管控设备适配、应用入口等核心配置。
三、核心技术前置讲解
正式写代码前,先梳理本项目用到的四大鸿蒙核心知识点,看懂再写代码,彻底告别死记硬背。
3.1 数据驱动UI(@State)
ArkTS 最核心的特性就是响应式状态管理。通过 @State 修饰的变量,一旦数值发生变化,页面对应UI会自动刷新,无需手动调用更新方法,这也是声明式UI区别于传统命令式UI的最大优势。
3.2 循环渲染(ForEach)
针对重复性UI(本项目三个手势按钮),使用 ForEach 遍历数组批量渲染,避免重复编写冗余代码,让代码更简洁、易维护。
3.3 条件渲染(if判断)
ArkUI 不支持前端常用的逻辑运算符渲染,仅支持原生 if 语句。可根据变量状态,按需展示/隐藏页面模块,优化页面视觉效果。
3.4 自适应权重布局
通过 Row 横向布局 + layoutWeight 权重属性,实现元素按比例均分屏幕宽度,完美适配不同尺寸的鸿蒙手机屏幕。
四、从零手写完整项目代码
4.1 定义数据模型
通过 interface 定义手势数据结构,将展示文案、图标、业务值解耦,实现数据与UI分离,符合工程化开发思想。
typescript
// 手势数据结构定义
interface Choice {
emoji: string; // 展示表情图标
label: string; // 中文文字描述
value: string; // 逻辑判定标识值
}

4.2 定义全局响应式状态
统一声明游戏展示状态、对局统计数据、静态手势数组,所有变量显式声明类型,规避编译报错。
typescript
@Entry
@Component
struct Index {
// 对局UI展示状态
@State playerChoice: string = ‘❔’;
@State computerChoice: string = ‘❔’;
@State result: string = ‘选择你的出拳’;
@State resultColor: string = ‘#8E8E93’;

// 对局统计数据状态
@State playerScore: number = 0;
@State computerScore: number = 0;
@State draws: number = 0;
@State roundCount: number = 0;

// 静态手势数据源(无需响应式,用readonly修饰)
readonly choices: Choice[] = [
{ emoji: ‘✊’, label: ‘石头’, value: ‘rock’ },
{ emoji: ‘✋’, label: ‘布’, value: ‘paper’ },
{ emoji: ‘✌️’, label: ‘剪刀’, value: ‘scissors’ }
];

4.3 封装核心游戏逻辑方法

  1. 电脑随机出拳方法
    利用随机数生成索引,从手势数组中随机取值,实现电脑随机出拳效果。
    typescript
    // 电脑随机获取手势
    getComputerChoice(): string {
    const randomIndex = Math.floor(Math.random() * 3);
    return this.choices[randomIndex].value;
    }

  2. 对局胜负判定核心方法
    覆盖所有对局场景,自动更新UI文案、字体颜色、统计数据,实现全自动对局判定。
    typescript
    // 核心对局逻辑
    play(playerValue: string): void {
    // 获取电脑随机手势
    const computerValue: string = this.getComputerChoice();

    // 匹配展示图标
    const playerEmoji = this.choices.find(c => c.value === playerValue)?.emoji ?? ‘❔’;
    const computerEmoji = this.choices.find(c => c.value === computerValue)?.emoji ?? ‘❔’;

    // 更新对局展示UI
    this.playerChoice = playerEmoji;
    this.computerChoice = computerEmoji;
    this.roundCount++;

    // 胜负、平局逻辑判定
    if (playerValue === computerValue) {
    this.result = ‘🤝 平局!’;
    this.resultColor = ‘#8E8E93’;
    this.draws++;
    } else if (
    (playerValue === ‘rock’ && computerValue === ‘scissors’) ||
    (playerValue === ‘scissors’ && computerValue === ‘paper’) ||
    (playerValue === ‘paper’ && computerValue === ‘rock’)
    ) {
    this.result = ‘🎉 你赢了!’;
    this.resultColor = ‘#34C759’;
    this.playerScore++;
    } else {
    this.result = ‘😅 电脑赢了!’;
    this.resultColor = ‘#FF3B30’;
    this.computerScore++;
    }
    }

  3. 游戏重置方法
    一键重置所有状态数据,恢复页面初始状态,实现重新开局功能。
    typescript
    // 重置所有游戏数据与UI状态
    resetGame(): void {
    this.playerChoice = ‘❔’;
    this.computerChoice = ‘❔’;
    this.result = ‘选择你的出拳’;
    this.resultColor = ‘#8E8E93’;
    this.playerScore = 0;
    this.computerScore = 0;
    this.draws = 0;
    this.roundCount = 0;
    }

4.4 分层UI页面布局
采用从上至下分层布局,页面层级清晰、样式美观,适配全系鸿蒙设备,自带过渡动画效果。
typescript
build() {
Column() {
// 页面标题区域
Text(‘✂️ 石头剪刀布’)
.fontSize(26)
.fontWeight(FontWeight.Bold)
.fontColor(‘#1C1C1E’)
.margin({ top: 30, bottom: 8 })

  Text('和电脑实时对战!')
    .fontSize(14)
    .fontColor('#8E8E93')
    .margin({ bottom: 24 })

  // 对战卡片区域(玩家 VS 电脑)
  Row() {
    // 玩家展示区
    Column() {
      Text('🧑 玩家')
        .fontSize(14)
        .fontColor('#8E8E93')
        .margin({ bottom: 8 })
      Text(this.playerChoice)
        .fontSize(64)
        .animation({ duration: 300 })
      Text(`${this.playerScore} 胜`)
        .fontSize(16)
        .fontWeight(FontWeight.Bold)
        .fontColor('#34C759')
        .margin({ top: 6 })
    }
    .layoutWeight(1)
    .alignItems(HorizontalAlign.Center)

    // VS分隔区域
    Column() {
      Text('VS')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor('#FF3B30')
    }
    .layoutWeight(0.5)
    .alignItems(HorizontalAlign.Center)

    // 电脑展示区
    Column() {
      Text('🤖 电脑')
        .fontSize(14)
        .fontColor('#8E8E93')
        .margin({ bottom: 8 })
      Text(this.computerChoice)
        .fontSize(64)
        .animation({ duration: 300 })
      Text(`${this.computerScore} 胜`)
        .fontSize(16)
        .fontWeight(FontWeight.Bold)
        .fontColor('#FF3B30')
        .margin({ top: 6 })
    }
    .layoutWeight(1)
    .alignItems(HorizontalAlign.Center)
  }
  .width('100%')
  .padding(20)
  .backgroundColor('#F2F2F7')
  .borderRadius(16)
  .margin({ bottom: 16 })

  // 对局结果展示
  Text(this.result)
    .fontSize(22)
    .fontWeight(FontWeight.Bold)
    .fontColor(this.resultColor)
    .margin({ top: 4, bottom: 24 })

  // 手势选择按钮组
  Row() {
    ForEach(this.choices, (choice: Choice) => {
      Column() {
        Text(choice.emoji)
          .fontSize(44)
        Text(choice.label)
          .fontSize(14)
          .fontColor('#1C1C1E')
          .margin({ top: 4 })
      }
      .width(96)
      .height(110)
      .backgroundColor('#F2F2F7')
      .borderRadius(16)
      .justifyContent(FlexAlign.Center)
      .alignItems(HorizontalAlign.Center)
      .onClick(() => {
        this.play(choice.value);
      })
    })
  }
  .width('100%')
  .justifyContent(FlexAlign.SpaceEvenly)
  .margin({ bottom: 24 })

  // 对局统计信息(条件渲染)
  if (this.roundCount > 0) {
    Row() {
      Text(`总局数:${this.roundCount} 局`)
        .fontSize(14)
        .fontColor('#8E8E93')
      Blank()
      Text(`平局次数:${this.draws} 次`)
        .fontSize(14)
        .fontColor('#8E8E93')
    }
    .width('100%')
    .padding({ left: 20, right: 20 })
    .margin({ bottom: 16 })
  }

  // 重置游戏按钮
  Button('🔄 重新开局')
    .type(ButtonType.Capsule)
    .width(180)
    .height(44)
    .backgroundColor('#8E8E93')
    .fontSize(16)
    .fontWeight(FontWeight.Medium)
    .onClick(() => this.resetGame())

}
.width('100%')
.height('100%')
.backgroundColor('#FFFFFF')
.padding(20)
.alignItems(HorizontalAlign.Center)

}
}

五、项目核心配置说明
5.1 页面路由注册
路径:entry/src/main/resources/base/profile/main_pages.json,必须注册页面才可正常预览运行。
json
{
“src”: [
“pages/Index”
]
}

5.2 SDK版本适配配置
路径:build-profile.json5,兼容高低版本SDK,解决编译报错。
json5
{
“app”: {
“products”: [
{
“name”: “default”,
“targetSdkVersion”: “6.1.1(24)”,
“compatibleSdkVersion”: “6.1.0(23)”,
“runtimeOS”: “HarmonyOS”
}
]
}
}

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

六、项目运行流程详解

  1. 初始化状态:项目启动后,页面默认展示问号占位图标,提示用户选择出拳,无任何统计数据。
  2. 交互对局:点击任意手势按钮,触发对局逻辑,电脑随机生成手势,300ms动画过渡,实时展示胜负结果与对应颜色。
  3. 数据更新:每完成一局,总局数、胜场数、平局数自动累加,页面实时刷新统计模块。
  4. 重置复盘:点击重新开局按钮,所有数据、UI状态一键归零,恢复初始界面。
    七、新手开发避坑指南
    整理开发过程中新手高频报错问题,精准解决开发卡点:
    •UI不刷新:禁止省略 @State 变量类型,必须显式声明类型,保证响应式生效
    •页面空白:检查 main_pages.json 是否正确注册页面路径
    •点击事件无效:ForEach 中必须用箭头函数绑定事件,不可直接调用方法
    •语法报错:ArkUI 仅支持 if 条件渲染,不支持 &&、三元表达式渲染UI
    •版本编译失败:统一SDK兼容版本与目标版本,适配真机/模拟器环境
    八、项目总结与进阶拓展
    8.1 项目收获
    通过本项目实战,可彻底掌握鸿蒙开发入门核心能力:响应式状态管理、声明式UI布局、事件交互、算法逻辑、动态样式、条件/循环渲染,完美搭建鸿蒙开发基础思维。
    8.2 高阶拓展方向
    基础项目可自由迭代升级,适合进阶学习与项目优化:
    •新增本地数据持久化,保存历史战绩与最高连胜
    •接入音频API,实现对局胜负专属音效
    •升级3D翻转动画,优化手势交互视觉效果
    •新增历史对局记录页面,实现多页面跳转
    •适配系统深色模式,实现昼夜主题切换
    九、常见问题汇总
    Q:模拟器可以正常运行,真机无法安装?
    A:开启手机开发者模式、USB调试,关闭签名校验,或配置项目自动签名。
    Q:代码无报错,页面无任何内容?
    A:大概率是页面未注册路由,检查 main_pages.json 路径是否正确。
    Q:状态更新后UI不变化?
    A:检查变量是否通过 @State 修饰,未修饰变量不具备响应式能力。
    结语:本文源码完整可直接运行,适配HarmonyOS NEXT全系设备,非常适合新手入门练习、期末课程设计、个人作品集项目!
Logo

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

更多推荐