📌 所属专栏: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版权协议,转载请附上原文出处链接及本声明。

Logo

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

更多推荐