一、游戏核心逻辑与美学设计

(一)数据模型与游戏规则的优雅实现

interface GuessResult {
  guess: number[]; // 用户猜测的数字数组
  result: string; // 猜谜结果(如"2A1B")
}

游戏通过两个接口定义数据结构,GuessResult统一管理猜测记录与结果反馈。核心功能generateTargetNumber采用经典的「循环去重法」生成4位不重复数字:

fufunumbers.includes(num)) numbers.push(num);
  }
  this.targetNumber = numbers; // 生成的目标数字存储于状态变量
}

这段代码通过Math.random结合数组去重,确保每次游戏开始时生成唯一的4位数字组合。

(二)AB值计算的算法优化

猜谜游戏的灵魂在于calculateResult函数对A(位置和数字均正确)与B(数字正确但位置错误)的精准计算。当前实现分为两步:

  1. 计算A值:直接对比同位置数字
for (let i = 0; i < 4; i++) {
  if (guess[i] === this.targetNumber[i]) aCount++;
}
  1. 计算B值:通过双重循环检测异位同数
for (let i = 0; i < 4; i++) {
  for (let j = 0; j < 4; j++) {
    if (i !== j && guess[i] === this.targetNumber[j]) {
      bCount++;
      break; // 避免重复计数
    }
  }
}

此算法通过break语句优化性能,确保每个猜测数字仅计算一次B值,避免重复匹配导致的结果偏差。

二、界面设计:从像素到情感的视觉叙事

游戏采用粉白渐变为主色调,搭配柔化阴影与圆润边框,营造出少女心爆棚的视觉体验。ArkUI的声明式UI语法让界面搭建如同搭积木般直观。

(一)状态管理与界面切换

通过@State装饰器管理界面状态:

@State private showGame: boolean = false; // 控制游戏界面显示
@State private showRules: boolean = false; // 控制规则弹窗显示

主菜单与游戏界面通过showGame状态切换,配合Column容器的条件渲染实现无缝过渡:

if (this.showGame) {
  // 渲染游戏界面
} else {
  // 渲染主菜单
}

(二)交互组件的细节雕琢

  1. 按钮设计
Button("💖 开始游戏 💖")
  .onClick(() => this.startGame())
  .width('80%')
  .height(65)
  .backgroundImage(
    'linear-gradient(to right, #FFB6C1, #FFC0CB)' // 渐变背景
  )
  .fontColor('#ffffff')
  .borderRadius(35)
  .shadow({ color: '#FFE4E1', radius: 5 }); // 柔和阴影

通过linear-gradient实现按钮色彩流动感,搭配shadow属性模拟立体按压效果。

  1. 输入框组
Row() {
  ForEach([0,1,2,3], (index) => {
    TextInput({ placeholder: '0' })
      .onChange((val) => this.handleInput(index, val))
      .width(60)
      .height(60)
      .border({ width: 2, color: '#FF69B4' })
      .backgroundColor('#FFF5F5')
      .shadow({ color: '#FFB6C1', radius: 3 }); // 输入框阴影
  })
}

使用ForEach循环创建4个并列输入框,每个输入框限制0-9的数字输入,通过shadow属性增加界面层次感。

  1. 历史记录列表
Scroll() {
  Column() {
    ForEach(this.guessResults, (item, index) => {
      Row()
        .children([
          Text(`${item.guess.join('')}:`).width(100),
          Text(item.result).color(item.result === '4A0B' ? '#FF1493' : '#8A2BE2')
        ])
        .padding(8)
        .backgroundColor('#FFFFFF')
        .borderRadius(15)
        .shadow({ color: '#FFE4E1', radius: 2 }); // 记录项阴影
    })
  }
}

滚动列表采用卡片式设计,猜中结果用醒目的玫红色标记,未猜中则用深紫色显示,通过颜色差异强化交互反馈。

三、用户体验优化:从功能实现到情感共鸣

(一)防误触与输入校验

// 提交猜测时的重复数字校验
const uniqueDigits = new Set(this.userGuess);
if (uniqueDigits.size < 4) {
  this.guessResults.push({
    guess: this.userGuess,
    result: '数字不能重复,请重新输入'
  });
  return; // 阻止无效猜测计入记录
}

通过Set数据结构检测输入数字的唯一性,避免无效猜测干扰游戏体验,同时将错误提示存入历史记录,帮助用户快速发现问题。

(二)情感化反馈设计

if (result === '4A0B') {
  AlertDialog.show({
    title: '🎉 恭喜!',
    message: `经过${this.score}次猜测后猜对了数字!`,
    primaryButton: { value: '确定', action: () => {} }
  });
}

猜中时弹出带烟花符号的庆祝弹窗,将猜测次数动态植入文案,让用户直观感受挑战成就。搭配score状态变量记录猜测次数,增强游戏的成长感。

四、进阶思考:代码可维护性与功能扩展

(一)接口重复问题优化

当前代码中GeneratedTypeLiteralInterface_2GeneratedTypeLiteralInterface_3定义完全相同,可合并为单一接口:

interface GuessResult {
  guess: number[];
  result: string;
}
// 使用时统一类型
@State private guessResults: GuessResult[] = [];

减少代码冗余,提升可维护性。

(二)未来功能扩展方向

  1. 难度选择:增加2位/3位数字模式,适配不同年龄段用户
  2. 主题切换:支持粉系、蓝系、萌宠等多主题皮肤
  3. 社交分享:猜中后可分享成绩到社交平台
  4. 音效反馈:点击按钮、猜中结果时播放对应音效

五、附源文件:

interface GeneratedTypeLiteralInterface_3 {
  guess: number[];
  result: string;
}

interface GeneratedTypeLiteralInterface_2 {
  guess: number[];
  result: string;
}

@Component
export struct play_2 {
  @State private score: number = 0;
  @State private gameMessage: string = "点击开始游戏";
  @State private showGame: boolean = false;
  @State private targetNumber: number[] = [];
  @State private userGuess: number[] = [0, 0, 0, 0];
  @State private guessResults: GeneratedTypeLiteralInterface_2[] = [];
  @State private showRules: boolean = false;

  // 生成不重复的4位数字
  private generateTargetNumber(): void {
    const numbers: number[] = [];
    while (numbers.length < 4) {
      const num = Math.floor(Math.random() * 10);
      if (!numbers.includes(num)) {
        numbers.push(num);
      }
    }
    this.targetNumber = numbers;
  }

  // 计算A和B的数量
  private calculateResult(guess: number[]): string {
    let aCount = 0; // 数字和位置都正确
    let bCount = 0; // 数字正确但位置不对

    // 计算A
    for (let i = 0; i < 4; i++) {
      if (guess[i] === this.targetNumber[i]) {
        aCount++;
      }
    }

    // 计算B
    for (let i = 0; i < 4; i++) {
      for (let j = 0; j < 4; j++) {
        if (i !== j && guess[i] === this.targetNumber[j]) {
          bCount++;
          break;
        }
      }
    }

    return `${aCount}A${bCount}B`;
  }

  build() {
    Column() {
      if (this.showGame) {
        // 数字猜测游戏界面
        Column({ space: 30 }) {
          // 得分显示
          Text(`猜测次数:${this.score}`)
            .fontSize(36)
            .fontColor("#FF69B4")
            .fontWeight(700)
            .fontStyle(FontStyle.Italic)

          // 游戏规则按钮
          Button("🧸 查看规则")
            .onClick(() => {
              this.showRules = !this.showRules;
            })
            .width('80%')
            .height(45)
            .backgroundColor("#FFB6C1")
            .fontColor("#FFFFFF")
            .fontSize(20)
            .borderRadius(25)
            .padding({ left: 10, right: 10 })

          // 规则说明
          if (this.showRules) {
            Text("🎀 游戏规则 🎀\n\n1. 系统随机生成一个不重复的4位数字\n2. 玩家输入一个4位数字作为猜测\n3. A表示数字和位置都正确,B表示数字正确但位置不对\n4. 根据反馈继续调整猜测,直到猜中为止\n\n🌸 小提示:试试找出每个数字的位置吧!")
              .fontSize(20)
              .fontColor("#FF69B4")
              .textAlign(TextAlign.Center)
              .padding({ top: 15, bottom: 15 })
              .backgroundColor("#FFF0F5")
              .borderRadius(20)
              .margin({ top: 5 })
          }

          // 历史记录
          Scroll() {
            Column(){
              ForEach(this.guessResults, (item: GeneratedTypeLiteralInterface_2, index: number) => {
                Row() {
                  Text(`${item.guess.join('')}:`)
                    .fontSize(24)
                    .fontColor("#FF69B4")
                    .width(100)
                    .textAlign(TextAlign.Center)
                  Text(item.result)
                    .fontSize(24)
                    .fontColor(item.result === "4A0B" ? "#FF1493" : "#8A2BE2")
                    .margin({left:20})
                    .maxLines(1)
                    .width(150)
                }
                .margin({ top: 10 })
                .border({ width: 1, color: "#FFE4E1" })
                .padding( 8 )
                .borderRadius(15)
                .backgroundColor("#FFFFFF")
              }, (item: GeneratedTypeLiteralInterface_3) => item.guess.toString())
            }
          }
          .height(220)
          .width('80%')
          .border({ width: 2, color: '#FFC0CB' })
          .borderRadius(20)

          // 输入区域
          Column({ space: 15 }) {
            Text("‼ 请输入4位不重复数字(0-9)")
              .fontSize(24)
              .fontColor("#8A2BE2")
              .fontStyle(FontStyle.Italic)

            Row({ space: 15 }) {
              ForEach([0, 1, 2, 3], (index: number) => {
                TextInput({ placeholder: '0' })
                  .onChange((value: string) => {
                    const num = parseInt(value);
                    if (!isNaN(num) && num >= 0 && num <= 9) {
                      this.userGuess[index] = num;
                    } else {
                      this.userGuess[index] = 0;
                    }
                  })
                  .width(60)
                  .height(60)
                  .border({ width: 2, color: '#FF69B4' })
                  .padding({ left: 10, right: 10 })
                  .borderRadius(15)
                  .backgroundColor('#FFF5F5')
                  .fontSize(32)
                  .textAlign(TextAlign.Center)
                  .shadow({ color: "#FFB6C1", radius: 5 }) // 添加柔和阴影
              }, (index: number) => index.toString())
            }
          }

          // 按钮样式优化
          Button("🍭 提交猜测")
            .onClick(() => {
              // 检查是否有重复数字
              const uniqueDigits = new Set(this.userGuess);
              if (uniqueDigits.size < 4) {
                this.guessResults.push({
                  guess: [this.userGuess[0], this.userGuess[1], this.userGuess[2], this.userGuess[3]],
                  result: "数字不能重复,请重新输入"
                });
                return;
              }

              this.score += 1;
              const result = this.calculateResult(this.userGuess);
              this.guessResults.push({
                guess: [...this.userGuess],
                result: result
              });

              if (result === "4A0B") {
                AlertDialog.show({
                  title: '🎉 恭喜!',
                  message: `恭喜你!经过${this.score}次猜测后猜对了数字!`,
                  primaryButton: {
                    value: '确定',
                    action: () => {}
                  }
                });              }
            })
            .width('80%')
            .height(55)
            .backgroundColor("linear-gradient(to right, #FF69B4, #FFB6C1)")
            .fontColor("#ffffff")
            .fontSize(26)
            .borderRadius(30)
            .padding({ left: 15, right: 15 })

          // 返回按钮
          Button("🏠 返回主菜单")
            .onClick(() => {
              this.showGame = false;
              this.gameMessage = "游戏已结束";
              this.score = 0;
              this.guessResults = [];
            })
            .width('80%')
            .height(55)
            .backgroundColor("#DDA0DD")
            .fontColor("#ffffff")
            .fontSize(26)
            .borderRadius(30)
            .padding({ left: 15, right: 15 })
        }
        .width('100%')
        .height('100%')
        .justifyContent(FlexAlign.Center)
        .alignItems(HorizontalAlign.Center)
      } else {
        // 主菜单界面
        Column({ space: 30 }) {
          // 游戏消息
          Text(this.gameMessage)
            .fontSize(36)
            .fontColor("#FF69B4")
            .fontWeight(700)
            .fontStyle(FontStyle.Italic)

          // 开始按钮
          Button("💖 开始游戏 💖")
            .onClick(() => {
              this.showGame = true;
              this.score = 0;
              this.gameMessage = "";
              this.guessResults = [];
              this.generateTargetNumber();
            })
            .width('80%')
            .height(65)
            .backgroundColor("linear-gradient(to right, #FFB6C1, #FFC0CB)")
            .fontColor("#ffffff")
            .fontSize(30)
            .borderRadius(35)
            .padding({ left: 20, right: 20 })
        }
        .width('100%')
        .height('100%')
        .justifyContent(FlexAlign.Center)
        .alignItems(HorizontalAlign.Center)
      }
    }
    .width('100%')
    .height('100%')
    .backgroundColor("#FFFDF3")
    .backgroundImage($r("app.media.background")) // 假设有一张柔和的背景图片
    .backgroundImageSize({ width: '100%', height: '100%' })
  }
}

Logo

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

更多推荐