下面我将介绍如何在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对(困难)等
  }
}

功能扩展建议

  1. ​主题系统​​:添加多套卡片主题供玩家选择
  2. ​计时模式​​:添加计时挑战模式
  3. ​音效系统​​:添加翻牌、匹配成功等音效
  4. ​动画效果​​:添加卡片翻转动画、匹配成功动画
  5. ​成就系统​​:记录玩家最佳成绩和成就
  6. ​多人模式​​:添加双人轮流游戏模式
  7. ​排行榜​​:记录并展示玩家高分记录

注意事项

  1. 确保所有卡片图片资源已添加到resources/base/element目录
  2. 根据设备屏幕尺寸调整卡片大小和布局
  3. 游戏难度(卡片对数)应根据设备屏幕大小动态调整
  4. 考虑添加加载动画,特别是图片资源较多时
  5. 对于ArkUI-X的跨平台特性,可以在不同设备上测试游戏体验

这个记忆翻牌游戏展示了ArkUI-X的组件化开发能力,通过组合不同的组件和数据绑定,实现了一个完整的休闲益智游戏。你可以根据需要进一步扩展和完善游戏功能。

Logo

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

更多推荐