本案例需要实现的是:用户通过点击"立即抽卡"按钮随机获取卡片,集齐六张不同生肖卡后触发胜利界面显示"恭喜获得手机一部",并支持重置游戏重新开始。

下面我将一步一步带你完成这个案例。

首先我们先完成静态页面:将卡片的背面以及角标和按钮静态部署好。

@Entry
@Component
struct Index {
  build() {
    Column() {
      // 一. 初始界面
      Column() {
        // 图片区域
        Flex({ wrap: FlexWrap.Wrap }) {
          Badge({
            count: 1,
            style: { badgeSize: 16, badgeColor: '#f00', fontSize: 14 }
          }) {
            Image($r('app.media.bg_00'))
              .width(80)
          }
          .margin(15)

          Badge({
            count: 1,
            style: { badgeSize: 16, badgeColor: '#f00', fontSize: 14 }
          }) {
            Image($r('app.media.bg_00'))
              .width(80)
          }
          .margin(15)

          Badge({
            count: 1,
            style: { badgeSize: 16, badgeColor: '#f00', fontSize: 14 }
          }) {
            Image($r('app.media.bg_00'))
              .width(80)
          }
          .margin(15)

          Badge({
            count: 1,
            style: { badgeSize: 16, badgeColor: '#f00', fontSize: 14 }
          }) {
            Image($r('app.media.bg_00'))
              .width(80)
          }
          .margin(15)

          Badge({
            count: 1,
            style: { badgeSize: 16, badgeColor: '#f00', fontSize: 14 }
          }) {
            Image($r('app.media.bg_00'))
              .width(80)
          }
          .margin(15)

          Badge({
            count: 1,
            style: { badgeSize: 16, badgeColor: '#f00', fontSize: 14 }
          }) {
            Image($r('app.media.bg_00'))
              .width(80)
          }
          .margin(15)
        }
        .margin({ top: 100, bottom: 50 })
        .padding({ left: 15 })

        // 抽卡按钮
        Button('立即抽卡')
          .width(200)
          .backgroundColor('#ED5B8C')
          .stateStyles({
            clicked: {
              .backgroundColor('#EA446C')
            }
          })
          .animation({
            duration: 1000
          })
      }
    }
  }
}

第二步:准备一下我们的需要用到的数据,如:生肖卡的正面,角标的次数等。同时使用foreach将页面渲染。

// 初始界面卡片接口
interface Card {
  url: string
  num: number
}

@Entry
@Component
struct Index {
  // 初始界面卡片状态
  @State
  images: Card[] = [

//url为图片的地址,unm是角标的次数,也就是每抽到一次卡片,角标数量会进行加1.
    {url: 'app.media.bg_00', num: 0},
    {url: 'app.media.bg_01', num: 0},
    {url: 'app.media.bg_02', num: 0},
    {url: 'app.media.bg_03', num: 0},
    {url: 'app.media.bg_04', num: 0},
    {url: 'app.media.bg_05', num: 0}
  ]

  build() {
    Column() {
      Column() {
        // 图片区域
        Flex({wrap: FlexWrap.Wrap}) {
          ForEach(this.images, (item: Card, index: number) => {
            Badge({
              count: item.num,
              style: {badgeSize: 16, badgeColor: '#f00', fontSize: 14}
            }) {
              Image($r(`${item.url}`))
                .width(80)
            }
            .margin(15)
          })
        }
        .margin({top: 100, bottom: 50})
        .padding({left: 15})
        // 抽卡按钮
        Button('立即抽卡')
          .width(200)
          .backgroundColor('#ED5B8C')
          .stateStyles({
            clicked: {
              .backgroundColor('#EA446C')
            }
          })
          .animation({
            duration: 1000
          })
      }
    }
  }
}

第三步:制作我们的遮罩层,以透明的黑色为背景将整个屏幕占据,然后在中间制作出标题、卡片正面和按钮。

Column({space: 30}) {
  Text('获取生肖卡')
    .fontColor('#F5EBCF')
    .fontSize(25)
    .fontWeight(600)
  Image($r('app.media.img_00'))
    .width(200)
  Button('开心收下')
    .width(200)
    .height(50)
    .backgroundColor(Color.Transparent)
    .border({width: 2, color: '#FFF9E0'})
}
.width('100%')
  .height('100%')
  .backgroundColor('rgba(0,0,0,0.8)')
  .justifyContent(FlexAlign.Center)
  .position({x: 0, y: 0})

第四步:将我们的遮罩层和两个按钮绑定起来并为卡片做缩放的动画。

        在隐藏遮罩层时需要注意一点,属性不可以使用opacity。opacity是透明度 ,它只是视觉效果上看不到了,但还是存在的,会遮挡住下面的组件。所以我们这里使用visibility属性,visibility是隐藏和显示组件。

 // 是否显示生肖卡界面状态
  @State
  isVisible: boolean = false

  // 生肖卡缩放状态
  @State
  imgX: number = 0
  @State
  imgY: number = 0

// 抽卡按钮
Button('立即抽卡')
  .width(200)
  .backgroundColor('#ED5B8C')
  .stateStyles({
    clicked: {
      .backgroundColor('#EA446C')
    }
  })
  .animation({
    duration: 1000
  })
  .onClick(() => {
    this.isVisible = true
    this.imgX = 1
    this.imgY = 1
  })

Column({space: 30}) {
  Image($r('app.media.img_00'))
    .width(200)
    .scale({x: this.imgX, y: this.imgY})
    .animation({duration: 400})
  Button('开心收下')
    .onClick(() => {
      // 生肖卡界面隐藏;卡片隐藏
      this.isVisible = false
      this.imgX = 0
      this.imgY = 0
    })
}
  // 使用状态控制整个界面显隐
  .visibility(this.isVisible ? Visibility.Visible : Visibility.Hidden)

第五步:实现收下卡片后卡牌角标加1和中奖的静态页面

// 随机生肖卡序号
  @State
  randomIndex: number = -1

Button('立即抽卡')
  .onClick(() => {
    // 随机生肖卡 0-5
    this.randomIndex = Math.floor(Math.random() * 6)
  })
Column({space: 30}) {
  // 使用生成的随机数筛选生肖卡
  Image($r(`app.media.img_0${this.randomIndex}`))
  Button('开心收下')
    .onClick(() => {
      // 收下卡片更新对象数组 -- 替换初始界面图片url和角标数字
      this.images[this.randomIndex] = {
        url: `app.media.img_0${this.randomIndex}`,
        num: this.images[this.randomIndex].num += 1
      }
    })
}

// 抽奖页面-遮罩层
Column({space: 50}) {
  Text('恭喜获得手机一部')
    .fontColor('#F5EBCF')
    .fontSize(25)
    .fontWeight(600)
  Image($r('app.media.hw'))
    .width(300)
  Button('再来一次')
    .width(200)
    .height(50)
    .backgroundColor(Color.Transparent)
    .border({width: 2, color: '#FFF9E0'})
}
.width('100%')
  .height('100%')
  .backgroundColor('rgba(0,0,0,0.8)')
  .justifyContent(FlexAlign.Center)
  .position({x: 0, y: 0})

第六步:实现是否中奖的判断和中奖之后的页面以及重新开始。

 Column({ space: 50 }) {
          Text('恭喜获得手机一部')
            .fontColor('#F5EBCF')
            .fontSize(25)
            .fontWeight(600)
          Image($r('app.media.hw'))
            .width(300)
          Button('再来一次')
            .width(200)
            .height(50)
            .backgroundColor(Color.Transparent)
            .border({ width: 2, color: '#FFF9E0' })
            .onClick(() => {
              this.ifWin = false
              this.cards = [{ url: 'app.media.bg_00', countNum: 0 },
                { url: 'app.media.bg_01', countNum: 0 },
                { url: 'app.media.bg_02', countNum: 0 },
                { url: 'app.media.bg_03', countNum: 0 },
                { url: 'app.media.bg_04', countNum: 0 },
                { url: 'app.media.bg_05', countNum: 0 }]
            })
        }
        .width('100%')
        .height('100%')
        .backgroundColor('rgba(0,0,0,0.8)')
        .justifyContent(FlexAlign.Center)
        .position({ x: 0, y: 0 })
        .visibility(this.ifWin ? Visibility.Visible : Visibility.Hidden)

这样就可以实现一个完整的抽卡游戏了。最后附上全部代码

interface Card {
  url: string
  countNum: number
}

@Entry
@Component
struct Index {
  @State cards: Card[] = [
    { url: 'app.media.bg_00', countNum: 0 },
    { url: 'app.media.bg_01', countNum: 0 },
    { url: 'app.media.bg_02', countNum: 0 },
    { url: 'app.media.bg_03', countNum: 0 },
    { url: 'app.media.bg_04', countNum: 0 },
    { url: 'app.media.bg_05', countNum: 0 }
  ]
  @State isShow: boolean = false
  @State rands: number = 0
  @State imgX: number = 0
  @State imgY: number = 0
  @State ifWin: boolean = false

  build() {
    Column() {
      Column({ space: 60 }) {
        Flex({
          wrap: FlexWrap.Wrap,
          justifyContent: FlexAlign.SpaceBetween
        }) {
          ForEach(this.cards, (item: Card, index: number) => {
            Badge({ count: item.countNum, style: {} }) {
              Image($r(item.url))
                .syncLoad(true)
                .width(100)
            }
          })

        }
        .padding(15)

        Button('立即抽卡')
          .width('70%')
          .backgroundColor(' #e05582 ')
          .onClick(() => {
            this.isShow = true
            this.imgX = 1
            this.imgY = 1
            this.rands = Math.floor(Math.random() * 6)
          })

        Column({ space: 30 }) {
          Text('获取生肖卡')
            .fontColor('#F5EBCF')
            .fontSize(25)
            .fontWeight(600)
          Image($r(`app.media.img_0${this.rands}`))
            .width(200)
            .syncLoad(true)
            .scale({ x: this.imgX, y: this.imgY })
            .animation({})
          Button('开心收下')
            .width(200)
            .height(50)
            .backgroundColor(Color.Transparent)
            .border({ width: 2, color: '#FFF9E0' })
            .onClick(() => {
              this.isShow = false
              this.imgX = 0
              this.imgY = 0

              this.cards[this.rands] =
                { url: `app.media.img_0${this.rands}`, countNum: ++this.cards[this.rands].countNum }
              let count: number = 0

              for (let item of this.cards) {
                if (item.countNum >= 1) {
                  count++
                } else {
                  break
                }
              }
              if (count === 6) {
                this.ifWin = true
              }
            })

        }
        .width('100%')
        .height('100%')
        .backgroundColor('rgba(0,0,0,0.8)')
        .justifyContent(FlexAlign.Center)
        .position({ x: 0, y: 0 })

        //opacity是透明度 ,只是看不见了但是还存在。会遮挡下面的内容。
        // .opacity(this.opaNum)

        //visibility  隐藏和显示组件 Visibility.Visible 是显示 ,Visibility.Hidden 是隐藏
        .visibility(this.isShow ? Visibility.Visible : Visibility.Hidden)


        // 抽奖页面-遮罩层
        Column({ space: 50 }) {
          Text('恭喜获得手机一部')
            .fontColor('#F5EBCF')
            .fontSize(25)
            .fontWeight(600)
          Image($r('app.media.hw'))
            .width(300)
          Button('再来一次')
            .width(200)
            .height(50)
            .backgroundColor(Color.Transparent)
            .border({ width: 2, color: '#FFF9E0' })
            .onClick(() => {
              this.ifWin = false
              this.cards = [{ url: 'app.media.bg_00', countNum: 0 },
                { url: 'app.media.bg_01', countNum: 0 },
                { url: 'app.media.bg_02', countNum: 0 },
                { url: 'app.media.bg_03', countNum: 0 },
                { url: 'app.media.bg_04', countNum: 0 },
                { url: 'app.media.bg_05', countNum: 0 }]
            })
        }
        .width('100%')
        .height('100%')
        .backgroundColor('rgba(0,0,0,0.8)')
        .justifyContent(FlexAlign.Center)
        .position({ x: 0, y: 0 })
        .visibility(this.ifWin ? Visibility.Visible : Visibility.Hidden)

      }
      .height('100%')
      .justifyContent(FlexAlign.Center)

    }
    .width('100%')
    .height('100%')
  }
}

Logo

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

更多推荐