مورد توسعه بعدی Hongmeng: Flop Memory

【مقدمه】
در این حالت ، ما از چارچوب Next Hongmeng برای توسعه یک بازی Flop حافظه ساده استفاده خواهیم کرد. منطق اصلی بازی این است که بازیکنان کارت ها را برای یافتن جفت های تطبیق می دهند. در این مقاله روند اجرای بازی با جزئیات ، از جمله نمایش کارت ، منطق تطبیق و تعامل کاربر معرفی می شود.
【آماده سازی محیط زیست توسعه
سیستم رایانه ای: ویندوز 10
ابزارهای توسعه: Deveco Studio Next Beta1 نسخه ساخت: 5.0.3.806
نسخه پروژه: API 12
ماشین واقعی: Mate 60 Pro
زبان: Arkts ، Arkui
ساختار پروژه
این پروژه از دو دسته تشکیل شده است:
Gamecell: یک کارت واحد در بازی را نشان می دهد ، مسئول مدیریت وضعیت و اثرات انیمیشن کارت است.
MemoryGame: اجزای بازی ، مدیریت منطق بازی و رابط کاربری.
کلاس Gamecell
کلاس Gamecell واحد اصلی یک بازی است که حاوی خصوصیات و روشهای زیر است:
ملک:
مقدار: مقدار کارت (مانند “A” ، “B” و غیره).
isVisible: کنترل می کند که آیا کارت قابل مشاهده است.
isfrontvisible: کنترل می کند که آیا کارت با آن روبرو است.
ismatched: علامت گذاری کنید که آیا کارت با هم هماهنگ شده است یا خیر.
IsanimationRunning: آیا انیمیشن در حال اجرا است.
چرخش: زاویه چرخش کارت.
روش:
آشکار (زمان انیمیشن ، پاسخ به تماس): جلوی کارت را نشان می دهد و انیمیشن را اجرا می کند.
مخفی کردن (زمان انیمیشن ، پاسخ به تماس): جلوی کارت را پنهان می کند و انیمیشن را اجرا می کند.
تنظیم مجدد (): تنظیم مجدد وضعیت کارت.
اجرای انیمیشن
در روشهای آشکار و مخفی کردن ، ما از عملکرد AnimateToimmedistmedistmed برای پیاده سازی انیمیشن FLIP از کارت استفاده می کنیم. با تنظیم مدت زمان ، تعداد تکرارها و انواع انیمیشن ها ، تجربه کاربر صاف را تضمین کنید.
یادبود
کلاس MemoryGame مؤلفه اصلی بازی است که مسئول مدیریت وضعیت بازی و تعامل کاربر است.
ملک:
Gamecells: آرایه ای که تمام کارت ها را ذخیره می کند.
سلولهای: اندازه کارت.
CellSpacing: فاصله بین کارت.
انتقال: مدت زمان انتقال انیمیشن.
FirstSelectedIndex و SecondselectedIndex: فهرست کارت انتخاب شده توسط کاربر را ثبت می کند.
IsGameover: نشانه ای از پایان بازی است.
روش:
About toAppear (): کارت بازی را اولیه کنید و آن را تغییر دهید.
ShuffleCards (): الگوریتم Shuffle ، به طور تصادفی ترتیب کارت را مختل می کند.
CheckFormatch (): بررسی کنید که آیا دو کارت انتخاب شده توسط کاربر مطابقت دارد یا خیر.
ساخت (): رابط بازی را بسازید.
منطق بازی
در روش CheckFormatch ، ما تعیین می کنیم که آیا دو کارت انتخاب شده توسط کاربر یکسان هستند یا خیر. اگر یکسان باشد ، اگر متفاوت باشد ، آن را مشخص کنید. در پایان بازی ، یک کادر گفتگو ظاهر می شود تا کاربر را به پیروزی برساند و گزینه ای را برای شروع فراهم می کند.
رابط کاربری
در روش ساخت ، ما از طرح های ستون و فلکس برای سازماندهی نمایش کارت استفاده می کنیم. هر کارت مقدار خود را از طریق مؤلفه متن نشان می دهد و رنگ پس زمینه و زاویه چرخش را مطابق با حالت تنظیم می کند. هنگامی که کاربر روی کارت کلیک می کند ، تلنگر مربوطه و منطق تطبیق ایجاد می شود.
در نتیجه
از طریق این مورد ، ما نشان می دهیم که چگونه می توان با استفاده از چارچوب بعدی Hongmeng یک بازی Flop حافظه ساده را توسعه داد. این پروژه نه تنها منطق اصلی بازی را در بر می گیرد ، بلکه نحوه دستیابی به جلوه های انیمیشن و تعامل کاربر را نیز نشان می دهد. امیدوارم این مورد بتواند الهام بخش و کمک به شما در توسعه هنگمنگ بعدی باشد.
【کد کامل
import { promptAction } from '@kit.ArkUI' // 导入用于显示对话框的模块
// 使用装饰器来观察数据变化
@ObservedV2
class GameCell { // 定义单元格类
@Trace value: string; // 单元格的值,即卡片上的图案
@Trace isVisible: boolean = false; // 控制卡片是否可见
isFrontVisible: boolean = false; // 控制卡片是否正面朝上
isMatched: boolean = false; // 标记卡片是否已被匹配
isAnimationRunning: boolean = false; // 动画是否正在运行
@Trace rotationAngle: number = 0; // 卡片的旋转角度
constructor(value: string) { // 构造函数,初始化单元格
this.value = value; // 设置单元格的值
}
// 展示卡片正面的方法
revealFace(animationTime: number, callback?: () => void) {
if (this.isAnimationRunning) { // 如果已经有动画在运行,则返回
return;
}
this.isAnimationRunning = true; // 设置动画状态为运行中
animateToImmediately({ // 开始动画
duration: animationTime, // 动画持续时间
iterations: 1, // 动画迭代次数
curve: Curve.Linear, // 动画曲线类型
onFinish: () => { // 动画完成后的回调
animateToImmediately({ // 再次开始动画
duration: animationTime, // 动画持续时间
iterations: 1, // 动画迭代次数
curve: Curve.Linear, // 动画曲线类型
onFinish: () => { // 动画完成后的回调
this.isFrontVisible = true; // 设置卡片为正面朝上
this.isAnimationRunning = false; // 设置动画状态为停止
if (callback) { // 如果有回调函数,则执行
callback();
}
}
}, () => { // 动画开始时的回调
this.isVisible = true; // 设置卡片为可见
this.rotationAngle = 0; // 设置旋转角度为0
});
}
}, () => { // 动画开始时的回调
this.isVisible = false; // 设置卡片为不可见
this.rotationAngle = 90; // 设置旋转角度为90度
});
}
// 重置卡片状态的方法
reset() {
this.isVisible = false; // 设置卡片为不可见
this.rotationAngle = 180; // 设置旋转角度为180度
this.isFrontVisible = false; // 设置卡片为背面朝上
this.isAnimationRunning = false; // 设置动画状态为停止
this.isMatched = false; // 设置卡片为未匹配
}
// 隐藏卡片正面的方法
hideFace(animationTime: number, callback?: () => void) {
if (this.isAnimationRunning) { // 如果已经有动画在运行,则返回
return;
}
this.isAnimationRunning = true; // 设置动画状态为运行中
animateToImmediately({ // 开始动画
duration: animationTime, // 动画持续时间
iterations: 1, // 动画迭代次数
curve: Curve.Linear, // 动画曲线类型
onFinish: () => { // 动画完成后的回调
animateToImmediately({ // 再次开始动画
duration: animationTime, // 动画持续时间
iterations: 1, // 动画迭代次数
curve: Curve.Linear, // 动画曲线类型
onFinish: () => { // 动画完成后的回调
this.isFrontVisible = false; // 设置卡片为背面朝上
this.isAnimationRunning = false; // 设置动画状态为停止
if (callback) { // 如果有回调函数,则执行
callback();
}
}
}, () => { // 动画开始时的回调
this.isVisible = false; // 设置卡片为不可见
this.rotationAngle = 180; // 设置旋转角度为180度
});
}
}, () => { // 动画开始时的回调
this.isVisible = true; // 设置卡片为可见
this.rotationAngle = 90; // 设置旋转角度为90度
});
}
}
// 定义组件入口
@Entry
@Component
struct MemoryGame { // 定义游戏组件
@State gameCells: GameCell[] = []; // 存储游戏中的所有单元格
@State cellSize: number = 150; // 单元格的大小
@State cellSpacing: number = 5; // 单元格之间的间距
@State transitionDuration: number = 150; // 过渡动画的持续时间
@State firstSelectedIndex: number | null = null; // 记录第一次选择的卡片索引
@State secondSelectedIndex: number | null = null; // 记录第二次选择的卡片索引
@State isGameOver: boolean = false; // 游戏是否结束
@State startTime: number = 0; // 游戏开始时间
aboutToAppear(): void { // 组件即将显示时触发
let cardValues: string[] = ["A", "B", "C", "D", "E", "F", "G", "H"]; // 定义卡片的值
for (let value of cardValues) { // 遍历卡片值
this.gameCells.push(new GameCell(value)); // 添加到游戏单元格数组中
this.gameCells.push(new GameCell(value)); // 每个值添加两次以形成对
}
this.shuffleCards(); // 洗牌
}
// 洗牌方法
shuffleCards() {
this.firstSelectedIndex = null; // 清除第一次选择索引
this.secondSelectedIndex = null; // 清除第二次选择索引
this.isGameOver = false; // 游戏未结束
this.startTime = Date.now(); // 设置游戏开始时间为当前时间
for (let i = 0; i < 16; i++) { // 重置所有单元格状态
this.gameCells[i].reset();
}
for (let i = this.gameCells.length - 1; i > 0; i--) { // 洗牌算法
const randomIndex = Math.floor(Math.random() * (i + 1)); // 随机索引
let tempValue = this.gameCells[i].value; // 临时保存值
this.gameCells[i].value = this.gameCells[randomIndex].value; // 交换值
this.gameCells[randomIndex].value = tempValue; // 交换值
}
}
// 检查卡片是否匹配的方法
checkForMatch() {
if (this.firstSelectedIndex !== null && this.secondSelectedIndex !== null) { // 确保两个索引都不为空
const firstCell = this.gameCells[this.firstSelectedIndex]; // 获取第一个选中的单元格
const secondCell = this.gameCells[this.secondSelectedIndex]; // 获取第二个选中的单元格
if (firstCell.value === secondCell.value) { // 如果两个单元格的值相同
firstCell.isMatched = true; // 标记为已匹配
secondCell.isMatched = true; // 标记为已匹配
this.firstSelectedIndex = null; // 清除第一次选择索引
this.secondSelectedIndex = null; // 清除第二次选择索引
if (this.gameCells.every(cell => cell.isMatched)) { // 如果所有单元格都已匹配
this.isGameOver = true; // 游戏结束
console.info("游戏结束"); // 打印信息
promptAction.showDialog({ // 显示对话框
title: '游戏胜利!', // 对话框标题
message: '恭喜你,用时:' + ((Date.now() - this.startTime) / 1000).toFixed(3) + '秒', // 对话框消息
buttons: [{ text: '重新开始', color: '#ffa500' }] // 对话框按钮
}).then(() => { // 对话框关闭后执行
this.shuffleCards(); // 重新开始游戏
});
}
} else { // 如果两个单元格的值不同
setTimeout(() => { // 延迟一段时间后
if (this.firstSelectedIndex !== null) { // 如果第一个索引不为空
this.gameCells[this.firstSelectedIndex].hideFace(this.transitionDuration, () => { // 隐藏卡片
this.firstSelectedIndex = null; // 清除第一次选择索引
});
}
if (this.secondSelectedIndex !== null) { // 如果第二个索引不为空
this.gameCells[this.secondSelectedIndex].hideFace(this.transitionDuration, () => { // 隐藏卡片
this.secondSelectedIndex = null; // 清除第二次选择索引
});
}
}, 400); // 延迟时间
}
}
}
// 构建游戏界面的方法
build() {
Column({ space: 20 }) { // 创建一个垂直布局
Flex({ wrap: FlexWrap.Wrap }) { // 创建一个可换行的弹性布局
ForEach(this.gameCells, (gameCell: GameCell, index: number) => { // 遍历游戏单元格
Text(`${gameCell.isVisible ? gameCell.value : ''}`) // 显示单元格的值或空字符串
.width(`${this.cellSize}lpx`) // 设置宽度
.height(`${this.cellSize}lpx`) // 设置高度
.margin(`${this.cellSpacing}lpx`) // 设置边距
.fontSize(`${this.cellSize / 2}lpx`) // 设置字体大小
.textAlign(TextAlign.Center) // 文本居中
.backgroundColor(gameCell.isVisible ? Color.Orange : Color.Gray) // 设置背景颜色
.fontColor(Color.White) // 设置字体颜色
.borderRadius(5) // 设置圆角
.rotate({ // 设置旋转
x: 0,
y: 1,
z: 0,
angle: gameCell.rotationAngle, // 旋转角度
centerX: `${this.cellSize / 2}lpx`, // 中心点X坐标
centerY: `${this.cellSize / 2}lpx`, // 中心点Y坐标
})
.onClick(() => { // 单击事件处理
if (this.isGameOver) { // 如果游戏已结束
console.info("游戏已结束"); // 打印信息
return;
}
if (gameCell.isMatched) { // 如果单元格已匹配
console.info("当前已标记"); // 打印信息
return;
}
if (this.firstSelectedIndex == null) { // 如果没有第一次选择
this.firstSelectedIndex = index; // 设置第一次选择索引
if (!gameCell.isFrontVisible) { // 如果不是正面朝上
gameCell.revealFace(this.transitionDuration); // 展示正面
}
} else if (this.firstSelectedIndex == index) { // 如果与第一次选择相同
console.info("和上一次点击的是一样的,不予处理"); // 打印信息
} else if (this.secondSelectedIndex == null) { // 如果没有第二次选择
this.secondSelectedIndex = index; // 设置第二次选择索引
if (!gameCell.isFrontVisible) { // 如果不是正面朝上
gameCell.revealFace(this.transitionDuration, () => { // 展示正面
this.checkForMatch(); // 检查是否匹配
});
}
}
});
});
}.width(`${(this.cellSize + this.cellSpacing * 2) * 4}lpx`); // 设置宽度
Button('重新开始') // 创建“重新开始”按钮
.onClick(() => { // 按钮点击事件
this.shuffleCards(); // 重新开始游戏
});
}.height('100%').width('100%'); // 设置高度和宽度
}
}