Hello!我是小邢哥—— 13 年编程老炮,实战派技术人,拆解编程技巧、分享副业心得,记录程序员的进阶路,AI 时代一起稳稳向前。
ArkTS 作为 HarmonyOS 原生开发语言,搭配 ArkUI 声明式 UI 框架,简直给开发者插上了高效开发的 “翅膀”—— 代码简洁清爽,跨设备适配还省心!

今天咱们就踩着 HarmonyOS 6.0 的 “技术跳板”,用 ArkTS + ArkUI 造一款好玩到停不下来的石头剪刀布游戏!
功能说明
这款 “欢乐对决版” 石头剪刀布,藏着这些超赞玩法:
- 手势随心选:剪刀✂️、石头、布三大王牌任你 Pick,点一点就能锁定出战手势
- 电脑 “心机” 出拳:随机生成手势不套路,胜负判定快到眨眼间
- 得分实时飘红:你的战绩、电脑积分同步更新,输赢战况一目了然

- 贴心交互提示:没选手势?立马弹出 “小提醒”;赢了输了?结果文字高亮 + 表情加持,情绪拉满
- 全设备适配:手机、平板都能玩,UI 布局自动 “变身”,怎么看都舒服

开发环境准备
开发工具:DevEco Studio 6.0+
HarmonyOS 版本:6.0(API Version 20)
资源准备:剪刀、石头、布、初始占位图 4 张图片资源(放置于 main_pages 目录下的 media 文件夹)
石头剪刀布大作战代码解析:从数据到交互的趣味拆解

1.数据模型:游戏道具的 “身份证”
interface GameOption{
name: string;
icon: Resource;
emoji: string;
}
第一登场的是 GameOption 接口,它就像给剪刀、石头、布发了 “身份证”,规定了每个道具必须有的信息:
- name:道具的中文名字(”剪刀”、”石头”、”布”)
- icon:对应的图片资源(列如 $r(“app.media.jd”) 就是剪刀的图片)
- emoji:emoji 符号(✂️、、),用表情让游戏更直观
然后在组件里,用 gameOptions 数组创建了三个具体道具,相当于把 “身份证” 填好内容,组成了游戏的核心道具库。

2.游戏状态中心:记录一切的 “小本本”
// 游戏核心数据
private gameOptions:GameOption[] = [
{ name: "剪刀", icon: $r("app.media.jd"), emoji: "✂️" },
{ name: "石头", icon: $r("app.media.st"), emoji: "" },
{ name: "布", icon: $r("app.media.bu"), emoji: "" }
];
@State userChoice: number = -1; // 用户选择的索引(-1表明未选择)
@State computerChoice: number = -1; // 电脑选择的索引
@State isComputing: boolean = false; // 电脑选择中状态
@State userScore: number = 0;
@State computerScore: number = 0;
@State round: number = 0; // 回合数
@State resultText: string = "准备好了吗?快来挑战吧!";
@State resultColor: Color = Color.Blue;
@State errorTip: string = "";
组件里一堆带 @State 的变量,就像游戏的 “记忆小本本”,专门记录实时状态,而且一旦记的内容变了,界面会自动跟着变(这就是 ArkUI 的响应式魔法~):
- userChoice/computerChoice:记玩家和电脑选了哪个道具(-1 表明还没选,0 = 剪刀、1 = 石头、2 = 布)
- isComputing:记电脑是不是正在 “思考”(出拳动画中)
- userScore/computerScore:玩家和电脑的分数,赢一局加 1 分
- round:当前是第几回合,每比一次就 + 1
- resultText/resultColor:记录每回合的结果文字和颜色(赢了绿色、输了红色、平了橙色)
- errorTip:当玩家没选就点 “开始对决” 时,用来提示 “请先选一个手势哦~”

3游戏核心逻辑:裁判和动画师的合体
// 重置单局状态
private resetRound() {
this.userChoice = -1;
this.computerChoice = -1;
this.errorTip = "";
}
// 电脑选择动画与逻辑
private async computerChoose() {
this.isComputing = true;
this.resultText = "电脑正在出拳...";
this.resultColor = Color.Gray;
// 随机切换几次干扰视觉,增加趣味性
for (let i = 0; i < 5; i++) {
this.computerChoice = Math.floor(Math.random() * 3);
}
// 最终选择
this.computerChoice = Math.floor(Math.random() * 3);
this.isComputing = false;
this.judgeResult();
}
// 判定胜负
private judgeResult() {
this.round++;
const user = this.userChoice;
const computer = this.computerChoice;
// 胜负逻辑
if (user === computer) {
this.resultText = `第${this.round}回合:平局!${this.gameOptions[user].emoji} vs ${this.gameOptions[computer].emoji} 再来一局吧~`;
this.resultColor = Color.Orange;
} else if (
(user === 0 && computer === 2) ||
(user === 1 && computer === 0) ||
(user === 2 && computer === 1)
) {
this.userScore++;
this.resultText = `第${this.round}回合:你赢啦! ${this.gameOptions[user].emoji} 战胜了 ${this.gameOptions[computer].emoji} 太棒了!`;
this.resultColor = Color.Green;
} else {
this.computerScore++;
this.resultText = `第${this.round}回合:有点可惜~ ${this.gameOptions[computer].emoji} 战胜了 ${this.gameOptions[user].emoji} 再来一次!`;
this.resultColor = Color.Red;
}
}
// 重置游戏
private resetGame() {
this.resetRound();
this.userScore = 0;
this.computerScore = 0;
this.round = 0;
this.resultText = "游戏重置!准备开始新的挑战吧~";
this.resultColor = Color.Blue;
}
这部分是游戏的 “大脑”,包含了各种操作逻辑和动画效果,让游戏能跑起来:
- resetRound ():单局重置小助手每局结束后,把玩家和电脑的选择清空(变回 – 1),错误提示也删掉,相当于 “请双方准备下一局”。
- computerChoose ():电脑的 “假装思考” 秀电脑选拳不是直接出,而是先 “演” 一波:先把 isComputing 设为 true,告知界面 “我要开始选了”循环 5 次随机切换选择(列如快速在剪刀→石头→布之间跳),制造 “思考” 的假象最后选一个最终结果,结束 “思考” 状态,然后调用 judgeResult() 判胜负

- judgeResult ():胜负判定裁判这是最核心的逻辑,用 “剪刀赢布,石头赢剪刀,布赢石头” 的规则判胜负:玩家和电脑选一样?→ 平局,橙色文字提示玩家赢了?→ 玩家分数 + 1,绿色文字欢呼电脑赢了?→ 电脑分数 + 1,红色文字安慰
- resetGame ():全局重置大师不仅重置单局状态,还把分数、回合数全清零,相当于 “游戏重启,一切归零”,适合想重新开始的玩家。

四、游戏舞台搭建:UI 界面的 “华丽演出”
build() {
Column() {
// 标题区域
Column() {
Text(" 石头剪刀布大作战 ")
.fontSize(32)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
.padding(15)
.backgroundColor(Color.Orange)
.borderRadius(10)
.shadow({ radius: 10, color: Color.Orange })
}
.padding(10)
// 计分板
Row() {
Column() {
Text("电脑")
.fontSize(18)
.fontColor(Color.Gray)
Text(this.computerScore.toString())
.fontSize(40)
.fontWeight(FontWeight.Bold)
.fontColor(Color.Gray)
}
.padding(20)
.backgroundColor("#f5f5f5")
.borderRadius(15)
.shadow({ radius: 5 })
Text("VS")
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor(Color.Orange)
.padding(10)
Column() {
Text("玩家")
.fontSize(18)
.fontColor(Color.Gray)
Text(this.userScore.toString())
.fontSize(40)
.fontWeight(FontWeight.Bold)
.fontColor(Color.Blue)
}
.padding(20)
.backgroundColor("#f5f5f5")
.borderRadius(15)
.shadow({ radius: 5 })
}
.padding({ top: 5, bottom: 15 })
// 玩家选择区
Column() {
Text(`你的选择 ${this.userChoice !== -1 ? this.gameOptions[this.userChoice].emoji : ""}`)
.fontSize(20)
.padding(10)
.fontWeight(FontWeight.Medium)
Row({ space: 15 }) {
ForEach(this.gameOptions, (item:GameOption, index) => {
Image(item.icon)
.width("28%")
.height(80)
.objectFit(ImageFit.Contain)
.border({
width: this.userChoice === index ? 5 : 2,
color: this.userChoice === index ? Color.Blue : Color.Gray
})
.borderRadius(15)
.shadow({
radius: this.userChoice === index ? 10 : 3,
color: this.userChoice === index ? Color.Blue : Color.Transparent
})
.onClick(() => {
// 点击动画效果
animateTo({ duration: 200, curve: Curve.EaseOut }, () => {
this.userChoice = index;
});
this.errorTip = "";
})
.padding(5)
})
}
.width("100%")
.justifyContent(FlexAlign.Center)
}
.padding(10)
.backgroundColor("#fff")
.borderRadius(20)
.margin({ left: 15, right: 15 })
.shadow({ radius: 5 })
// 电脑选择区
Column() {
Text(`电脑选择 ${this.computerChoice !== -1 && !this.isComputing ? this.gameOptions[this.computerChoice].emoji : ""}`)
.fontSize(20)
.padding(10)
.fontWeight(FontWeight.Medium)
if (this.isComputing) {
// 加载动画
Image($r("app.media.stj"))
.width("60%")
.height(100)
.objectFit(ImageFit.Contain)
.borderRadius(15)
.rotate({ angle: this.isComputing ? 360 : 0 })
.animation({ duration: 1000, iterations: -1, curve: Curve.Linear })
} else {
Image(this.computerChoice === -1 ? $r("app.media.stj") : this.gameOptions[this.computerChoice].icon)
.width("60%")
.height(180)
.objectFit(ImageFit.Contain)
.borderRadius(15)
.border({ width: 2, color: "#fff1efef" })
.animation({ duration: 500, curve: Curve.EaseIn })
}
}
.padding(10)
.backgroundColor("#fff")
.borderRadius(20)
.margin({ left: 15, right: 15, top: 10 })
.shadow({ radius: 5 })
// 操作区
Column({ space: 15 }) {
Row({ space: 15 }) {
Button("开始对决")
.width("45%")
.height(50)
.fontSize(18)
.backgroundColor(Color.Orange)
.borderRadius(25)
.onClick(() => {
if (this.userChoice === -1) {
this.errorTip = "请先选择一个手势哦~ ";
return;
}
this.computerChoose();
})
Button("重新开始")
.width("45%")
.height(50)
.fontSize(18)
.backgroundColor(Color.Gray)
.borderRadius(25)
.onClick(() => {
animateTo({ duration: 300 }, () => {
this.resetGame();
});
})
}
.width("100%")
.padding({ left: 15, right: 15 })
// 结果提示
Text(this.resultText)
.fontSize(14)
.fontColor(this.resultColor)
.padding(10)
.textAlign(TextAlign.Center)
.width("90%")
.backgroundColor("#f9f9f9")
.borderRadius(10)
// 错误提示
Text(this.errorTip)
.fontSize(16)
.fontColor(Color.Orange)
.padding(5)
}
.padding(10)
}
.width("100%")
.height("100%")
.backgroundColor("#f0f2f5")
.padding({ bottom: 30 })
}
}
build() 方法就像搭建游戏舞台,把各个区域按顺序摆好,让玩家看得舒服、玩得顺手:
- 标题区:吸睛的 “游戏招牌”橙色背景 + 白色粗体文字 ” 石头剪刀布大作战 “,再加上阴影效果,一眼就知道这是个好玩的游戏。
- 计分板:胜负的 “实时看板”左右分栏显示电脑和玩家的分数,中间用 “VS” 隔开,灰色代表电脑,蓝色代表玩家,数字超大超醒目,输赢一眼看清。
- 玩家选择区:你的 “出拳操作台”上面文字提示 “你的选择”,选了之后会显示对应的 emoji(列如选了剪刀就显示✂️)下面三个图片按钮(剪刀、石头、布),选中的会有蓝色粗边框 + 阴影,像被 “高亮选中”,点击时还有 200ms 的动画,手感超爽

- 电脑选择区:对手的 “神秘操作区”电脑没选时显示默认图片,选的时候(isComputing为 true)会播放旋转动画(360 度不停转),像在 “快速翻牌”选完后会用 500ms 的动画平滑切换到最终选择的图片,仪式感拉满

- 操作区:游戏的 “控制中心”两个按钮:”开始对决”(橙色,点了之后电脑开始选拳)和 “重新开始”(灰色,点了会用动画重置所有状态)结果提示区:用不同颜色显示每回合结果,背景浅灰,文字居中,清晰又不刺眼错误提示区:当玩家没选就点对决时,会显示橙色提示文字,友善提醒
总结
这样一套兼顾逻辑严谨性和交互趣味性的代码,既能轻松 get ArkUI 开发精髓,又能快速打造出一款让人上瘾的小游戏。不妨动手替换资源试试,让你的石头剪刀布大作战更具专属风格吧!
© 版权声明
文章版权归作者所有,未经允许请勿转载。
相关文章
暂无评论...
