这是 Unity 基础系列教程的第一篇博客。我们将由浅入深,一步一步学习Unity及游戏开发相关的东西。整个系列教程所使用的Unity版本为 2018.4 及以上就可以,如果要使用特殊版本,则会在文中指出。

今天要做的是一个能够实时显示当前时间的时钟,就是下面这个东东。

p002001_Unity-001-1

1 首先建立一个新工程

首先打开Unity,创建一个新工程,名字自己定,例如 Clock 就可以。默认打开后,Unity 默认布局是下面图的样子。

p002002_Unity-001-2

你也可以更新布局,例如换成同时显示View和Game视图的布局,只需要点击编辑器最右上角的那个按钮,然后选择 2 by 3 即可成为下面图的样子。

p002003_Unity-001-3

下面是分辨率的设置,一般游戏开发中,会使用一个基准分辨率,很多游戏采用的是 16:9 的模式。这个在 Game 视图中设置,看下面的图,选择 16:9 即可

p002004_Unity-001-4

1.1 创建一个 GameObject

默认的场景中,会包含两个 GameObject,一个是主相机 MainCamera, 一个是灯光 Directional Light。这两个东西保持默认就好,现在我们创建一个新的物体,在 Hierarchy 面板右键,然后 Create Empty,或者通过菜单栏 GameObject/Create Empty都可以,这样就会在Hierarchy 面板上看到我们新建的物体,然后对这个物体重命名为 Clock,并且把它的位置置为 (0,0,0)。看下面的图

p002005_Unity-001-5

p002006_Unity-001-6

1.2 创建时钟的表盘

创建表盘,我们使用 Unity 默认的物体 Cylinder,然后改变它的大小,使其成为我们的表盘。首先,通过右键 Hierarchy 空白处,或者通过菜单栏 GameObject 中的 3D Object/Cylinder 选项,来创建一个 Cylinder,就是一个圆柱体。

p002007_Unity-001-7

Cylinder 默认已经有了很多组件,Mesh Filter、Capsule Collider、MeshRenderer。默认我们不需要物理模拟方面的东西,所以我们先把 Capsule Collider 这个碰撞器给删掉,通过右键这个组件,Remove Component 即可。

然后我们改变园柱体的大小,因为表盘是一个圆盘形状的东西,所以我们把圆柱体压平,也就是改变y轴的大小始可。把圆柱体 Scale 设置为 (10, 0.1, 10),如下图。

p002008_Unity-001-8

接下来要做的,就是把 Cylinder 重命名为 Face,然后把这个物体拖到我们一开始建立的 Clock 物体下面,作为它的子物体,并且把坐标归为 (0, 0, 0),如下图。

p002009_Unity-001-9

1.3 创建时钟刻度

表盘是 360 度,有 12 个小时,所以每个小时间隔的角度是 356 / 12 = 30 度。也就是说,我们需要每隔 30 度创建一个小时刻度。最终效果如下

p002010_Unity-001-10

接下来我们一步一步来创建刻度。

首先创建一个 Cube,将它的 Scale 设置为 (0.5, 0.2, 1),然后设置它的位置为 (0, 0.2, 4)。如果没错的话,它现在应该处于 12 点位置。

但是有一个问题,因为它默认是白色的,看不清,所以我们创建一个材质,命名为 Clock Dark,然后设置 Albedo 颜色值为 (73 73 73 255),然后把这个材质拖到Cube上,现在应该是下图中的样子。

p002011_Unity-001-11

接下来我们继续创建其他刻度,但是有一个问题,我们怎样才能精确地设置每一个刻度的位置呢?其实很简单,只需要旋转30度即可,但是,不是旋转刻度本身,而是要建立一个新的 GameObject。

新建一个新的空 GameObject,坐标置为 (0, 0, 0),然后将刚才创建的 Cube 拖动到新建立的 GameObject 下面,作为子物体,将 Cube 重命名为 Hour Indicator。如下图这样

p002012_Unity-001-12

下面我们创建 1 点时的刻度,只需要复制上面的 “GameObject”,注意,不是复制 Hour Indicator,而是复制它的父物体,然后将复制后的物体 y 轴旋转 30 度即可。那 2 点的位置,就是再复制一个 GameObject,这只旋转为 60 度即可。其他的时间刻度也同样,只需要依次增加旋转角度。

当所有刻度创建完毕后,我们将所有的 Hour Indicator 拖动到之前创建的 Clock 下面,然后删除掉为了旋转而临时创建的 “GameObject”,到此,刻度创建完毕。如下图

p002013_Unity-001-13

1.4 创建时钟指针

创建指针,与上面创建刻度类似。首先新建一个 Cube,命名为 Arm,设置 Scale 为 (0.3, 0.2, 2.5),设置坐标 (0, 0.2, 0.75)。然后将上面创建的材质 Clock Drak 也赋予我们刚建立的 Arm。现在状态如下

p002014_Unity-001-14

为了后面旋转,我们还要创建一个空的GameObject,命名为 Hours Arm,然后将 Hours Arm 坐标设置为 (0, 0, 0)。然后将之前创建的 Arm 拖动到 Hours Arm 下面,作为其子物体。然后再将 Hours Arm 拖动到 Clock 下面。现在的层级如下

p002015_Unity-001-15

接下来我们再创建分针和秒针,和上面创建时针基本类似。选中之前创建的 Hours Arm,然后按 Ctrl+D (如果是Mac,则是Command + D) 两次,复制两份 Hours Arm,重命名为 Minutes Arm 和 Seconds Arm,作为分针和秒针。

设置 Minutes Arm 下面的 Arm 缩放和坐标,Scale 为 (0.2, 0.15, 4),Position 为 (0, 0.375, 1)

设置 Seconds Arm 下面的 Arm 绽放和坐标,Scale 为 (0.1, 0.1, 5),Position 为 (0, 0.5, 1.25)

为了使秒针更明显,我们创建一个新的材质,命名为 Clock Red,然后设置颜色值为 (197, 0, 0, 255),然后将材质拖到 Seconds Arm 下面的 Arm 物体上。目前应该是下面的样子

p002016_Unity-001-16

2 实时显示当前时间

接下来就是写代码的时间,我们先看代码,然后对代码作解释。代码中我们实现了两种指针行走的方式,一种是逐步方式,一步是持续方式。注意看代码中的注释

using UnityEngine;
using System;

public class Clock : MonoBehaviour
{
    // 定义时针、分针、秒针步伐角度
    const float degreesPerHour = 30f;
    const float degreesPerMinute = 6f;
    const float degreesPerSecond = 6f;

    // 时针、分针、秒针的旋转体 Transform
    public Transform hoursTransform;
    public Transform minutesTransform;
    public Transform secondsTransform;

    // 指针行走模式
    public bool continuous = false;

    private void Awake()
    {
        UpdateDiscrete();
    }

    private void Update()
    {
        if (continuous)
        {
            UpdateContinuous();
        }
        else
        {
            UpdateDiscrete();
        }
    }

    // 逐步方式更新当前时间
    private void UpdateDiscrete()
    {
        DateTime time = DateTime.Now;
        hoursTransform.localRotation = 
            Quaternion.Euler(0f, time.Hour * degreesPerHour, 0f);

        minutesTransform.localRotation = 
            Quaternion.Euler(0f, time.Minute * degreesPerMinute, 0f);

        secondsTransform.localRotation =
            Quaternion.Euler(0f, time.Second * degreesPerSecond, 0f);
    }

    // 持续方式更新当前时间
    private void UpdateContinuous()
    {
        TimeSpan time = DateTime.Now.TimeOfDay;
        hoursTransform.localRotation =
            Quaternion.Euler(0f, (float)time.TotalHours * degreesPerHour, 0f);

        minutesTransform.localRotation =
            Quaternion.Euler(0f, (float)time.TotalMinutes * degreesPerMinute, 0f);

        secondsTransform.localRotation =
            Quaternion.Euler(0f, (float)time.TotalSeconds * degreesPerSecond, 0f);
    }
}

上面代码中,首先我们定义了各指针每一步行走的角度,然后定义了三个变量,用于引用三个指针旋转体的Transform,最后写了两种方式的更新指针位置,通过 continuous 变量控制使用哪种方式更新指针。

将脚本拖动到我们之前建立的 Clock 物体上面,然后将三个指针的旋转体 Transform 拖到脚本对应的变量区域,如下图所示

p002017_Unity-001-17

接下来,运行即可看到效果

下面是未勾选 continuous 的运行效果

下面是勾选了 continuous 的运行效果

好了,这次的教程到这里就结束了,如果有什么问题,欢迎在下面留言~

原文翻译自 Game Objects and Scripts Creating a Clock Github 代码下载: animating-the-clock.unitypackage