任务
需求
模拟人和计算机玩猜拳游戏,玩家输入名字,进入游戏界面,玩家先出拳,选择对应石头剪刀布的图片,然后计算机产生1~3之间随机数和人出的拳进行比较,确定此轮输赢,一共3轮,3轮结果是最终结果,显示计算机还是人赢了,游戏结束。
随机数对应约定如下:
1:石头
2:剪刀
3:布
界面原型
游戏首页:
游戏启动页:
模拟出拳页面:
出拳结果展示:
涉及知识点
- 主轴对齐,交叉轴对齐
- 使用背景图片
- 自定义组件生命周期
- 路由跳转
- Progress组件
- 定时器
- 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配合控制图片背景铺设方式
预览效果:
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组件参考:
预览效果:
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,组件要消失时触发
预览效果:
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状态存储
预览效果:
跳转到启动页:
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)
}
预览效果:
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()函数调用计算机出拳,并判断游戏结果。
判断逻辑:
- 检查次数,如果次数用尽提示退出
- 计算机出拳
- 计算机出拳和玩家出拳对比,判断结果并给赢家+10分
- 剩余轮数-1
- 如果是最后一轮,比较分数,如果不是仅显示本轮结果
- 弹框显示比赛结果
// 判断猜拳结果
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()
})
测试猜拳逻辑:
开始猜拳:
点击石头:
点击剪刀:
再次点击剪刀:
轮数用尽时点击出拳:
5)展示玩家名
修改ShowFistPage中代码:
//@State playerName: string = 'Jerry' //玩家名字
@StorageLink('playerName')playerName: string = 'Jerry' //玩家名字
@State title: string = `欢迎${this.playerName}挑战猜拳游戏`;
预览效果:
6)从启动页面跳转
修改LoadingPage页面aboutToAppear中的代码,在计时结束后进行路由跳转:
setTimeout(()=>{
clearInterval(this.timer)
router.pushUrl({
url: 'pages/ShowFistPage'
})
},3000)
5 测试游戏
从游戏首页进入:
进入启动页:
开始出拳:
参考
代码仓
##鸿蒙应用开发 ##鸿蒙游戏 ##休闲娱乐