HarmonyOS NETX 5ArkUI-X打造数字猜谜游戏:(附源文件)
游戏采用粉白渐变为主色调,搭配柔化阴影与圆润边框,营造出少女心爆棚的视觉体验。数据结构检测输入数字的唯一性,避免无效猜测干扰游戏体验,同时将错误提示存入历史记录,帮助用户快速发现问题。滚动列表采用卡片式设计,猜中结果用醒目的玫红色标记,未猜中则用深紫色显示,通过颜色差异强化交互反馈。猜中时弹出带烟花符号的庆祝弹窗,将猜测次数动态植入文案,让用户直观感受挑战成就。语句优化性能,确保每个猜测数字仅计算
一、游戏核心逻辑与美学设计
(一)数据模型与游戏规则的优雅实现
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(数字正确但位置错误)的精准计算。当前实现分为两步:
- 计算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; // 避免重复计数
}
}
}
此算法通过break
语句优化性能,确保每个猜测数字仅计算一次B值,避免重复匹配导致的结果偏差。
二、界面设计:从像素到情感的视觉叙事
游戏采用粉白渐变为主色调,搭配柔化阴影与圆润边框,营造出少女心爆棚的视觉体验。ArkUI的声明式UI语法让界面搭建如同搭积木般直观。
(一)状态管理与界面切换
通过@State
装饰器管理界面状态:
@State private showGame: boolean = false; // 控制游戏界面显示
@State private showRules: boolean = false; // 控制规则弹窗显示
主菜单与游戏界面通过showGame
状态切换,配合Column
容器的条件渲染实现无缝过渡:
if (this.showGame) {
// 渲染游戏界面
} else {
// 渲染主菜单
}
(二)交互组件的细节雕琢
- 按钮设计:
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
属性模拟立体按压效果。
- 输入框组:
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
属性增加界面层次感。
- 历史记录列表:
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_2
与GeneratedTypeLiteralInterface_3
定义完全相同,可合并为单一接口:
interface GuessResult {
guess: number[];
result: string;
}
// 使用时统一类型
@State private guessResults: GuessResult[] = [];
减少代码冗余,提升可维护性。
(二)未来功能扩展方向
- 难度选择:增加2位/3位数字模式,适配不同年龄段用户
- 主题切换:支持粉系、蓝系、萌宠等多主题皮肤
- 社交分享:猜中后可分享成绩到社交平台
- 音效反馈:点击按钮、猜中结果时播放对应音效
五、附源文件:
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%' })
}
}
更多推荐
所有评论(0)