【菜菜丸的菜鸟教程】制作带闹铃和振动功能的仿真闹钟

news2024/10/7 12:19:05
一、准备闹钟模型
(一)下载模型
从Unity资源商店和其他模型网站可以下载到各种各样的闹钟模型。为了帮助大家了解机械钟表的设置原理,建议使用带有时针、分针和秒针的钟表,如下图。
注意:时针、分针和秒针最好是挂在闹钟父物体下的三个独立的子物体。
(二)指针归零
如果模型默认的指针未指向12点的位置,那么我们需要手动将其归零。归零后的钟表指针位置如下:
归零后,要观察并记住Inspector中各指针的本地Transform旋转角度(Rotation),这个角度在接下来的脚本中会用到。比如,我的模型各指针旋转角度如下:
二、令闹钟显示当前时间
在Project窗口中新建一个名为Clock的脚本,挂到闹钟物体上。
首先声明变量,除了时针、分针、秒针三个GameObject变量以外,还要声明一个DateTime变量来获取系统时间。因为后面我们还要声明其他变量,为方便区分,可以在这些变量前面加个Header,如下:
    
    
[ Header ( "Clock Parts" ) ] public GameObject hourHand ; public GameObject minuteHand ; public GameObject secondHand ; DateTime currentTime ;
用System.DateTime.Now可以获得当前系统时间。
currentTime.Hour:当前小时数
currentTime.Minute:当前分钟数
currentTime.Second:当前秒数
    
    
currentTime = System . DateTime . Now ;
那么,如何将系统时间转换为指针的旋转角度呢?以时针为例,可能有小伙伴认为,直接用系统时间的小时数乘以360度再除以24不就行了吗?
这里有两个问题。首先,虽然1天有24个小时,但机械钟表是12小时制,需要先进行换算。第二,时针旋转的角度不仅受到小时数的影响,也受到分钟数和秒数的影响。比如,14:00:00和14:30:00、14:30:40的时针旋转角度肯定是不同的。
带着这个思路,我们先来写时针旋转角度的脚本。
    
    
hourHand . transform . localRotation = UnityEngine . Quaternion . Euler ( 0.0f , 0.0f , ( 90.0f + ( ( currentTime . Hour % 12.0f ) * 360.0f / 12.0f ) + ( ( 360.0f / 12.0f ) * ( currentTime . Minute % 60.0f ) / 60.0f ) + ( ( 360.0f / 12.0f ) * ( currentTime . Second % 60.0f ) / 3600.0f ) ) ) ;
掌握原理之后,分针和秒针旋转角度的计算也是同理。
    
    
void Update ( ) { //更新系统时间并转化为对应的指针旋转角度 currentTime = System . DateTime . Now ; hourHand . transform . localRotation = UnityEngine . Quaternion . Euler ( 0.0f , 0.0f , ( 90.0f + ( ( currentTime . Hour % 12.0f ) * 360.0f / 12.0f ) + ( ( 360.0f / 12.0f ) * ( currentTime . Minute % 60.0f ) / 60.0f ) + ( ( 360.0f / 12.0f ) * ( currentTime . Second % 60.0f ) / 3600.0f ) ) ) ; minuteHand . transform . localRotation = UnityEngine . Quaternion . Euler ( 0.0f , 0.0f , ( 90.0f + ( ( currentTime . Minute % 60.0f ) * 360.0f / 60.0f ) + ( ( 360.0f / 60.0f ) * ( currentTime . Second % 60.0f ) / 60.0f ) ) ) ; secondHand . transform . localRotation = UnityEngine . Quaternion . Euler ( ( 270.0f - ( ( currentTime . Second % 60.0f ) * 360.0f / 60.0f ) ) , 90.0f , 0.0f ) ; }
写好脚本后,将时针、分针、秒针的GameObject分别拖入相应栏位。
现在运行游戏,闹钟将会显示为当前的系统时间!
三、UI制作
(一)显示界面
显示界面中,将显示当前闹铃时间,以及闹钟的设定按钮和停止按钮。
首先,在Hierarchy窗口中单击右键,选择UI>Canvas,新建画布。在Canvas下新建空物体,重命名为Group,用作显示界面各元素的父物体。
在Group下新建两个Button,分别命名为Set Ring和Stop Ring,将按钮文字分别改为“设定闹铃”和“停止闹铃”,并调整按钮至合适的位置和大小。
再在Group下新建两个Text,并排放置,给第二个Text重命名为Time,将Text的默认文字分别改为“当前闹铃时间:”和“未设定闹铃”,并调整文字的大小、颜色等参数。
制作好的显示界面UI如下所示:
(二)设定闹钟界面
新建一个空物体,命名为Setting Panel,将Transform归零。在Setting Panel下新建画布Canvas。在Canvas下再新建一个Panel,命名为Background,作为闹钟设定界面的背景图,并按需要调整大小、颜色和背景图片(Source Image)。本例中将这张背景图放在屏幕正中。
在Background下新建一个下拉列表(UI>Dropdown)和一个Text,二者并排放在背景图左上,将下拉列表重命名为Dropdown-Hour,将Text的文字改为“时”。点开下拉列表时,应显示24小时制的所有可选小时数,即0-23,所以我们需要在该下拉列表的Options中加入这些选项,如图。
设定分钟和秒的UI制作同理,只不过下拉列表的项数变为60项(0-59)。将分钟和秒的下拉列表分别重命名为“Dropdown - Minute”和“Dropdown - Second”。完成后的UI如下所示:
然后,在Background下新建两个按钮,分别重命名为“Confirm Button”和“Cancel Button”按钮文字分别为“确定”和“取消”。完成后,设定闹钟界面如下图所示:
最后,取消勾选Setting Panel,使之隐藏。
四、设定闹铃脚本
这部分脚本将存储设定的闹铃时间,并显示在UI中。
首先声明变量,为了方便区分,仍然建议在声明变量之前加个Header。
    
    
[ Header ( "UI Elements" ) ] public GameObject settingPanel ; public Button settingRingBtn ; public Button stopRingBtn ; public Button confirmBtn ; public Button cancelBtn ; public Dropdown hourDropdown ; public Dropdown minuteDropdown ; public Dropdown secondDropdown ; public Text timeText ; int hours ; int minutes ; int seconds ;
声明变量后,回到Unity中,为变量赋值。
编写以下脚本,其中包括三个方法,分别用来打开设定面板、设定闹铃时间和关闭设定面板。
    
    
//打开设定面板 void OpenSettingPanel ( ) { settingPanel . SetActive ( true ) ; } //设定闹铃时间 void SettingRingTime ( ) { hours = hourDropdown . value ; minutes = minuteDropdown . value ; seconds = secondDropdown . value ; timeText . text = hours + "时" + minutes + "分" + seconds + "秒" ; settingPanel . SetActive ( false ) ; } //关闭设定面板 void CloseSettingPanel ( ) { settingPanel . SetActive ( false ) ; }
最后,在Start中为按钮添加Listener。
    
    
void Start ( ) { settingRingBtn . onClick . AddListener ( OpenSettingPanel ) ; confirmBtn . onClick . AddListener ( SettingRingTime ) ; cancelBtn . onClick . AddListener ( CloseSettingPanel ) ; }
四、闹钟响铃与振动脚本
(一)闹钟响铃
先从网上找一段你喜欢的闹铃音效,保存在Project>Assets文件夹中。然后,在Clock脚本所附的闹钟物体上添加Audio Source组件,将音频拖进去,如图:
在Update语句块中,加入以下脚本:
    
    
void Update ( ) { //如果系统时间等于设定时间,则闹钟响铃 if ( currentTime . Hour == hours && currentTime . Minute == minutes && currentTime . Second == seconds ) { this . GetComponent < AudioSource > ( ) . Play ( ) ; } }
(二)闹钟振动
在这个案例中,我们不用动画控制闹钟振动,而用代码来实现。这样做的好处是可以方便地调整闹钟振动的幅度、时间等参数。
和上面一样,首先声明闹钟振动相关变量。
    
    
[ Header ( "Shaking Parameters" ) ] public float time = 3.0f ; public float distance = 0.1f ; public float delayBetweenShakes = 0f ; private Vector3 startPos ; private float timer ; private Vector3 randomPos ;
因为闹钟“振动”这个动作需要一定时间,而且可能是反复进行的,所以适合用协程来写,如下:
    
    
//闹钟振动 public void StartShaking ( ) { StopAllCoroutines ( ) ; StartCoroutine ( Shake ( ) ) ; } private IEnumerator Shake ( ) { timer = 0f ; //time为闹钟振动的总时间 while ( timer < time ) { timer += Time . deltaTime ; //生成随机位置,随机位置=初始位置+(单位半径球体内部随机点位置 * 距离乘数) randomPos = startPos + ( UnityEngine . Random . insideUnitSphere * distance ) ; //闹钟移动至该随机位置 transform . position = randomPos ; //delayBetweenShakes表示每次振动之间的时间间隔,如为0则连续振动 if ( delayBetweenShakes > 0f ) { yield return new WaitForSeconds ( delayBetweenShakes ) ; } else { yield return null ; } } //闹钟回到初始位置 transform . position = startPos ; }
注意,time的值最好不长于闹铃音频的时长,否则就会出现闹钟已经不响,但仍然在振动的情况。
只要系统时间等于设定时间,就调用StartShaking方法,让闹钟开始振动。
    
    
void Update ( ) { //如果系统时间等于设定时间,则闹钟开始振动 if ( currentTime . Hour == hours && currentTime . Minute == minutes && currentTime . Second == seconds ) { StartShaking ( ) ; } }
最后,我们可能不想等待闹铃响完,这时点击之前制作的“停止闹铃”就可以关上它。为此,需要写一段停止闹铃的脚本,并在Start语句块中加入对按钮的Listener。
    
    
void Start ( ) { stopRingBtn . onClick . AddListener ( StopRing ) ; } void StopRing ( ) { this . GetComponent < AudioSource > ( ) . Stop ( ) ; StopAllCoroutines ( ) ; //由于中途结束了振动脚本,因此需要令闹钟回到初始位置 transform . position = startPos ; }
附:本教程完整脚本
    
    
using UnityEngine ; using System ; using UnityEngine . UI ; using System . Collections ; public class Clock : MonoBehaviour { [ Header ( "Clock Parts" ) ] public GameObject hourHand ; public GameObject minuteHand ; public GameObject secondHand ; DateTime currentTime ; [ Header ( "UI Elements" ) ] public GameObject settingPanel ; public Button settingRingBtn ; public Button stopRingBtn ; public Button confirmBtn ; public Button cancelBtn ; public Dropdown hourDropdown ; public Dropdown minuteDropdown ; public Dropdown secondDropdown ; public Text timeText ; int hours ; int minutes ; int seconds ; [ Header ( "Shaking Parameters" ) ] public float time = 0.2f ; public float distance = 0.1f ; public float delayBetweenShakes = 0f ; private Vector3 startPos ; private float timer ; private Vector3 randomPos ; // Start is called before the first frame update void Start ( ) { //记录闹钟初始位置 startPos = transform . position ; settingRingBtn . onClick . AddListener ( OpenSettingPanel ) ; confirmBtn . onClick . AddListener ( SettingRingTime ) ; cancelBtn . onClick . AddListener ( CloseSettingPanel ) ; stopRingBtn . onClick . AddListener ( StopRing ) ; } // Update is called once per frame void Update ( ) { //更新系统时间并转化为对应的指针旋转角度 currentTime = System . DateTime . Now ; hourHand . transform . localRotation = UnityEngine . Quaternion . Euler ( 0.0f , 0.0f , ( 90.0f + ( ( currentTime . Hour % 12.0f ) * 360.0f / 12.0f ) + ( ( 360.0f / 12.0f ) * ( currentTime . Minute % 60.0f ) / 60.0f ) + ( ( 360.0f / 12.0f ) * ( currentTime . Second % 60.0f ) / 3600.0f ) ) ) ; minuteHand . transform . localRotation = UnityEngine . Quaternion . Euler ( 0.0f , 0.0f , ( 90.0f + ( ( currentTime . Minute % 60.0f ) * 360.0f / 60.0f ) + ( ( 360.0f / 60.0f ) * ( currentTime . Second % 60.0f ) / 60.0f ) ) ) ; secondHand . transform . localRotation = UnityEngine . Quaternion . Euler ( ( 270.0f - ( ( currentTime . Second % 60.0f ) * 360.0f / 60.0f ) ) , 90.0f , 0.0f ) ; //如果系统时间等于设定时间,则闹钟响铃 if ( currentTime . Hour == hours && currentTime . Minute == minutes && currentTime . Second == seconds ) { this . GetComponent < AudioSource > ( ) . Play ( ) ; } //如果系统时间等于设定时间,则闹钟开始振动 if ( currentTime . Hour == hours && currentTime . Minute == minutes && currentTime . Second == seconds ) { StartShaking ( ) ; } } //打开设定面板 void OpenSettingPanel ( ) { settingPanel . SetActive ( true ) ; } //设定闹铃时间 void SettingRingTime ( ) { hours = hourDropdown . value ; minutes = minuteDropdown . value ; seconds = secondDropdown . value ; timeText . text = hours + "时" + minutes + "分" + seconds + "秒" ; settingPanel . SetActive ( false ) ; } //关闭设定面板 void CloseSettingPanel ( ) { settingPanel . SetActive ( false ) ; } //停止闹铃 void StopRing ( ) { this . GetComponent < AudioSource > ( ) . Stop ( ) ; StopAllCoroutines ( ) ; //由于中途结束了振动脚本,因此需要令闹钟回到初始位置 transform . position = startPos ; } //闹钟振动 public void StartShaking ( ) { StopAllCoroutines ( ) ; StartCoroutine ( Shake ( ) ) ; } private IEnumerator Shake ( ) { timer = 0f ; //time为闹钟振动的总时间 while ( timer < time ) { timer += Time . deltaTime ; //生成随机位置,随机位置=初始位置+(单位半径球体内部随机点位置 * 距离乘数) randomPos = startPos + ( UnityEngine . Random . insideUnitSphere * distance ) ; //闹钟移动至该随机位置 transform . position = randomPos ; //delayBetweenShakes表示每次振动之间的时间间隔,如为0则连续振动 if ( delayBetweenShakes > 0f ) { yield return new WaitForSeconds ( delayBetweenShakes ) ; } else { yield return null ; } } //闹钟回到初始位置 transform . position = startPos ; } }
现在,闹钟就制作完毕了。点击播放键来试试效果吧!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据结构】--二叉树

注&#xff1a;本文树和二叉树的概念及结构部分有部分参考了别的文章&#xff0c;其他的二叉树的实现和性质习题等等都是自己一点点写的&#xff0c;创作不易&#xff0c;希望支持&#xff01; ————————————————————— 目录 一. 树概念及结构 1、树概念…

springboot家具商城系统

开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven…

Spring Boot 系列2 -- 配置文件

目录 1. 配置文件的作用 2. 配置文件的格式 3. properties 配置文件说明 3.1 properties 基本语法 3.2 读取配置文件 3.3 properties 缺点 4.yml 配置文件说明 4.1 yml 基本语法 4.2 yml 使用进阶 4.2.1 yml 配置不同数据类型及 null 4.2.2 yml 配置读取 4.2.3 注意…

FPGA学习——点亮流水灯

文章目录 一、前言二、源码三、ModelSim仿真3.1 tb文件源码&#xff1a;3.2 创建项目3.3 ModelSim仿真 一、前言 在FPGA开发板中&#xff0c;一般板载LED默认高电平点亮&#xff0c;因此我们只需要将想要亮起的LED赋值为1即可。 本入门实验要求为每隔1s开发板上的LED轮流亮起&…

STM32 Proteus仿真医用仓库环境控制系统紫外线消毒RS232上传CO2 -0066

STM32 Proteus仿真医用仓库环境控制系统紫外线消毒RS232上传CO2 -0066 Proteus仿真小实验&#xff1a; STM32 Proteus仿真医用仓库环境控制系统紫外线消毒RS232上传CO2 -0066 功能&#xff1a; 硬件组成&#xff1a;STM32F103R6单片机 LCD1602显示器DHT11温度湿度电位器模拟…

高分卫星影像及GIS技术在甘南泥石流灾害中的应用

本文使用的甘南夏河县泥石流灾情专题数据如下&#xff08;来源于高分甘肃中心&#xff09;&#xff1a; &#xff08;1&#xff09;灾前遥感影像 &#xff08;2&#xff09;灾害位置 &#xff08;3&#xff09;基础地理数据&#xff1a;行政区划、交通路网、河流水系、湖泊水库…

前端Vue自定义精美steps步骤条进度条插件 物流信息跟踪展示组件 流程审批跟进组件

随着技术的发展&#xff0c;开发的复杂度也越来越高&#xff0c;传统开发方式将一个系统做成了整块应用&#xff0c;经常出现的情况就是一个小小的改动或者一个小功能的增加可能会引起整体逻辑的修改&#xff0c;造成牵一发而动全身。 通过组件化开发&#xff0c;可以有效实现…

怎么用PDF派工具将Word转成PDF

Word是我们最常用的一种格式文件&#xff0c;它易于编辑&#xff0c;但是安全性和稳定性较差&#xff0c;有时候我们发送给别人的Word文件&#xff0c;接收到打开内容已经乱码。遇到这种情况&#xff0c;我们可以优先将Word文件转换成稳定性好的PDF文件。那么如何进行文件格式转…

如何使用伪元素 ::before 实现 Antd 表单一模一样的 required 红色 * 号

如何使用伪元素 ::before 实现 Antd 表单一模一样的 required 红色 * 号 背景 以一个简单的 Form.Item 包裹 Select 为例 我们去实现它的 * 号 操作 F12 打开控制台选中这个元素上面查看 CSS 属性 仿照这个写在 .less 文件里 // .less .ruleTable::before {display: inlin…

RiProV2主题一级分类显示包含子分类的数量Ritheme主题美化WordPress美化类似的步骤

美化-RiProV2主题一级分类显示包含子分类的数量 WordPress主题一级分类页面显示包含子分类的数量 一级分类显示子分类相加的数量 原主题配置项 原来的RiProV2主题,虽然有个配置用来显示分类下的数量。 但是该数量有个问题,就是一级分类的数量显示不包含该一级分类下二级…

操作系统14:缓冲区和磁盘调度算法

目录 1、缓冲区管理 &#xff08;1&#xff09;单缓冲区和双缓冲区 1.1 - 单缓冲区 1.2 - 双缓冲区 &#xff08;2&#xff09;环形缓冲区/多缓冲区 &#xff08;3&#xff09;缓冲池(Buffer Pool) 3.1 - 缓冲池的组成 3.2 - 缓冲池的工作方式 2、磁盘存储器的性能和调…

面向对象进阶一(static,继承,多态)

面向对象进阶一 一、static二、继承2.1 继承的定义和特点2.2 继承内容、成员变量和成员方法的访问特点2.2.1继承内容2.2.2 成员变量的访问特点2.2.3 成员方法的访问方法、方法的重写 2.3 继承中构造方法的访问特点 三、this、super使用总结四、多态4.1 多态的基本概念4.2 多态调…

MySQL 学习笔记 2:触发器

MySQL 学习笔记 2&#xff1a;触发器 图源&#xff1a;ubiq.co 触发器&#xff0c;就像字面意思那样&#xff0c;它会在数据库某些事件发生时执行一些操作。 具体来说&#xff0c;触发器会在特定表的INSERT、UPDATE、DELETE这些类型的 SQL 语句执行时被“触发”&#xff0c;并…

CopyOnWriteArrayList使用以及原理分析

文章目录 一、CopyOnWriteArrayList的简介二、CopyOnWriteArrayList类的继承关系1、Iterable接口&#xff1a;2、Collection接口&#xff1a;3、List接口&#xff1a;4、Cloneable接口&#xff1a;5、Serializable接口&#xff1a;6、RandomAccess接口&#xff1a; 三、CopyOnW…

模糊图片怎么修复清晰度?这几个方法分享给你~

在我们的日常生活和工作中&#xff0c;经常会遇到图片模糊的问题&#xff0c;这可能是由于拍摄时的手抖、对焦不准确或者图片压缩过度等原因造成的。那么&#xff0c;如何修复模糊的图片&#xff0c;提高其清晰度呢&#xff1f;本文将为您介绍几种方法。 方法一&#xff1a;使…

ABAP调用阿里云接口-短信服务-HTTP协议及签名(abap版本)<转载>

原文链接&#xff1a;https://blog.csdn.net/xiefireworks/article/details/113037650 阿里云接口文档请参考官网地址 https://help.aliyun.com/document_detail/59210.html?spm5176.8195934.J_5834642020.5.11ba4378DLVi4O 此处仅介绍使用ABAP完成阿里云短信服务签名请求的…

树莓派4B的串口UART配置

1 安装串口&#xff1a; 如果没有更换pip源会报错&#xff0c;所以指定安装源 pip install pyserial -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com 修改uart配置&#xff1a; vim /boot/firmware/config.txt 在末尾添加&#xff1a; dtoverlayuart2…

X86架构的Linux(Ubuntu版本)上离线安装CUnit来解决Could not find CUnit(missing:CUNIT_LIBRARY)问题

前言1 下载cunit压缩安装包&#xff1a;CUint-2.1-3.tar.bz2&#xff08;为了安装成功请下载对应版本&#xff09;2 解压安装压缩包3 sudo ./bootstrap --prefix/usr/local/cunit 生成可执行文件configure*4 sudo ./configure --prefix/usr/local/cunit5 sudo make . 编译 &…

Centos安装指定docker版本和docker-compose

目录 一. 直接安装Docker最新镜像源 1. 卸载旧版本的Docker&#xff1a; 2. 安装依赖包&#xff1a; 3. 添加Docker源&#xff1a; 4. 安装Docker&#xff1a; 5. 启动Docker服务&#xff1a; 6. 验证Docker是否安装成功&#xff1a; 二、指定Docker版本安装 1. 查看…

已解决‘mongo‘ 不是内部或外部命令,也不是可运行的程序

已解决&#xff08;MongoDB安装报错&#xff09;‘mongo’ 不是内部或外部命令,也不是可运行的程序 报错代码 粉丝群里的一个小伙伴安装完MongoDB后&#xff0c;在cmd中启动&#xff0c;却说不是可运行的命令&#xff1f; 报错原因 报错原因&#xff1a;由于没有配置环境变量的…