鸿蒙NEXT开发案例:指尖轮盘

news/2024/11/14 18:01:55/文章来源:https://www.cnblogs.com/zhongcx/p/18540339

 

【1】引言

“指尖轮盘”是一个简单而有趣的互动游戏(类似抓阄),这个应用通过触摸屏幕的方式,让玩家参与一个激动人心的游戏,最终选出幸运的赢家。未来可以进一步扩展功能,如增加游戏模式、优化动画效果、增加音效等,提升用户体验。

【2】环境准备

电脑系统:windows 10

开发工具:DevEco Studio NEXT Beta1 Build Version: 5.0.3.806

工程版本:API 12

真机:mate60 pro

语言:ArkTS、ArkUI

【功能概述】

1. 显示标题和游戏说明,引导玩家参与游戏。

2. 支持多位玩家参与,每位玩家以不同颜色的圆形表示。

3. 根据触摸屏幕的手指数量,动态更新界面状态。

4. 实现倒计时功能,倒计时结束后随机选择一位玩家作为赢家。

【技术实现要点】

1. 使用鸿蒙系统提供的组件和状态管理功能,构建界面和处理用户交互。

2. 利用动画效果,为玩家圆形添加缩放动画,增强视觉效果。

3. 通过定时器实现倒计时和随机选择玩家的功能。

4. 处理触摸事件,根据手指数量更新玩家位置和界面状态。

【开发流程】

1. 创建玩家位置类(PlayerPosition),用于管理玩家属性和动画效果。

2. 设计入口组件(WheelGamePage),包含玩家列表、倒计时、触摸事件处理等功能。

3. 构建UI界面,显示标题、说明文本和玩家圆形,实现动态更新和交互效果。

4. 实现倒计时和随机选择玩家的逻辑,提升游戏体验。

【完整代码】

@ObservedV2// 观察类,用于观察属性变化
class PlayerPosition {@Trace isVisible: boolean = false // 玩家是否可见@Trace startX: number = 0 // 玩家起始X坐标@Trace startY: number = 0 // 玩家起始Y坐标@Trace scaleOptions: ScaleOptions = { x: 0.5, y: 0.5 } // 玩家缩放选项cellWidth: number = 100 // 玩家圆形的宽度color: string // 玩家颜色constructor(color: string) { // 构造函数,初始化颜色this.color = color}isRunningAnimation: boolean = false // 动画是否正在运行setShowAnimation() { // 设置显示动画if (!this.isRunningAnimation) { // 如果动画未运行this.isRunningAnimation = true // 标记为正在运行animateToImmediately({// 开始动画delay: 0,duration: 500,curve: Curve.Linear,iterations: 1,onFinish: () => { // 动画完成后的回调console.info(`onFinish 1`)animateToImmediately({// 开始第二个动画delay: 0,duration: 300,iterations: -1,curve: Curve.Linear,onFinish: () => { // 第二个动画完成后的回调console.info(`onFinish 2`)}}, () => {this.scaleOptions = { x: 1.1, y: 1.1 } // 设置缩放})}}, () => {this.scaleOptions = { x: 1.0, y: 1.0 } // 动画结束时重置缩放})}}
}@Entry// 入口组件
@Component
struct WheelGamePage {@State playerList: PlayerPosition[] = [// 玩家列表new PlayerPosition("#26c2ff"),new PlayerPosition("#978efe"),new PlayerPosition("#c389fe"),new PlayerPosition("#ff85bd"),new PlayerPosition("#ff7051"),new PlayerPosition("#fea800"),new PlayerPosition("#ffcf18"),new PlayerPosition("#a9c92a"),]@State showTitle: boolean = true // 是否显示标题@State showInstructions: boolean = true // 是否显示说明@State showCountdown: boolean = false // 是否显示倒计时@State @Watch('countdownNumberChanged') countdownNumber: number = 3 // 倒计时数字@State selectIndex: number = -1 // 最终选中的玩家下标countdownTimerId: number = 0 // 倒计时定时器IDrandomSelectionTimerId: number = 0 // 随机选择定时器IDcountdownNumberChanged() { // 倒计时变化的处理函数if (this.countdownNumber <= 0) { // 如果倒计时结束this.startRandomSelection(); // 开始随机选择} else {this.selectIndex = -1; // 结束随机显示}}startRandomSelection() { // 开始随机选择玩家const len = this.playerList.length + Math.floor(Math.random() * this.playerList.length); // 随机长度const visiblePlayers = this.playerList.filter(player => player.isVisible); // 可见玩家列表console.info(`visiblePlayers:${JSON.stringify(visiblePlayers)}`);let count = 0; // 当前计数let iteration = 0; // 当前迭代次数clearInterval(this.randomSelectionTimerId); // 清除之前的定时器this.randomSelectionTimerId = setInterval(() => { // 设置新的定时器console.info(`count:${count}`);console.info(`iteration:${iteration}`);console.info(`len:${len}`);if (iteration >= len) { // 如果达到迭代次数clearInterval(this.randomSelectionTimerId); // 清除定时器return;}this.selectIndex = count++ % visiblePlayers.length; // 随机选择玩家iteration++; // 增加迭代次数}, 150); // 每150毫秒执行一次}updatePlayerPositions(touchPoints: TouchObject[]) { // 更新玩家位置this.playerList.forEach((player, index) => { // 遍历玩家列表if (index < touchPoints.length) { // 如果触摸点数量大于玩家索引player.isVisible = true // 设置玩家可见player.setShowAnimation() // 设置动画player.startX = touchPoints[index].x // 更新X坐标player.startY = touchPoints[index].y // 更新Y坐标} else {player.isVisible = false // 设置玩家不可见}})}updateTextState(touchCount: number) { // 更新文本状态this.countdownNumber = 3 // 重置倒计时if (touchCount === 0) { // 如果没有触摸this.showTitle = true // 显示标题this.showInstructions = true // 显示说明this.showCountdown = false // 隐藏倒计时} else if (touchCount === 1) { // 如果有一个触摸this.showTitle = false // 隐藏标题this.showInstructions = true // 显示说明this.showCountdown = false // 隐藏倒计时} else if (touchCount >= 2) { // 如果有两个或更多触摸this.showTitle = false // 隐藏标题this.showInstructions = false // 隐藏说明this.showCountdown = true // 显示倒计时clearInterval(this.countdownTimerId) // 清除之前的倒计时this.countdownTimerId = setInterval(() => { // 设置新的倒计时if (this.countdownNumber >= 0) { // 如果倒计时未结束this.countdownNumber-- // 倒计时减一} else {clearInterval(this.countdownTimerId) // 倒计时结束,清除定时器}}, 1000) // 每秒执行一次}}build() { // 构建UIStack() { // 创建堆栈布局Text("指尖轮盘")// 显示标题文本.width('100%')// 宽度100%.height(80)// 高度80.textAlign(TextAlign.Center)// 文本居中.fontSize(20)// 字体大小20.fontColor("#0c0c0c")// 字体颜色.visibility(this.showTitle ? Visibility.Visible : Visibility.Hidden)// 根据状态设置可见性.draggable(false) // 不可拖动Stack() { // 创建另一个堆栈布局Text(`1. 邀请您的朋友一起加入这场激动人心的游戏吧!只需2到${this.playerList.length}位玩家即可开始。\n
2. 准备好后,请每位参与者伸出一根手指轻轻按住手机屏幕。倒计时3秒后,游戏自动启动,或者您也可以手动点击“开始”按钮。\n
3. 紧紧握住你的手指,直到动画结束。幸运之神将会眷顾其中一位玩家,成为本局的赢家!`)// 显示说明文本.textAlign(TextAlign.JUSTIFY)// 文本对齐.fontSize(20)// 字体大小20.fontColor("#0c0c0c")// 字体颜色.padding(20)// 内边距20.visibility(this.showInstructions ? Visibility.Visible : Visibility.None)// 根据状态设置可见性.draggable(false) // 不可拖动Text(this.countdownNumber > 0 ? `倒计时${this.countdownNumber}秒后开始` : ``)// 显示倒计时文本.textAlign(TextAlign.Center)// 文本居中.fontSize(20)// 字体大小20.fontColor("#0c0c0c")// 字体颜色.padding(20)// 内边距20.visibility(this.showCountdown ? Visibility.Visible : Visibility.None)// 根据状态设置可见性.draggable(false)}.width('100%').height('100%') // 设置堆栈宽高.draggable(false)ForEach(this.playerList, (player: PlayerPosition, index: number) => { // 遍历玩家列表Stack() { // 创建堆栈布局Circle()// 创建外圈圆形.width(player.cellWidth + 10)// 外圈宽度比玩家宽度大10.height(player.cellWidth + 10)// 外圈高度比玩家高度大10.fill(player.color)// 填充外圈颜色.fillOpacity(0.5)// 设置外圈透明度为0.5.visibility(player.isVisible ? Visibility.Visible : Visibility.None)// 根据玩家可见性设置外圈可见性.draggable(false)// 外圈不可拖动.scale(player.scaleOptions) // 设置外圈缩放选项Circle()// 创建内圈圆形.width(player.cellWidth)// 内圈宽度.height(player.cellWidth)// 内圈高度.fill(player.color)// 填充内圈颜色.fillOpacity(1)// 设置内圈透明度为1.visibility(player.isVisible ? Visibility.Visible : Visibility.None)// 根据玩家可见性设置内圈可见性.draggable(false)// 内圈不可拖动.scale(player.scaleOptions) // 设置内圈缩放选项}.draggable(false) // 堆栈布局不可拖动.scale(this.selectIndex == index ? { x: 1.5, y: 1.5 } : { x: 1.0, y: 1.0 }) // 根据选中状态设置缩放.margin({ left: player.startX - player.cellWidth / 2, top: player.startY - player.cellWidth / 2 }) // 设置玩家位置})}.align(Alignment.TopStart) // 设置堆栈对齐方式.height('100%') // 设置堆栈高度为100%.width('100%') // 设置堆栈宽度为100%.draggable(false) // 堆栈不可拖动.onTouch((event: TouchEvent) => { // 处理触摸事件if (event.type == TouchType.Down) { // 按下事件this.updatePlayerPositions(event.touches) // 更新玩家位置this.updateTextState(event.touches.length) // 更新文本状态} else if (event.type == TouchType.Move) { // 移动事件this.updatePlayerPositions(event.touches) // 更新玩家位置} else if (event.type == TouchType.Up) { // 抬起事件this.updateTextState(event.touches.length - 1) // 更新文本状态if (event.touches.length - 1 === 0) { // 如果没有触摸this.updatePlayerPositions([]) // 清空玩家位置}} else if (event.type == TouchType.Cancel) { // 取消事件this.updatePlayerPositions(event.touches) // 更新玩家位置}})}
}

  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/831923.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

antD——Warning: `callback` is deprecated. Please return a promise instead.

参考: 1. https://blog.csdn.net/huochai770880/article/details/125925665我的情况 antD表单校验,代码未报错,但提交时控制台报错:Warning: `callback` is deprecated. Please return a promise instead.原报错代码:const validateParams = useCallback((_: RuleObject, …

Qml 中的那些坑(七)---ComboBox嵌入Popup时,滚动内容超过其可见区域不会关闭ComboBox弹窗

最近在写信息提交 ( 表单 ) 的窗口时发现一个奇怪的 BUG: 可以看到,当 `ComboBox` 嵌入 `Popup` 时,点开 `ComboBox`,然后滚动内容超过其可见区域并不会关闭 `ComboBox` 弹窗,并且会超出其 `父 Popup` 范围。【写在前面】 最近在写信息提交 ( 表单 ) 的窗口时发现一个奇怪…

【Cytoscape 3.10软件下载与安装教程】

1、安装包 Cytoscape3.10: 链接:https://pan.quark.cn/s/0fc00372f3a4 提取码:styP Cytoscape3.9 链接:https://pan.quark.cn/s/f2747b32fe54 提取码:ean2 Cytoscape3.8: 链接:https://pan.quark.cn/s/c6092262f108 提取码:24G6 Cytoscape3.7: 链接:https://pan.qua…

max 函数与 min 函数相关

max 函数与 min 函数相关前情概要 只要有两个实数,就会涉及能大小比较的问题,那么只要有两个函数,自然也会涉及能大小比较的问题,比如我们熟悉的两个简单函数 \(y=2x+1\) 和 \(y=-x+1\),做出两个函数的图象如下,从图象可以看出,当 \(x<0\) 时,\(g(x)>f(x)\);当 …

kafka监控

kafka监控部署 kafka使用Prometheus、Grafana和kafka_exporter来构建kafka指标监控 问题背景 在实时场景下,对于数据积压是很常见的,我们更希望如何去快速知道有没有数据积压,目前消费了多少,速度怎么样,趋势如何。可以使用原生命令kafka-consumer-groups.sh --bootstrap-…

实景三维赋能地灾风险管控

在当今社会,随着城市化进程的加速以及工业化的发展,地质灾害成为了威胁人们生命财产安全的重要因素之一。特别是在全球气候变化的背景下,极端天气事件的增多导致地质灾害的发生频率和强度都有所上升。因此,如何有效地进行地质灾害的风险管控,成为当前亟待解决的问题之一。…

20222301 2024-2025-1 《网络与系统攻防技术》实验五实验报告

1.实验内容 (1)从www.besti.edu.cn、baidu.com、sina.com.cn中选择一个DNS域名进行查询,获取如下信息: ①DNS注册人及联系方式 ②该域名对应IP地址 ③IP地址注册人及联系方式 ④IP地址所在国家、城市和具体地理位置 (2)尝试获取BBS、论坛、QQ、MSN中某一好友的IP地址,并…

高级语言程序设计作业 11/11

2024高级语言程序设计:https://edu.cnblogs.com/campus/fzu/2024C 高级语言程序设计课程第五次作业:https://edu.cnblogs.com/campus/fzu/2024C/homework/13304 学号:102400215 姓名:胡加乘1 #include <iostream>using namespace std;#define ROWS 3 #define COLS 5i…

win 11 开发板,windows,ubuntu虚拟机网络互通

确保在同一个网段里面就行 如果ping开发板不通,将win防火墙关闭了试一试 虚拟机使用桥接模式,桥接到正确的网卡上,此处使用的是usb网卡 编辑->虚拟机网络编辑器ubuntu手动设置桥接的网卡信息此处ens32是桥接的网卡 ens33是NAT网卡windows也是同样设置,注意网段保持一致虚拟机…

手把手教你搭建OpenDRIVE道路模型(上)

在自动驾驶技术的研发与验证阶段,OpenDRIVE格式的数据被广泛应用于仿真测试平台的搭建,帮助开发者在虚拟环境中对算法进行高效迭代与优化,从而加速自动驾驶技术的商业化进程,推动汽车行业向更加智能化、自主化的未来发展。 OpenDRIVE作为一种高度专业化的道路建模标准…

SpringBoot项目引入Elasticsearch时启动失败

1、前情提要: https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/installation.html 以上是Elasticsearch对接Java的官方文档(pom依赖部分)我本地Windows安装的Elasticsearch也是8.15.3版本 2、启动报错 *************************** APPLICA…

四款超实用的免费报表工具推荐!轻松选择适合你的数据神器

现如今,报表工具逐渐成为企业数据分析和决策的重要一环。本文将为大家介绍四款免费报表工具,通过这些工具,用户可以轻松地将原始数据转换为直观易懂的报表,帮助决策者更快地获取信息和做出判断。无论是寻求简单易用、实时更新,还是需要强大的数据分析能力的用户,都能在这…