HarmonyOS NEXT零基础实战|手写猜数字小游戏(状态管理+列表渲染+动画交互)
本教程通过开发经典猜数字游戏(1~100随机谜底),帮助零基础新手快速掌握HarmonyOS NEXT核心开发技能:技术栈:ArkTS声明式UI + Stage模型,纯本地运行核心逻辑:随机数生成、输入校验、动态反馈(文字/颜色)、历史记录存储、状态管理(@State)交互优化:快捷数字按钮、庆祝动画、游戏结束禁操、一键重启UI设计:卡片式分层布局,适配手机全屏,包含状态提示区、输入模块、历史记录
📌 所属专栏:HarmonyOS NEXT 零基础实战教程
🎯 适配版本:HarmonyOS NEXT、DevEco Studio 最新版、Stage模型
✅ 难度等级:新手入门 · 零基础友好
💡 前言
对于鸿蒙开发新手而言,单纯学习组件布局、基础语法枯燥且难以落地,想要快速掌握状态管理、动态UI、交互逻辑、列表渲染、动画效果,小游戏实战是最优学习方式。
今天带大家从零开发经典猜数字小游戏,项目逻辑轻量化、知识点密集、交互体验完整。全程使用ArkTS原生语法+声明式UI开发,无需后端、无需网络,纯本地运行。
通过本项目,你可以彻底吃透鸿蒙核心动态开发知识点,告别只会写静态页面的短板,轻松入门交互式应用开发。
一、项目整体概述
1.1 游戏核心规则
猜数字是经典的逻辑推理休闲小游戏,规则简单易懂、可玩性强,核心逻辑如下:
•系统自动随机生成 1~100 之间的整数作为谜底
•玩家手动输入数字或点击快捷按钮进行猜测
•系统实时反馈结果:数字偏大、数字偏小、猜测正确
•猜中谜底后统计猜测次数,触发庆祝动画,支持一键重启游戏
1.2 项目功能亮点
本项目并非简陋Demo,具备完整的游戏交互与体验优化:
•随机数生成:精准生成1-100随机谜底,每次开局重置
•输入校验机制:非法数字、超出范围输入实时拦截提示
•多维交互反馈:文字+颜色双重提示,直观展示猜测结果
•快捷数字按钮:预设常用数字,一键填入,提升操作效率
•完整历史记录:实时保存每一次猜测记录,有序展示
•状态权限控制:游戏结束后自动禁用输入,防止误操作
•动画特效加持:猜中后触发缩放庆祝动画,提升游戏氛围感
•一键重启对局:随时开启新游戏,状态全部重置
1.3 页面UI设计
采用当下主流的卡片式分层UI,界面简洁美观、层次分明,适配手机全屏展示:
•顶部区域:游戏标题、规则副标题
•核心卡片区:状态提示、猜测次数统计、输入提交模块、庆祝动画
•快捷操作区:多组预设数字快捷按钮
•历史记录区:逐条展示所有猜测记录,有序排版
•底部功能区:游戏结束展示重启按钮,界面自适应切换
二、数据结构与状态设计
合理的状态与数据结构是项目规范开发的核心,本项目通过自定义接口+响应式状态变量统一管理游戏数据,代码可读性、可维护性大幅提升。
2.1 自定义记录数据接口
定义猜测记录接口,统一规范单条记录的数据格式,实现类型约束:
typescript
// 猜测记录数据结构
interface GuessRecord {
guess: number // 玩家猜测的数字
result: string // 猜测结果文本
resultColor: string // 结果展示颜色
}
2.2 全局响应式状态变量
所有涉及UI更新、游戏状态切换的变量,全部使用 @State 修饰,实现数据驱动UI自动刷新:
typescript
// 谜底目标数字
@State targetNumber: number = 0
// 用户输入的猜测数字
@State userInput: string = ‘’
// 累计猜测次数
@State attempts: number = 0
// 游戏提示文案
@State hintText: string = ‘输入 1-100 之间的数字开始游戏’
// 提示文案颜色
@State hintColor: string = ‘#888888’
// 游戏结束状态
@State isGameOver: boolean = false
// 猜测历史记录数组
@State guessHistory: GuessRecord[] = []
// 庆祝动画展示状态
@State showCelebration: boolean = false
三、核心业务逻辑精讲
3.1 新游戏初始化逻辑
页面加载、重启游戏时触发,完成随机数生成、所有状态重置,保证每一局游戏初始化干净无残留数据。同时打印谜底日志,方便开发调试。
typescript
// 初始化新游戏
newGame(): void {
// 生成1-100随机整数
this.targetNumber = Math.floor(Math.random() * 100) + 1
// 重置所有游戏状态
this.userInput = ‘’
this.attempts = 0
this.hintText = ‘输入 1-100 之间的数字开始游戏’
this.hintColor = ‘#888888’
this.isGameOver = false
this.guessHistory = []
this.showCelebration = false
// 控制台打印谜底,方便调试
console.info([猜数字] 本局谜底:${this.targetNumber})
}
3.2 猜测提交核心逻辑
核心业务函数,包含输入合法性校验、结果判断、状态更新、历史记录存储、游戏结束判定全流程逻辑:
typescript
// 提交猜测结果
submitGuess(): void {
const guess = parseInt(this.userInput)
// 非法输入校验
if (isNaN(guess) || guess < 1 || guess > 100) {
this.hintText = '⚠️ 请输入1-100范围内的整数!'
this.hintColor = '#E67E22'
return
}
// 有效猜测,次数累加
this.attempts++
let newHint = ''
let newColor = ''
let correct = false
// 大小对比逻辑
if (guess === this.targetNumber) {
// 猜测正确,游戏结束
newHint = `🎉 恭喜猜中!谜底就是${this.targetNumber},共猜测${this.attempts}次`
newColor = '#27AE60'
correct = true
this.isGameOver = true
this.showCelebration = true
} else if (guess < this.targetNumber) {
newHint = `👆 ${guess} 数字偏小,再试试!`
newColor = '#E74C3C'
} else {
newHint = `👇 ${guess} 数字偏大,再试试!`
newColor = '#E74C3C'
}
// 更新提示状态
this.hintText = newHint
this.hintColor = newColor
// 新增历史记录(最新记录置顶)
this.guessHistory = [
{
guess: guess,
result: correct ? '✅ 猜测正确' : (guess < this.targetNumber ? '⬆ 数字偏小' : '⬇ 数字偏大'),
resultColor: correct ? '#27AE60' : '#E74C3C'
},
...this.guessHistory
]
// 清空输入框,方便下次输入
this.userInput = ''
}
3.3 复用快捷按钮组件
通过 @Builder 封装通用数字按钮组件,减少重复代码,统一按钮样式,支持点击快速填入数字,游戏结束后自动失效:
typescript
// 快捷数字按钮封装
@Builder
quickButton(value: number): void {
Button(${value})
.width(58)
.height(36)
.backgroundColor(‘#EEEEEE’)
.borderRadius(8)
.fontSize(14)
.fontColor(‘#555555’)
.fontWeight(FontWeight.Medium)
.onClick(() => {
// 仅游戏进行中可点击
if (!this.isGameOver) {
this.userInput = value.toString()
}
})
}
3.4 页面生命周期初始化
页面渲染完成后自动初始化游戏,无需手动点击开局,提升用户体验:
typescript
// 页面显示时初始化游戏
aboutToAppear(): void {
this.newGame()
}
四、完整UI布局实现
整体采用外层滚动容器+居中卡片布局,适配所有屏幕尺寸,结合条件渲染、动态样式、动画过渡实现高颜值交互界面。以下为完整build布局代码:
typescript
build() {
Column() {
Scroll() {
Column({ space: 12 }) {
// 顶部标题区域
Text(‘🎯 趣味猜数字’)
.fontSize(28)
.fontWeight(FontWeight.Bold)
Text('请猜测1~100之间的随机整数')
.fontSize(14)
.fontColor('#999999')
// 核心游戏卡片
Column({ space: 16 }) {
// 状态提示文字
Text(this.hintText)
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor(this.hintColor)
.textAlign(TextAlign.Center)
.width('100%')
.animation({ duration: 300 })
// 猜测次数统计
if (this.attempts > 0) {
Text(`已猜测 ${this.attempts} 次`)
.fontSize(13)
.fontColor('#AAAAAA')
}
// 输入框+功能按钮
Row({ space: 10 }) {
TextInput({ text: this.userInput, placeholder: '请输入数字...' })
.type(InputType.Number)
.maxLength(3)
.fontSize(20)
.fontWeight(FontWeight.Bold)
.textAlign(TextAlign.Center)
.height(50)
.layoutWeight(1)
.backgroundColor('#F5F5F5')
.borderRadius(12)
.onChange((val: string) => {
this.userInput = val
})
.onSubmit(() => {
if (!this.isGameOver) {
this.submitGuess()
}
})
.enabled(!this.isGameOver)
Button(this.isGameOver ? '🔄' : '↵')
.width(50)
.height(50)
.backgroundColor(this.isGameOver ? '#3498DB' : '#2D3436')
.borderRadius(12)
.fontSize(22)
.fontColor('#FFFFFF')
.onClick(() => {
this.isGameOver ? this.newGame() : this.submitGuess()
})
}
.width('100%')
// 猜中庆祝动画
if (this.showCelebration) {
Text('✨ 🌟 ⭐ 🌟 ✨')
.fontSize(24)
.textAlign(TextAlign.Center)
.width('100%')
.margin({ top: 4 })
.transition({ type: TransitionType.Insert, scale: { x: 0, y: 0 } })
}
}
.width('85%')
.padding(20)
.backgroundColor('#FFFFFF')
.borderRadius(16)
.shadow({ radius: 6, color: '#1A000000', offsetY: 3 })
// 快捷数字选择区
if (!this.isGameOver) {
Column() {
Text('快捷选择')
.fontSize(14)
.fontColor('#AAAAAA')
.margin({ bottom: 8 })
Row({ space: 8 }) {
this.quickButton(10)
this.quickButton(25)
this.quickButton(50)
this.quickButton(75)
this.quickButton(90)
}
.width('100%')
Row({ space: 8 }) {
this.quickButton(1)
this.quickButton(33)
this.quickButton(66)
this.quickButton(99)
this.quickButton(100)
}
.width('100%')
}
.width('85%')
.margin({ bottom: 8 })
}
// 重启游戏按钮
if (this.isGameOver) {
Button('🔄 再来一局')
.width('85%')
.height(48)
.backgroundColor('#3498DB')
.borderRadius(14)
.fontSize(17)
.fontColor('#FFFFFF')
.onClick(() => {
this.newGame()
})
}
// 猜测历史记录列表
if (this.guessHistory.length > 0) {
Column({ space: 8 }) {
Text('📋 猜测记录')
.fontSize(16)
.fontWeight(FontWeight.Medium)
.fontColor('#666666')
.width('100%')
Column({ space: 4 }) {
ForEach(this.guessHistory, (item: GuessRecord) => {
Row() {
Text(`#${this.guessHistory.length - this.guessHistory.indexOf(item)}`)
.fontSize(14)
.fontColor('#AAAAAA')
.width(36)
Text(`${item.guess}`)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor('#2D3436')
.width(60)
Text(item.result)
.fontSize(15)
.fontColor(item.resultColor)
.fontWeight(FontWeight.Medium)
}
.width('100%')
.padding({ top: 8, bottom: 8, left: 12, right: 12 })
.backgroundColor('#FAFAFA')
.borderRadius(10)
})
}
}
.width('85%')
.margin({ top: 8, bottom: 32 })
}
}
.width('100%')
.alignItems(HorizontalAlign.Center)
}
.scrollable(ScrollDirection.Vertical)
}
.width('100%')
.height('100%')
.backgroundColor('#F0F2F5')
}
五、新手高频Bug与解决方案
问题1:输入框提交后无法自动清空
问题原因:对TextInput单向绑定特性不熟悉,状态更新未同步视图
解决方案:通过@State变量托管输入内容,赋值空字符串后可自动同步清空输入框,源码已内置该逻辑。
问题2:历史记录序号排序错乱
问题原因:新记录插入数组头部,原生索引顺序颠倒
解决方案:通过 数组长度 - 当前索引 计算真实排序序号,保证记录从上到下依次递增。
问题3:猜中后庆祝动画不生效
问题原因:Transition动画必须配合条件渲染使用,静态组件无法触发动画
解决方案:通过isShow状态+if条件控制组件显示隐藏,搭配插入缩放动画,完美实现庆祝效果。
问题4:游戏结束后仍可输入猜测
问题原因:未做状态权限拦截,输入框和点击事件未做限制
解决方案:双重拦截,通过 enabled 禁用输入框,同时在点击事件中判断游戏状态,杜绝无效操作。
问题5:快捷按钮游戏结束后仍可点击
解决方案:按钮点击事件中增加游戏状态判断,游戏结束后禁止赋值输入框。
六、项目进阶拓展方向
基础版游戏完成后,可自主拓展功能,升级为完整版趣味小游戏:
•多难度模式:新增简单/中等/困难难度,对应不同数字范围(50/100/500)
•计时功能:记录单局游戏用时,比拼猜测速度
•战绩记录:本地存储最佳成绩、最少猜测次数记录
•智能提示:猜测多次后触发提示,告知玩家数字区间
•音效反馈:猜测正确/错误播放不同提示音效
•分数统计:根据猜测次数计算得分,增加游戏趣味性
七、项目学习总结
猜数字小游戏是鸿蒙NEXT开发中入门交互开发的标杆项目,代码量适中、知识点全覆盖,零基础极易上手。
通过本项目实战,你将彻底掌握五大核心能力:
1、熟练使用@State响应式状态管理,吃透数据驱动UI核心思想;
2、掌握条件渲染、动态样式、组件显隐控制的实战用法;
3、学会@Builder封装复用组件,简化代码、提升规范性;
4、掌握ForEach列表渲染、数据遍历展示的开发技巧;
5、熟悉输入框交互、事件处理、简单动画开发的完整流程。
本项目涵盖了鸿蒙交互开发的基础核心知识点,学完可独立开发各类轻量互动小游戏、工具类应用。
后续持续更新鸿蒙进阶实战教程,零基础一站式吃透HarmonyOS NEXT开发!
点赞+收藏+订阅专栏,持续更新全套鸿蒙零基础实战项目!
版权声明:本文为CSDN原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
更多推荐

所有评论(0)