6-猜拳游戏

0 阅读4分钟

任务

需求

模拟人和计算机玩猜拳游戏,玩家输入名字,进入游戏界面,玩家先出拳,选择对应石头剪刀布的图片,然后计算机产生1~3之间随机数和人出的拳进行比较,确定此轮输赢,一共3轮,3轮结果是最终结果,显示计算机还是人赢了,游戏结束。

随机数对应约定如下:

1:石头

2:剪刀

3:布

界面原型

游戏首页:

image-20250321100433114.png

游戏启动页:

image-20250321134105284.png

模拟出拳页面:

image-20250321144855283.png

出拳结果展示:

image-20250321145044470.png

涉及知识点

  1. 主轴对齐,交叉轴对齐
  2. 使用背景图片
  3. 自定义组件生命周期
  4. 路由跳转
  5. Progress组件
  6. 定时器
  7. AppStorage:应用全局UI状态存储

1 游戏首页

1)新建游戏首页

在pages下新建页面,命名为:GuessFistIndexPage,删除原有代码,并编写如下骨架代码:

//猜拳游戏入口
@Entry
@Component
struct GuessFistIndexPage {
  @State title: string = '猜拳大作战'


  build() {
    Column() {




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

2)游戏首页UI

设置背景图片,添加标题,玩家输入框、游戏按钮,控制对齐方式:

  build() {
    Column() {

      Text(this.title)
        .fontColor(Color.Green)
        .fontSize(38)
        .fontWeight(FontWeight.Bold)

      Column({space:10}){
        TextInput({placeholder:'请输入玩家名字'})
          .width('95%')
          .height(50)

        Button('开始游戏')
          .width('95%')
          .height(50)
          .fontSize(22)
          .backgroundColor(Color.Orange)
      }


    }
    .height('100%')
    .width('100%')
    .backgroundImage($r('app.media.guess_fist_bg'))
    .backgroundImageSize(ImageSize.Cover)
    .justifyContent(FlexAlign.SpaceAround)
  }

[!NOTE]

justifyContent:控制组件沿主轴方向对齐

backgroundImage和backgroundImageSize配合控制图片背景铺设方式

预览效果:

image-20250321094639514.png

2 模拟启动页面

在启动游戏前我们模拟一个启动页面,在启动页面给出进度组件,并在3秒后进入游戏猜拳主页。

1)创建页面

在pages下新建页面,命名为LoadingPage,清理后代码如下:

@Entry
@Component
struct LoadingPage {


  build() {
    Column() {


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

2)添加提示信息,并给出进度条

添加Text组件显示玩家正进入游戏,并给出进度条提示:

@Entry
@Component
struct LoadingPage {
  @State playerName: string = 'Jerry'

  build() {
    Column() {
      Text(`玩家:[${this.playerName}]正进入游戏...`).fontSize(20)
        .fontWeight(FontWeight.Bold)
      Progress({ value: 33, total: 99, type: ProgressType.ScaleRing })
        .color(Color.Grey).value(33).width(150)
        .style({ strokeWidth: 15, scaleCount: 15, scaleWidth: 5 })


    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.SpaceAround)
  }
}

[!NOTE]

定时3秒,progress设置为99,每次步进33

Progress组件参考:

developer.huawei.com/consumer/cn…

预览效果:

image-20250321101516981.png

3)进度条定时

进度条定时3秒,3秒后进入游戏主页。

先定义变量,保存进度条初始值

  @State currentValue: number = 33
  @State currentColorValue: number = 33//进度条带颜色部分

修改进度条,使用初始值设置progress组件

      Progress({ value: this.currentValue, total: 99, type: ProgressType.ScaleRing })
        .color(Color.Grey).value(this.currentColorValue).width(150)
        .style({ strokeWidth: 15, scaleCount: 15, scaleWidth: 5 })

页面出现时,开始计时3秒,并刷新进度条显示

先在前面定义定时器变量:

private timer:number = 0;//定时器

编写组件生命周期函数:aboutToAppea,设置计时器,计时3秒,然后销毁:

  aboutToAppear() {
    if (this.currentValue <= 99 && this.currentColorValue <= 99) {
      this.timer = setInterval(()=>{
        this.currentValue +=33
        this.currentColorValue += 33
      },1000)
    }
    setTimeout(()=>{
      clearInterval(this.timer)
    },3000)
  }

[!IMPORTANT]

aboutToAppear:组件生命周期函数,组件要出现时触发

还有一个是:aboutToDisappear,组件要消失时触发

预览效果:

image-20250321105151491.png

4)展示玩家名

首先在游戏首页存储玩家名,在GuessFistIndexPage编码,首先定义保存玩家名的变量:

 @State playerName: string = '';//玩家名

为输入框绑定onChange事件,在输入时,将玩家名字保存到变量中:

        TextInput({placeholder:'请输入玩家名字'})
          .width('95%')
          .height(50)
          .onChange((value)=>{
            this.playerName = value
          })

点击开始游戏按钮,存储玩家名并跳转到游戏启动页:

        Button('开始游戏')
          .width('95%')
          .height(50)
          .fontSize(22)
          .backgroundColor(Color.Orange)
          .onClick(()=>{
            //存储玩家名
            AppStorage.setOrCreate('playerName',this.playerName)
            //跳转到游戏启动页
            router.pushUrl({
              url:'pages/LoadingPage'
            })
          })

修改LoadingPage从中获取玩家名:

...
struct LoadingPage {
  //@State playerName: string = 'Jerry'
   @StorageLink('playerName') playerName: string = 'jerry'//从中AppStorage获取玩家名
  ...

[!IMPORTANT]

AppStorage:应用全局的UI状态存储

developer.huawei.com/consumer/cn…

预览效果:

image-20250321111635032.png

跳转到启动页:

image-20250321111711358.png

3 出拳页面

在出拳页面点击石头剪刀布的图片完成出拳。

1)新建页面

在pages下新建页面,命名为:ShowFistPage,并清理原有代码:

@Entry
@Component
struct ShowFistPage {
  @State title: string = '欢迎挑战猜拳游戏';

  build() {
    Column() {
    

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

2)编写猜拳游戏UI

显示标题,剩余轮数,出拳提示及3张图片显示出拳选项,并使用@Extend对图片样式进行封装。

@Entry
@Component
struct ShowFistPage {
  @State title: string = '欢迎挑战猜拳游戏';

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

      Text(this.title).fontSize(30).fontWeight(FontWeight.Bold)
      Text('剩余3轮').fontSize(20)
      Text('请点击对应图片出拳').fontSize(20).fontColor(Color.Red)
      Image($r('app.media.shitou'))
        . fistImageStyle(Color.Red)

      Image($r('app.media.jiandao'))
        .fistImageStyle(Color.Yellow)
      Image($r('app.media.bu'))
        .fistImageStyle(Color.Blue)


    }
    .height('100%')
    .width('100%')
  }
}
@Extend(Image)
function fistImageStyle(color:Color){
  .width(150)
  .height(150)
  .borderRadius(75)
  .borderWidth(2)
  .borderColor(color)

}

预览效果:

image-20250321141528695.png

4 实现猜拳逻辑

1)首先定义所需变量

继续在ShowFistPage中添加代码:

  @State playerName: string = 'Jerry' //玩家名字
  @State times: number = 3 //猜拳次数
  @State computerFist: number = 0 //计算机出拳:1-石头,2-剪刀,3-布
  @State playerFist: number = 0 //玩家出拳
  @State computerScore: number = 0 // 计算机当前得分
  @State playerScore: number = 0 //玩家当前得分
  @State resultMessage:string = '' //猜拳结果提示

2)生成随机数,代计算机出拳

添加genRandom()函数,生成1~3之间的随机数,其值表示计算机出的拳:

  genRandom(min:number,max:number){
    let range = max - min;
    let randNumber = Math.random();
    this.computerFist = min + Math.round(randNumber * range)//四舍五入
    console.info('computerfist:'+this.computerFist)

  }

3)判断猜拳结果

添加judgeResult()函数调用计算机出拳,并判断游戏结果。

判断逻辑:

  1. 检查次数,如果次数用尽提示退出
  2. 计算机出拳
  3. 计算机出拳和玩家出拳对比,判断结果并给赢家+10分
  4. 剩余轮数-1
  5. 如果是最后一轮,比较分数,如果不是仅显示本轮结果
  6. 弹框显示比赛结果
  // 判断猜拳结果
  judgeResult(){

    console.info('player:' + this.playerFist)
    if(this.times <= 0){
      this.resultMessage = '轮数用尽,游戏已退出!!!'
      AlertDialog.show({
        title:'提示',
        message:this.resultMessage,
        confirm:{
          value:'关闭',
          action:()=>{
            console.info('轮数用尽,游戏已退出')
          }
        },
        cancel:()=>{
          console.info('cancel callback')
        }

      })
      return
    }

    //计算机出拳
    this.genRandom(1,3)
    //平局,各加10分
    if(this.computerFist == this.playerFist){
      this.playerScore += 10
      this.computerScore += 10
      this.resultMessage = '本轮平局'

      console.info("palyer分数:"+this.playerScore+"|jsj:"+this.computerScore)
    }else if((this.playerFist == 1 && this.computerFist ==2)
      ||(this.playerFist == 2 && this.computerFist ==3)
      ||(this.playerFist == 3 && this.computerFist ==1)){//玩家赢 +10
      this.playerScore +=10
      this.resultMessage = '本轮你赢了!'
      console.info("palyer分数:"+this.playerScore+"|jsj:"+this.computerScore)
    }else {//计算机赢 +10
      this.computerScore += 10
      this.resultMessage = '本轮计算机赢了!'
      console.info("palyer分数:"+this.playerScore+"|jsj:"+this.computerScore)
    }

    this.times --
    if(this.times == 0){
      let tempMessage = ''
      if(this.computerScore == this.playerScore){
        tempMessage = '平局'
      }else if(this.computerScore > this.playerScore){
        tempMessage = '你输了!!!!'
      }else{
        tempMessage = '你赢了!!!!'

      }
      console.info("最终:"+tempMessage+",palyer分数:"+this.playerScore+"|jsj:"+this.computerScore)
      this.resultMessage = this.resultMessage.concat(`,最终成绩:${tempMessage}`)
    }

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

    })
  }

4)为图片绑定事件开始出拳

猜拳逻辑完成后,需要显示剩余轮数:

 Text(`剩余${this.times}轮`).fontSize(20)

然后为图片绑定事件,进入猜拳逻辑判断:

      Image($r('app.media.shitou'))
        . fistImageStyle(Color.Red)
        .onClick(() => {
          this.playerFist = 1
          this.judgeResult()
          console.info('石头')
        })


      Image($r('app.media.jiandao'))
        .fistImageStyle(Color.Yellow)
        .onClick(() => {
          this.playerFist = 2
          console.info('剪刀')
          this.judgeResult()
        })
      Image($r('app.media.bu'))
        .fistImageStyle(Color.Blue)
        .onClick(() => {
          this.playerFist = 3
          console.info('布')
          this.judgeResult()
        })

测试猜拳逻辑:

开始猜拳:

image-20250321143246879.png

点击石头:

image-20250321143312966.png

点击剪刀:

image-20250321143246879.png

再次点击剪刀:

image-20250321143406636.png

轮数用尽时点击出拳:

image-20250321143449231.png

5)展示玩家名

修改ShowFistPage中代码:

  //@State playerName: string = 'Jerry' //玩家名字
  @StorageLink('playerName')playerName: string = 'Jerry' //玩家名字
  @State title: string = `欢迎${this.playerName}挑战猜拳游戏`;

预览效果:

image-20250321144142968.png

6)从启动页面跳转

修改LoadingPage页面aboutToAppear中的代码,在计时结束后进行路由跳转:

    setTimeout(()=>{
      clearInterval(this.timer)
      router.pushUrl({
        url: 'pages/ShowFistPage'
      })
    },3000)

5 测试游戏

从游戏首页进入:

image-20250321144710073.png

进入启动页:

image-20250321144734855.png

开始出拳:

image-20250321144810586.png

参考

代码仓

gitee.com/snowyvalley…

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