5-积分抽奖

0 阅读5分钟

任务要求

模拟积分抽奖程序,玩家首先输入玩家姓名,跳转到积分抽奖页面,玩家初始积分为1000分,在积分抽奖页面有红黄蓝灰四种卡片,抽中红卡加500分,抽中黄卡加200分,抽中蓝卡减500分,抽到灰卡积分清零。

抽卡规则:

  1. 仅能抽3次
  2. 积分清零不能继续

抽卡完毕后可以查看获奖情况:

L3(分数 ==2500):笔记本

L2(分数>=1500):智能手表

L1(分数>0):钥匙扣

L0(分数<=0):未中奖

界面原型:

1)入口页面:

image-20250318211512204.png

2)抽卡页面:

image-20250319141420132.png

3)开始抽卡:

image-20250319145123510.png

4)抽卡结果:

image-20250319170004308.png

涉及知识点

  1. 常用属性方法,阴影设置

  2. 线性布局,边距,内容对齐

  3. @Styles、@Extend

  4. 路由参数传递

  5. 条件渲染

  6. AlertDialog

1 入口页面

界面原型:

image-20250318211502236.png

1)页面标题

在pages下面新建页面,命名为:ScoreGamePage,清除原有代码,仅留框架代码,然后添加如下代码,完成标题部分:

@Entry
@Component
struct ScoreGamePage {
  @State title: string = '积分抽奖'


  build() {
    Column(){

      Text(this.title)
        .fontSize(44)
        .fontWeight(FontWeight.Bolder)
        .margin(20)

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

  }
}

预览效果:

image-20250318203349768.png

2)布局【好运连连】部分

使用Row布局,【好运】占一行,【连连】占一行。

build() {
    Column({ space: 10 }) {

      Text(this.title)
        ...

      Row({ space: 10 }) {
        Text('好')
          .squareTxt(Color.Red)

        Text('运')

          .squareTxt(Color.Yellow)

      }

      Row({ space: 10 }) {
        Text('连')
          .squareTxt(Color.Blue)
        Text('连')
          .squareTxt(Color.Gray)

      }

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

  }
}

使用@Extend定义全局样式(需要写在组件外面):

@Extend(Text)
function squareTxt(color: Color) {
  .fontSize(50)
  .width(150)
  .height(150)
  .borderRadius(12)
  .backgroundColor(color)
  .textAlign(TextAlign.Center)
  .shadow({radius:8,color:'#ccc',offsetX:20,offsetY:20})

}

[!NOTE]

关于@Extend

1、扩展原生组件

2、属于全局样式,需在组件外定义,必须加function

3、可以传递参数

4、仅可使用所扩展组件的属性方法和所有组件的通用属性方法

预览效果:

image-20250318210339188.png

3)输入玩家名及开始抽奖按钮

继续添加文本输入框和按钮:

      TextInput({placeholder:'请输入您的名字'})
        .width('95%')
        .margin(20)
      Button('开始抽奖')
        .width('95%')
        .height(50)
        .fontSize(22)

预览效果:

image-20250318211139793.png

2 抽奖页面

界面原型:

image-20250319141341004.png

1)新建页面,在pages下面新建页面,命名为:StartScoreGamePage,清理原有代码,然后使用Column布局页面:

@Entry
@Component
struct StartScoreGamePage {


  build() {
    Column() {

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

2)布局统计栏

显示玩家名、分数、剩余次数。

  build() {
    Column() {

      Text('Jerry:得分:1000,剩余次数:3')
        .titleBarTxtStyle()


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

定义样式:

@Extend(Text) function titleBarTxtStyle(){
  .fontSize(20)
  .fontWeight(FontWeight.Bold)
  .fontColor(Color.Green)
  .width('95%')
  .height(80)
  .backgroundColor('#f1f3f5')
  .borderRadius(8)
  .textAlign(TextAlign.Center)
  .margin(10)
}

预览效果:

image-20250318214325495.png

3)卡片区域布局

布局红黄卡片,在一个Row布局中包含一个Column布局,上面显示图片,下面显示文本:

      //卡片区域
      Row({space:5}){
        Column({space:5}){
          Image($r('app.media.redcard'))
            .borderColor(Color.Red)
            .cardStyle()
          Text('红卡')
            .cardTitleStyle(Color.Red)


        }
        Column({space:5}){
          Image($r('app.media.yellowcard'))
            .cardStyle()
            .borderColor(Color.Yellow)
          Text('黄卡')
            .cardTitleStyle(Color.Yellow)
        }

      }
      .margin(5)

卡片图片部分样式封装,使用@Styles:

  @Styles cardStyle(){
    .width('40%')
    .height('25%')
    .borderRadius(18)

    .borderWidth(4)
  }

[!NOTE]

写在组件内

卡片标题样式封装,使用@Extend,写在组件外:

@Extend(Text) function cardTitleStyle(color:Color){
  .fontSize(22)
  .fontWeight(FontWeight.Bold)
  .fontColor(color)
  .margin({top:5})

}

预览效果:

image-20250319110139867.png

使用同样布局,布局蓝卡和灰卡,代码基本类似:

     Row({space:5}){
        Column({space:5}){
          Image($r('app.media.bluecard'))
            .borderColor(Color.Blue)
            .cardStyle()
          Text('蓝卡')
            .cardTitleStyle(Color.Blue)


        }
        Column({space:5}){
          Image($r('app.media.graycard'))
            .cardStyle()
            .borderColor(Color.Gray)
          Text('灰卡')
            .cardTitleStyle(Color.Gray)


        }

      }
      .margin(5)

预览效果:

image-20250319110847014.png

4)触发按钮

添加【我要抽卡】和【抽奖结果】按钮:

      // 触发按钮
      Button('我要抽卡').width('80%').height(50).fontSize(25)
      Button('抽奖结果').width('80%').height(50).fontSize(25)
        .backgroundColor(Color.Orange)

[!NOTE]

注意调整按钮组件父容器设置组件间间隙,此处设置为5

预览效果:

image-20250319111429637.png

3 显示玩家数据

1)替换标题中的硬编码

我们需要修改状态栏中的信息,不再使用硬编码,能够获取玩家名称,得分和剩余次数。

玩家名称需入口页面通过路由参数的方式进行获取,当前得分默认1000分,剩余次数默认3次。

首先定义所需变量:

  @State playerName: string = '匿名'
  @State score:number = 1000
  @State times:number = 3

替换状态栏硬编码:

      //Text('Jerry:得分:1000,剩余次数:3')
      Text(`${this.playerName}:得分:${this.score},剩余次数:${this.times}`)
        .titleBarTxtStyle()

预览效果:

image-20250319112220286.png

2)通过路由传递参数

修改入口页面,通过路由传递参数,首先在ScoreGamePage中定义变量保存玩家名:

  @State playerName: string = ''

为输入框绑定事件,获取输入的玩家名:

      TextInput({placeholder:'请输入您的名字'})
        .width('95%')
        .margin(20)
        //绑定玩家名
        .onChange((value)=>{
          this.playerName = value
        })

为开始抽奖按钮绑定事件进行路由跳转,并传递玩家名,初始分数,次数等:

     Button('开始抽奖')
        .width('95%')
        .height(50)
        .fontSize(22)
        .onClick(() => {
          router.pushUrl({
            url: 'pages/StartScoreGamePage',
            params: {
              // 路由参数传递
              playerName: this.playerName,
              initScore: 1000,
              times: 3
            }
          })
        })

在StartScoreGamePage组件前面定义路由参数接口:

//定义路由参数接口
interface MyRouterParams {
  playerName: string, //玩家名
  initScore: number, // 初始分数
  times: number //抽奖次数
}

在组件头部变量处改为从路由参数中获取:

  //@State playerName: string = '匿名'
  @State playerName: string = (router.getParams() as MyRouterParams).playerName
  @State score: number = (router.getParams() as MyRouterParams).initScore
  @State times: number = (router.getParams() as MyRouterParams).times

[!NOTE]

更多路由api请参考:

developer.huawei.com/consumer/cn…

预览效果:

image-20250319141119675.png

点击开始抽奖按钮后进行跳转:

image-20250319141158621.png

4 实现抽卡功能

1)产生随机数模拟抽卡

抽卡规则:

1:红卡积分加500

2:黄卡积分加200

3:蓝卡积分减500

4:灰卡积分清零

首先在StartScoreGamePage中定义变量保存抽到的卡编号:

  @State cardNum: number = 0;//抽到的卡编号

然后添加函数随机产生卡片编号:

  genCardNumber(max:number,min:number){
    let range = max - min;
    let rand = Math.random();
    this.cardNum = min + Math.round(range * rand);//四舍五入
    if(this.cardNum == 1){
      this.score += 500;//红卡积分加500

    }
    if(this.cardNum == 2){
      this.score += 200;//黄卡积分加100

    }

    if(this.cardNum == 3){
      this.score -= 500;//蓝卡积分减50

    }

    if(this.cardNum  == 4){
      this.score = 0;//灰卡积分清零

    }
    console.info('cardNum:'+this.cardNum +':score:'+this.score)
  }

2)实现抽卡

继续添加函数,实现积分和抽卡次数判断,显示抽卡结果:

drawCard(){
    this.times--
    let msg = ''//对话框提示卡片抽取信息
    //次数和积分同时不为零可以继续
    if (this.times >= 0 && this.score > 0) {
      this.genCardNumber(1, 4)
      if (this.cardNum == 1) {
        msg = '恭喜您:),您抽到了红卡,积分+500!'

      }
      if (this.cardNum == 2) {

        msg = '恭喜您:),您抽到了黄卡,积分+200!'
      }

      if (this.cardNum == 3) {

        msg = '很遗憾:(,您抽到了蓝卡,积分-500!'
      }

      if (this.cardNum == 4) {

        msg = '很遗憾:(,您抽到了灰卡,积分清零!'
      }
      AlertDialog.show({
        title: '提示',
        message: msg,
        confirm:{
          value:'关闭',
          action:()=>{
            console.info('confirm callback')
          }
        },
        cancel:()=>{
          console.info('cancel callback')
        }
      })

    }else{
      //次数用完
      if(this.times <0 ){
        this.times = 0
        msg = '您的抽卡次数已用尽:('

      }else{
        this.times = 0
        msg = '很遗憾,您的积分已用尽,下次再来:('
      }

      AlertDialog.show({
        title: '提示',
        message: msg,
        confirm:{
          value:'关闭',
          action:()=>{
            console.info('confirm callback')
          }
        },
        cancel:()=>{
          console.info('cancel callback')
        }
      })

    }

  }

[!NOTE]

AlertDialog参考api:

developer.huawei.com/consumer/cn…

3)将函数绑定到【我要抽卡】按钮:

      // 触发按钮
      Button('我要抽卡').width('80%').height(50).fontSize(25)
        .onClick(()=>{
          this.drawCard()
        })

4)功能验证

仍然从入口页面开始预览:

image-20250319144315066.png

输入名字后继续:

image-20250319144836127.png

点击我要抽卡按钮:

image-20250319144911742.png

积分清零后不可再次抽卡:

image-20250319144947006.png <img src="转存失败,建议直接上传图片文件 assets/image-20250319144947006.png" alt="image-

5 结果展示

1)新建页面命名为:ScoreGameResultPage,用于展示抽奖结果,删除多余代码,仅留骨架代码:

@Entry
@Component
struct ScoreGameResultPage {


  build() {

  }
}

2)根据中奖等级展示中奖结果图片

首先定义中奖等级,然后在build函数中使用条件渲染展示获奖文字和图片:

@Entry
@Component
struct ScoreGameResultPage {
  @State gradeLevel: number = 1//中奖等级


  build() {

    Column({space:10}){
      if(this.gradeLevel ==3){
        Text('恭喜您,您抽到笔记本一个!')
          .fontSize(22)
          .fontWeight(FontWeight.Bold)
        Image($r('app.media.note'))
          .width(200)
          .height(200)
          .borderRadius(8)

      }else if(this.gradeLevel ==2){
        Text('恭喜您,您抽到手表一个!')
          .fontSize(22)
          .fontWeight(FontWeight.Bold)
        Image($r('app.media.watch'))
          .width(200)
          .height(200)
          .borderRadius(8)
      }else{
        Text('恭喜您,您抽到钥匙扣一个!')
          .fontSize(22)
          .fontWeight(FontWeight.Bold)
        Image($r('app.media.yaoshikou'))
          .width(200)
          .height(200)
          .borderRadius(8)

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

  }
}

预览效果:

image-20250319155147740.png

3)完成结果查看功能

在StartScoreGamePage页面继续编码,首先定义中奖级别:

@State gradelevel: number = 0; // 中奖级别

然后定义结果展示函数:

代码逻辑:

  1. 次数未用尽,不可查看结果
  2. 分数==2500,gradeLevel=3
  3. 分数>=1500,gradeLevel=2
  4. 分数>0,gradeLevel=1
  5. 分数<=0,gradeLevel=0 未中奖
  6. 未中奖不可查看奖品
  7. 其他情况进行路由跳转,进入查看奖品页面

编写函数showResult():

  //显示中奖结果,根据中奖级别进行跳转页面
  showResult(){
    if(this.times >0){
      AlertDialog.show({
        title: '提示',
        message: '您还没有抽完奖,不能查看结果!!!',
        confirm:{
          value:'关闭',
          action:()=>{
            console.info('confirm callback')
          }
        },
        cancel:()=>{
          console.info('cancel callback')
        }
      })
      return
    }

    if(this.score == 2500){
      this.gradelevel = 3
    }
    else if(this.score >= 1500){
      this.gradelevel = 2
    }
    else if(this.score > 0){
      this.gradelevel = 1
    }
    else{
      this.gradelevel = 0
    }

    if(this.gradelevel == 0){
      AlertDialog.show({
        title: '提示',
        message: '您没有抽中任何奖品,下次再来!!!',
        confirm:{
          value:'关闭',
          action:()=>{
            console.info('confirm callback')
          }
        },
        cancel:()=>{
          console.info('cancel callback')
        }
      })
      return
    }

    router.pushUrl({
      url:'pages/ScoreGameResultPage',
      params:{
        gradeLevel: this.gradelevel
      }
    })
  }
}

在抽奖按钮上绑定事件:

     Button('抽奖结果').width('80%').height(50).fontSize(25)
        .backgroundColor(Color.Orange)
        .onClick(()=>{
          this.showResult()//显示中奖结果
        })

在ScoreGameResultPage页面处理路由参数,首先定义接口:

//定义路由参数接口
interface ReultRouterParams {
  gradeLevel: number // 中奖结果
}

从路由中获取参数:

  @State gradeLevel: number = (router.getParams() as ReultRouterParams).gradeLevel

4)功能验证:

从入口页面进入游戏:

image-20250319165647018.png

点击开始抽奖:

image-20250319165717111.png

点击我要抽卡:

image-20250319165741618.png

继续点击我要抽卡,直到抽奖完成:

image-20250319165840872.png

点击抽奖结果:

image-20250319165914036.png

代码仓:

gitee.com/snowyvalley…

##鸿蒙应用开发 ##鸿蒙游戏 ##休闲娱乐