文章来自于catlikecoding,原文作者介绍了如何用Unity制作一个模拟时钟。本文翻译了具体的制作过程。
介绍
在这个教程里,我们写一个简短的C#脚本来模拟时钟的指针,你将会学到:
· 创建对象层次结构
· 创建脚本应用到对象
· 访问命名空间
· 使用update函数
· 旋转基于时间的东西
假设你已经对Unity的编辑器有了基本的了解,只要你玩了几分钟的Unity你就可以开始了。
创建时钟
先创建一个新的Unity工程。默认场景包含一个基于 (0, 1, -10) 、俯视Z轴的相机。为了获得和场景视图相机相似的视角,选择相机,然后从菜单中选择GameObject /Align View to Selected。
我们需要一个对象结构来代表时钟,从GameObject /Create Empty创建一个空游戏对象,命名为Clock。为它创建三个子对象,分别命名为Hours, Minutes,以及 Seconds,确保它们都在(0,0,0)位置。
我们用简单的方块来表示时钟的指针。通过GameObject / CreateOther / Cube为每一个指针创建子cube。时针的位置是(0, 1, 0),大小(0.5, 2, 0.5)。分针的位置是(0, 1.5, 0),大小(0.25, 3, 0.25)。秒针的位置 (0, 2, 0),大小(0.1, 4, 0.1)。
激活时钟
激活时钟需要一个脚本。在Project视图里选择Create / C# Script 来创建一个新的C#脚本,命名为ClockAnimator。打开这个脚本并清空,这样我们就可以从头开始。
首先我们想从UnityEngine的命名空间使用一些东西,然后声明ClockAnimator的存在。它是一个从MonoBehaviour.继承的公共有效的class 。
这为我们提供了最小的类,可以用来创建组件,保存它,然后应用到Clock 对象,这可以从 Project视图拖拽到 Hierarchy 视图,或者通过Add Component 按钮来实现。
using UnityEngine;
public class ClockAnimator : MonoBehaviour {
}
为了激活指针,我们需要进入Transform组件,在脚本中为每个指针添加公共Transform变量并保存。这些公共变量将允许你指定对象到编辑器中的组件属性。然后编辑器会抓取对象的Transform组件并指定到变量。选择Clock对象,然后把相应的对象拖拽到新的属性上。
using UnityEngine;
public class ClockAnimator : MonoBehaviour {
public Transform hours, minutes, seconds;
}
属性为空与填好属性的ClockAnimator
接下来,给脚本添加update函数。这个函数比较特别,每帧都会被调用。我们用它来设置时钟指针的旋转。
保存脚本之后,编辑器就会主要到组件是有更新函数的,并且会展示一个复选框来让我们禁用它,当然我们是不会禁用的。
using UnityEngine;
public class ClockAnimator : MonoBehaviour {
public Transform hours, minutes, seconds;
void Update()
{
//currently do nothing
}
}
更新ClockAnimator使其有个复选框
时针每小时旋转 360/12 度,分针每分钟旋转 360/60 度,秒针每秒钟旋转 360/60 度,为了方便起见爱你,我们把这些值定义为私有常数浮点值。
using UnityEngine;
public class ClockAnimator : MonoBehaviour {
private const float
hoursToDegrees = 360f / 12f,
minutesToDegrees = 360f / 60f,
secondsToDegrees = 360f / 60f;
public Transform hours, minutes, seconds;
void Update()
{
//currently do nothing
}
}
每次更新我们都需要知道当下的时间来使其有效。系统命名空间包含DateTime struct,这能完成此项任务。它有一个叫做Now的静态属性,包含当下时间。每次更新都需要抓取他并存储在一个临时变量里。
using UnityEngine;
using System;
public class ClockAnimator : MonoBehaviour {
private const float
hoursToDegrees = 360f / 12f,
minutesToDegrees = 360f / 60f,
secondsToDegrees = 360f / 60f;
public Transform hours, minutes, seconds;
void Update()
{
DateTime time = DateTime.Now;
}
}
为了使指针旋转起来,我们需要改变他们的局部旋转。直接设置指针的localRotation就可以,这要使用四元数。四元数可以定义任意的旋转。
由于我们是俯视Z轴的,而且Unity使用的是左手坐标系统,旋转必须围绕着Z轴的负半轴。
using UnityEngine;
using System;
public class ClockAnimator : MonoBehaviour {
private const float
hoursToDegrees = 360f / 12f,
minutesToDegrees = 360f / 60f,
secondsToDegrees = 360f / 60f;
public Transform hours, minutes, seconds;
void Update()
{
DateTime time = DateTime.Now;
hours.localRotation = Quaternion.Euler(0f, 0f, time.Hour * -hoursToDegrees);
minutes.localRotation = Quaternion.Euler(0f, 0f, time.Minute * -minutesToDegrees);
seconds.localRotation = Quaternion.Euler(0f, 0f, time.Second * -secondsToDegrees);
}
}
时钟展示
改进时钟
出效果了!在play模式下,时钟显示当下时间。然而,它只显示离散的步骤,仅仅像一个电子时钟。让我们加一个选项来使其展示模拟时间。在脚本里添加一个公共布尔变量analog,用它来决定在update函数中应该做些什么。我们可以在编辑其中切换这个值,甚至在play模式下也可以。
using UnityEngine;
using System;
public class ClockAnimator : MonoBehaviour {
private const float
hoursToDegrees = 360f / 12f,
minutesToDegrees = 360f / 60f,
secondsToDegrees = 360f / 60f;
public Transform hours, minutes, seconds;
public bool analog;
void Update()
{
if (analog)
{
//currently do nothing
}
else
{
DateTime time = DateTime.Now;
hours.localRotation = Quaternion.Euler(0f, 0f, time.Hour * -hoursToDegrees);
minutes.localRotation = Quaternion.Euler(0f, 0f, time.Minute * -minutesToDegrees);
seconds.localRotation = Quaternion.Euler(0f, 0f, time.Second * -secondsToDegrees);
}
}
}
ClockAnimator允许模拟模式
对于模拟选项,我们需要一个稍有不同的方法。现在我们要使用DateTime.Now.TimeOfDay代替DateTime,这是一个TimeSpan,允许我们访问稍逝的小时、分钟以及秒。由于这些值是双重提供的-双精数浮点-点值-我们需要将其转换成浮点数。
using UnityEngine;
using System;
public class ClockAnimator : MonoBehaviour {
private const float
hoursToDegrees = 360f / 12f,
minutesToDegrees = 360f / 60f,
secondsToDegrees = 360f / 60f;
public Transform hours, minutes, seconds;
public bool analog;
void Update()
{
if (analog)
{
TimeSpan timespan = DateTime.Now.TimeOfDay;
hours.localRotation =
Quaternion.Euler(0f, 0f, (float)timespan.TotalHours * -hoursToDegrees);
minutes.localRotation =
Quaternion.Euler(0f, 0f, (float)timespan.TotalMinutes * -minutesToDegrees);
seconds.localRotation =
Quaternion.Euler(0f, 0f, (float)timespan.TotalSeconds * -secondsToDegrees);
}
else
{
DateTime time = DateTime.Now;
hours.localRotation = Quaternion.Euler(0f, 0f, time.Hour * -hoursToDegrees);
minutes.localRotation = Quaternion.Euler(0f, 0f, time.Minute * -minutesToDegrees);
seconds.localRotation = Quaternion.Euler(0f, 0f, time.Second * -secondsToDegrees);
}
}
}
现在时钟能够模拟工作啦
模拟时钟显示