回复
鸿蒙NEXT开发案例:猜小球
zhongcx
发布于 2024-12-1 08:49
浏览
0收藏
【引言】
“猜小球”是一个经典的益智游戏,通常由一名表演者和多名参与者共同完成。表演者会将一个小球放在一个杯子下面,然后将三个杯子快速地交换位置,参与者则需要猜出最终哪个杯子下面有小球。本文将介绍如何使用HarmonyOS NEXT技术,如装饰器、状态管理和动画,来实现一个“猜小球”游戏。
【环境准备】
电脑系统:windows 10
开发工具:DevEco Studio NEXT Beta1 Build Version: 5.0.3.806
工程版本:API 12
真机:Mate 60 Pro
语言:ArkTS、ArkUI
【实现目标】
创建一个交互式的游戏,让玩家能够:
- 开始游戏:通过点击“开始游戏”按钮启动游戏,触发杯子间的随机交换。
- 调整动画速度:允许用户通过界面上的控制器来调整游戏过程中杯子交换的速度。
- 调整混合次数:让用户可以设置每局游戏中杯子的混合次数。
- 显示杯子内容:当动画停止后,玩家可以通过点击任意一个杯子来查看其下面是否有小球。
- 自动重置:如果所有预定的交换次数完成,游戏会自动重置,等待下一轮开始。
【开发逻辑】 - 定义杯子类:创建 Cup 类,定义杯子的属性和构造函数。
- 实现游戏逻辑:
• 初始化游戏状态。
• 实现 startGame() 方法,用于开始游戏。
• 实现 moveCups() 方法,用于移动杯子。
• 实现 swapBalls() 方法,用于交换杯子内的球。
• 实现 resetCupPosition() 方法,用于重置杯子的位置。 - 动画效果:使用动画库(animateToImmediately)实现杯子的动画效果。
【完整代码】
// 使用装饰器来追踪对象的变化
@ObservedV2
class Cup { // 定义杯子类
// 使用装饰器来追踪属性的变化
@Trace positionX: number; // 杯子的X轴位置
@Trace positionY: number; // 杯子的Y轴位置
@Trace containsBall: boolean; // 杯子内是否有球
@Trace isRevealed: boolean; // 杯子是否打开,即是否显示内部情况
// 构造函数初始化杯子的状态
constructor(hasBall: boolean) { // 初始化杯子,参数hasBall表示杯子是否包含小球
this.positionX = 0; // 初始X轴位置设为0
this.positionY = 0; // 初始Y轴位置设为0
this.containsBall = hasBall; // 设置杯子是否含有小球
this.isRevealed = true; // 初始状态为打开,即可以看到里面是否有球
}
}
// 游戏入口组件
@Entry
@Component
struct ThreeCupGame { // 定义游戏主结构体
// 游戏状态变量
@State gameCups: Cup[] = [// 初始化三个杯子数组,其中只有一个杯子含有小球
new Cup(true), // 第一个杯子含有小球
new Cup(false), // 第二个杯子不含有小球
new Cup(false)// 第三个杯子也不含有小球
];
@State cupWidth: number = 200; // 设置杯子宽度
@State cupSpacing: number = 10; // 设置杯子之间的间距
@State animationDurationMs: number = 140; // 设置动画持续时间(毫秒)
@State isGameAnimating: boolean = false; // 表示游戏是否正在进行动画
@State mixingCount: number = 5; // 设置每局游戏混合次数
@State currentMixingCount: number = 0; // 当前正在进行的混合次数计数
// 开始游戏的方法
startGame() { // 开始游戏的函数
this.currentMixingCount--; // 每次调用此函数时减少一次混合次数
const cupPairs = [[0, 1], [0, 2], [1, 2]]; // 定义可能的杯子对组合
const selectedPair = cupPairs[Math.floor(Math.random() * cupPairs.length)]; // 随机选择一对杯子
this.moveCups(selectedPair[0], selectedPair[1]); // 开始移动选定的两个杯子
}
// 移动指定的两个杯子
moveCups(cupIndex1: number, cupIndex2: number) {
const direction: number = Math.random() < 0.5 ? -1 : 1; // 随机方向
const distanceFactor: number = Math.abs(cupIndex1 - cupIndex2); // 距离因子
const adjustedDistanceFactor: number = distanceFactor === 1 ? 2 : 1; // 根据距离调整因子
animateToImmediately({
delay: 0,
duration: this.animationDurationMs
}, () => {
this.gameCups[cupIndex1].positionY = -direction * (this.cupWidth + this.cupSpacing * 2) / adjustedDistanceFactor
})
animateToImmediately({
delay: this.animationDurationMs,
duration: this.animationDurationMs
}, () => {
this.gameCups[cupIndex1].positionX = (this.cupWidth + this.cupSpacing * 2) * distanceFactor
this.gameCups[cupIndex1].positionY = -direction * (this.cupWidth + this.cupSpacing * 2) / adjustedDistanceFactor
})
animateToImmediately({
delay: this.animationDurationMs * 2,
duration: this.animationDurationMs
}, () => {
this.gameCups[cupIndex1].positionX = (this.cupWidth + this.cupSpacing * 2) * distanceFactor
this.gameCups[cupIndex1].positionY = 0
})
animateToImmediately({
delay: 0,
duration: this.animationDurationMs
}, () => {
this.gameCups[cupIndex2].positionY = direction * (this.cupWidth + this.cupSpacing * 2) / adjustedDistanceFactor
})
animateToImmediately({
delay: this.animationDurationMs,
duration: this.animationDurationMs
}, () => {
this.gameCups[cupIndex2].positionX = -(this.cupWidth + this.cupSpacing * 2) * distanceFactor
this.gameCups[cupIndex2].positionY = direction * (this.cupWidth + this.cupSpacing * 2) / adjustedDistanceFactor
})
animateToImmediately({
delay: this.animationDurationMs * 2,
duration: this.animationDurationMs,
onFinish: () => {
this.swapBalls(cupIndex1, cupIndex2)
}
}, () => {
this.gameCups[cupIndex2].positionX = -(this.cupWidth + this.cupSpacing * 2) * distanceFactor
this.gameCups[cupIndex2].positionY = 0
})
}
// 重置杯子的位置
resetCupPosition(cupIndex: number) { // 重置指定杯子位置的函数
this.gameCups[cupIndex].positionX = 0; // 重置X轴位置
this.gameCups[cupIndex].positionY = 0; // 重置Y轴位置
}
// 交换两个杯子内的球
swapBalls(cupIndex1: number, cupIndex2: number) { // 交换两个杯子中球的函数
this.resetCupPosition(cupIndex1); // 重置第一个杯子的位置
this.resetCupPosition(cupIndex2); // 重置第二个杯子的位置
let temporaryBallStatus = this.gameCups[cupIndex1].containsBall; // 临时保存第一个杯子的球状态
this.gameCups[cupIndex1].containsBall = this.gameCups[cupIndex2].containsBall; // 将第二个杯子的球状态赋给第一个杯子
this.gameCups[cupIndex2].containsBall = temporaryBallStatus; // 将临时保存的球状态赋给第二个杯子
if (this.currentMixingCount <= 0) { // 如果当前混合次数已经用完
this.isGameAnimating = false; // 结束动画
} else {
setTimeout(() => { // 否则,延时调用startGame继续下一轮混合
this.startGame();
}, 10);
}
}
// 构建游戏界面
build() { // 构建游戏界面的函数
Column({ space: 20 }) { // 创建一个垂直布局容器
// 游戏标题
Text('猜小球游戏')// 显示游戏标题
.fontSize(24)// 设置字体大小
.margin({ top: 20 }); // 设置顶部边距
// 动画速度控制器
Counter() { // 创建一个计数器组件
Text(`当前速度${this.animationDurationMs}毫秒`)// 显示当前动画速度
.fontColor(Color.Black)// 设置字体颜色
.fontSize('26lpx'); // 设置字体大小
}.width('400lpx') // 设置计数器宽度
.onInc(() => { // 当计数器增加时
this.animationDurationMs += 10; // 增加动画速度
}).onDec(() => { // 当计数器减少时
this.animationDurationMs -= 10; // 减少动画速度
this.animationDurationMs = this.animationDurationMs < 10 ? 10 : this.animationDurationMs; // 确保动画速度不低于10毫秒
});
// 混合次数控制器
Counter() { // 创建另一个计数器组件
Text(`每局混合${this.mixingCount}次`)// 显示当前混合次数
.fontColor(Color.Black)
.fontSize('26lpx');
}.width('400lpx').onInc(() => { // 当计数器增加时
this.mixingCount += 1; // 增加混合次数
}).onDec(() => { // 当计数器减少时
this.mixingCount -= 1; // 减少混合次数
this.mixingCount = this.mixingCount < 1 ? 1 : this.mixingCount; // 确保混合次数不低于1
});
// 杯子布局
Row() { // 创建一个水平布局容器
ForEach(this.gameCups, (cup: Cup) => { // 循环遍历每个杯子
Text(cup.isRevealed ? (cup.containsBall ? '小球' : '空') : '')// 根据杯子的状态显示文字
.width(`${this.cupWidth}lpx`)// 设置宽度
.height(`${this.cupWidth}lpx`)// 设置高度
.margin(`${this.cupSpacing}lpx`)// 设置外边距
.backgroundColor(Color.Orange)// 设置背景色
.fontSize(`${this.cupWidth / 4}lpx`)// 设置字体大小
.textAlign(TextAlign.Center)// 设置文本对齐方式
.fontColor(Color.White)// 设置字体颜色
.borderRadius(5)// 设置圆角半径
.translate({ x: `${cup.positionX}lpx`, y: `${cup.positionY}lpx` })// 设置位置偏移
.onClick(() => { // 当点击杯子时
if (!this.isGameAnimating) { // 如果游戏没有在动画中
cup.isRevealed = true; // 打开杯子查看内部
}
});
});
}.justifyContent(FlexAlign.Center).width('100%').height('720lpx').backgroundColor(Color.Gray); // 设置布局属性
// 开始游戏按钮
Button('开始游戏').onClick(() => { // 创建一个按钮,点击时触发事件
if (!this.isGameAnimating) { // 如果游戏没有在动画中
this.currentMixingCount = this.mixingCount; // 重置当前混合次数
this.isGameAnimating = true; // 设置游戏为动画中
this.gameCups.forEach(cup => cup.isRevealed = false); // 关闭所有杯子
this.startGame(); // 开始游戏
}
});
}.width('100%').height('100%'); // 设置布局容器的尺寸
}
}
分类
标签
赞
收藏
回复
相关推荐