鸿蒙NEXT零基础实战|手把手开发石头剪刀布小游戏(ArkTS状态驱动UI完整版)
项目麻雀虽小五脏俱全,涵盖状态管理、随机算法、动态样式、循环渲染、条件渲染、数据统计等鸿蒙核心知识点,非常适合新手练手、课程作业、入门复盘!用户手动选择石头、剪刀、布三种手势,系统随机生成电脑手势,自动判分、实时统计对局数据,支持一键重置游戏。ArkTS 最核心的特性就是响应式状态管理。单独学布局、学状态、学事件都很简单,但一旦需要整合起来做完整项目,就会逻辑混乱、代码报错。相比复杂的商城、社交类
很多刚入门鸿蒙开发的同学,都会面临一个问题:看文档能看懂,写代码无从下手。单独学布局、学状态、学事件都很简单,但一旦需要整合起来做完整项目,就会逻辑混乱、代码报错。
想要快速吃透鸿蒙声明式编程思想,最好的方式就是做一个轻量化、功能闭环、逻辑简单的实战项目。
今天这篇文章,带大家从零开发鸿蒙原生石头剪刀布人机对战小游戏。项目麻雀虽小五脏俱全,涵盖状态管理、随机算法、动态样式、循环渲染、条件渲染、数据统计等鸿蒙核心知识点,非常适合新手练手、课程作业、入门复盘!
一、项目整体介绍
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 封装核心游戏逻辑方法
-
电脑随机出拳方法
利用随机数生成索引,从手势数组中随机取值,实现电脑随机出拳效果。
typescript
// 电脑随机获取手势
getComputerChoice(): string {
const randomIndex = Math.floor(Math.random() * 3);
return this.choices[randomIndex].value;
} -
对局胜负判定核心方法
覆盖所有对局场景,自动更新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++;
}
} -
游戏重置方法
一键重置所有状态数据,恢复页面初始状态,实现重新开局功能。
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”
}
]
}
}



六、项目运行流程详解
- 初始化状态:项目启动后,页面默认展示问号占位图标,提示用户选择出拳,无任何统计数据。
- 交互对局:点击任意手势按钮,触发对局逻辑,电脑随机生成手势,300ms动画过渡,实时展示胜负结果与对应颜色。
- 数据更新:每完成一局,总局数、胜场数、平局数自动累加,页面实时刷新统计模块。
- 重置复盘:点击重新开局按钮,所有数据、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全系设备,非常适合新手入门练习、期末课程设计、个人作品集项目!
更多推荐

所有评论(0)