在鸿蒙HarmonyOS 5中使用ArkUI-X实现一个休闲益智类小游戏
·
下面我将介绍如何在HarmonyOS 5中使用ArkUI-X框架实现一个经典的"记忆翻牌"休闲益智游戏。这个游戏需要玩家记忆卡片位置并匹配成对的卡片。
项目结构
/MemoryGame
├── entry
│ └── src
│ ├── main
│ │ ├── ets
│ │ │ ├── components
│ │ │ │ ├── Card.ets // 卡片组件
│ │ │ │ ├── GameBoard.ets // 游戏面板组件
│ │ │ │ ├── GameStatus.ets // 游戏状态显示组件
│ │ │ ├── pages
│ │ │ │ ├── GamePage.ets // 游戏主页面
│ │ │ │ ├── StartPage.ets // 开始页面
│ │ │ ├── model
│ │ │ │ ├── GameData.ets // 游戏数据模型
│ │ ├── resources
│ │ │ ├── base
│ │ │ │ ├── element // 卡片图片等资源
实现步骤
1. 创建数据模型 (GameData.ets)
export class CardItem {
id: number;
value: number; // 卡片值,相同值表示一对
image: Resource; // 卡片正面图片
flipped: boolean = false; // 是否已翻开
matched: boolean = false; // 是否已匹配
constructor(id: number, value: number, image: Resource) {
this.id = id;
this.value = value;
this.image = image;
}
}
export class GameData {
cards: CardItem[] = [];
moves: number = 0;
pairsFound: number = 0;
gameOver: boolean = false;
firstCard: CardItem | null = null;
secondCard: CardItem | null = null;
canFlip: boolean = true; // 控制是否可以翻牌
// 初始化游戏
initGame(pairs: number, images: Resource[]) {
this.cards = [];
this.moves = 0;
this.pairsFound = 0;
this.gameOver = false;
// 创建卡片对
for (let i = 0; i < pairs; i++) {
const image = images[i % images.length];
this.cards.push(new CardItem(i * 2, i, image));
this.cards.push(new CardItem(i * 2 + 1, i, image));
}
// 洗牌
this.shuffleCards();
}
// 洗牌
shuffleCards() {
for (let i = this.cards.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[this.cards[i], this.cards[j]] = [this.cards[j], this.cards[i]];
}
}
// 翻牌
flipCard(card: CardItem): boolean {
if (!this.canFlip || card.flipped || card.matched) {
return false;
}
card.flipped = true;
if (!this.firstCard) {
this.firstCard = card;
return true;
}
this.secondCard = card;
this.moves++;
this.checkForMatch();
return true;
}
// 检查是否匹配
checkForMatch() {
this.canFlip = false;
if (this.firstCard && this.secondCard && this.firstCard.value === this.secondCard.value) {
// 匹配成功
this.firstCard.matched = true;
this.secondCard.matched = true;
this.pairsFound++;
this.firstCard = null;
this.secondCard = null;
this.canFlip = true;
// 检查游戏是否结束
if (this.pairsFound === this.cards.length / 2) {
this.gameOver = true;
}
} else {
// 不匹配,翻回去
setTimeout(() => {
if (this.firstCard) this.firstCard.flipped = false;
if (this.secondCard) this.secondCard.flipped = false;
this.firstCard = null;
this.secondCard = null;
this.canFlip = true;
}, 1000);
}
}
}
2. 创建卡片组件 (Card.ets)
@Component
export struct Card {
@Prop card: CardItem;
@Prop onFlip: () => void;
build() {
Stack() {
// 卡片背面
if (!this.card.flipped) {
Rect()
.width('100%')
.height('100%')
.fill('#3498db')
.radius(10)
.shadow({ radius: 5, color: Color.Black, offsetX: 2, offsetY: 2 })
}
// 卡片正面
if (this.card.flipped || this.card.matched) {
Column() {
Image(this.card.image)
.width('80%')
.height('80%')
.objectFit(ImageFit.Contain)
}
.width('100%')
.height('100%')
.backgroundColor(Color.White)
.radius(10)
.shadow({ radius: 5, color: Color.Black, offsetX: 2, offsetY: 2 })
}
// 已匹配的标记
if (this.card.matched) {
Image($r('app.media.checkmark'))
.width(30)
.height(30)
.position({ x: '80%', y: '80%' })
}
}
.width(80)
.height(120)
.onClick(() => {
if (!this.card.matched) {
this.onFlip();
}
})
}
}
3. 创建游戏面板组件 (GameBoard.ets)
@Component
export struct GameBoard {
@Link gameData: GameData;
build() {
Grid() {
ForEach(this.gameData.cards, (card: CardItem) => {
GridItem() {
Card({
card: card,
onFlip: () => {
this.gameData.flipCard(card);
}
})
}
})
}
.columnsTemplate('1fr 1fr 1fr 1fr')
.rowsTemplate('1fr 1fr 1fr')
.columnsGap(10)
.rowsGap(10)
.width('100%')
.height('70%')
.margin({ top: 20 })
}
}
4. 创建游戏状态组件 (GameStatus.ets)
@Component
export struct GameStatus {
@Link gameData: GameData;
build() {
Row({ space: 20 }) {
Column() {
Text('步数')
.fontSize(14)
Text(this.gameData.moves.toString())
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
Column() {
Text('配对')
.fontSize(14)
Text(`${this.gameData.pairsFound}/${this.gameData.cards.length / 2}`)
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
.margin({ bottom: 20 })
}
}
5. 创建游戏主页面 (GamePage.ets)
@Entry
@Component
struct GamePage {
@State gameData: GameData = new GameData();
@State difficulty: number = 8; // 默认8对卡片
aboutToAppear() {
this.startNewGame();
}
startNewGame() {
const cardImages = [
$r('app.media.card1'),
$r('app.media.card2'),
$r('app.media.card3'),
// 更多卡片图片...
];
this.gameData.initGame(this.difficulty, cardImages);
}
build() {
Column({ space: 20 }) {
// 标题
Text('记忆翻牌游戏')
.fontSize(24)
.fontWeight(FontWeight.Bold)
// 游戏状态
GameStatus({ gameData: $gameData })
// 游戏面板
GameBoard({ gameData: $gameData })
// 控制按钮
Row({ space: 20 }) {
Button('新游戏')
.onClick(() => {
this.startNewGame();
})
Button('难度')
.onClick(() => {
this.showDifficultyDialog();
})
}
// 游戏结束弹窗
if (this.gameData.gameOver) {
this.buildGameOverDialog()
}
}
.width('100%')
.height('100%')
.padding(20)
}
@Builder buildGameOverDialog() {
DialogComponent({
title: '恭喜!',
content: `你用了 ${this.gameData.moves} 步完成了游戏!`,
buttons: [
{
text: '再来一局',
action: () => {
this.startNewGame();
}
}
]
})
}
showDifficultyDialog() {
// 实现难度选择对话框
// 可以设置4对(简单)、8对(中等)、12对(困难)等
}
}
功能扩展建议
- 主题系统:添加多套卡片主题供玩家选择
- 计时模式:添加计时挑战模式
- 音效系统:添加翻牌、匹配成功等音效
- 动画效果:添加卡片翻转动画、匹配成功动画
- 成就系统:记录玩家最佳成绩和成就
- 多人模式:添加双人轮流游戏模式
- 排行榜:记录并展示玩家高分记录
注意事项
- 确保所有卡片图片资源已添加到
resources/base/element目录 - 根据设备屏幕尺寸调整卡片大小和布局
- 游戏难度(卡片对数)应根据设备屏幕大小动态调整
- 考虑添加加载动画,特别是图片资源较多时
- 对于ArkUI-X的跨平台特性,可以在不同设备上测试游戏体验
这个记忆翻牌游戏展示了ArkUI-X的组件化开发能力,通过组合不同的组件和数据绑定,实现了一个完整的休闲益智游戏。你可以根据需要进一步扩展和完善游戏功能。
更多推荐


所有评论(0)