认识Unity-1

从GameObjects与Scripts开始创建一个时钟

本文所用的Unity版本为2019.1.10,VS版本为2020

这篇文章是catlike系列的学习笔记,中文版教程可关注知乎“放牛的星星”,他的微信公众号为“壹种念头”

游戏引擎作为一种工具,最本质的用途就是制作出我们所想的游戏。本着“实践出真知”的态度,今天开始从零学习Unity,从做贴紧项目的角度了解这个新时代游戏引擎的方方面面。

首先我们创建一个新的项目

初始界面

默认创建出的场景会包含两个Game Object。其中,Main Camera会渲染出我们所看到的游戏场景,Directional Light则用来给场景展示阴影。
Hierarchy

鉴于一切行动都从Game Object开始,为了创建属于我们自己的东西,我们也要创建自己的Game Object:先创建一个名为Clock的Game Object
Inspector窗口会为我们展示Game Object的详细信息
Inspector

通常情况下,我们要注意自己所创建对象的坐标、旋转和缩放信息。就像在大多数三维建模软件里一样,如果最初的坐标没有保持“0,0,0”,后期会出现许多意想不到的麻烦。

既然想做一个时钟,就要先做出时钟的样子。
首先创建一个圆柱体Cylinder
圆柱体比刚刚的空对象多出了三个组件:

  • Mesh Filter:引用Unity内置的圆柱体网格
  • Capsule Collider:胶囊型的碰撞体,用来做3D物理相关
  • Mesh Renderer:这个组件告知了Unity如何画出Mesh Filter,它包含一个内置的Material材质球
    所有的组件都可以被移除,如果这个时钟仅仅是做出走动的动画,我们实际上不需要Collider

通过修改圆柱体XYZ轴的缩放,我们可以得到一个这样的圆盘


表盘

表盘作为Clock的一部分,后续操作都会和Clock的其他部分同步,所以我们将其重命名后放入刚刚创建的Clock空对象内:


Clock中包含Face

子物体的Transformation(变换)会受父对象影响

大多数情况下,重命名每一个自己创建的对象是非常必要且有意义的。无论你操作的是Unity之类的游戏引擎还是3DMax之类的三维建模软件,一个好的命名系统就如同代码的注释一样必要。

创建时钟的其他部分
创建一个Cube对象,将位置和缩放调整后作为指示小时的凸起部分。如果所有的对象都是白色的话,我们会很快分不清到底各部分是什么样的。所以我们需要一个新的材质球来为这个小时指示器换上新的颜色:在Assets → Create → Material中创建一个新的材质球,将它的Albedo换成一个新的颜色吧。

  • 什么是Albedo?Albedo是反照率。什么是反照率?这个要涉及图形学的知识,现在只要知道Albedo主要体现模型的纹理和颜色就好。

上面说在Mesh Renderer里有一个默认的材质球位置,我们把创建好的材质球拖过去就可以了。


新的表盘

为了做出一个正常表盘的效果,我们需要让这个小时指示器沿表盘的中心旋转12次,但是物体都是基于自身的中心进行旋转的。我们可以创建一个新的空对象,把小时指示器放进空对象中,再旋转空对象。


放入空对象

Ctrl+D复制12个空对象,创建出所有的小时指示器,然后选中所有的指示器,拖入Clock中。此时Unity会自动切换父子对象的关系。最后再删除没有用的空对象即可。
新的表盘

创建指针
创建指针的方式和上面差不多,但是指针是要旋转的,所以我们不再删除那个用来辅助的空对象

父子关系

创建好相关的指针后我们就可以开始真正的学习了
表盘

  • 记得在适当的时候保存会省去很多不必要的苦恼。比如突如其来的停电或Unity闹了小脾气

让时针动起来
Unity中所有对象的行动都基于Script(脚本),它指示着对象该以什么样的状态行动或工作。
首先通过Assets → Create → C# Script创建一个脚本。

下面的内容需要有一定的面向对象语言基础

首先删掉脚本中自带的内容(除了using部分),从零开始创建我们自己的脚本:
首先我们希望这个脚本操作我们想要操作的对象。那么我们创建的类就要继承于MonoBehaviour

  • MonoBehaviour代表我们自定的这个脚本是否能够像其他组件一样绑定到游戏对象上。如果像让自己写的代码能够绑定到游戏对象,那么就必须从这个类继承。(这个类在UnityEngine命名空间内)

将script拖到Clock对象里


脚本可以绑定对象了

要想移动指针,逻辑应该是修改Transform组件的rotation。为了让脚本知道我们要修改的是什么对象

public class Clock : MonoBehaviour
{
    public Transform HoursTransform;
}

public属性可以让数据或属性在类的外部可用。当我们写完上面的代码后,已经可以看到脚本中多出了一个可以绑定的操作对象


拖入Hours指针

像这样写出三个可操作的对象,分别绑定我们的Game Object


新的Script

接下来,我们创建一个Awake函数

private void Awake()
    {
        Debug.Log(DateTime.Now);
    }
  • Awake是Unity脚本所支持的类,只要物体被加到场景就会执行一次。
  • Debug是UnityEngine命名空间下的一个类,用来做调试用的,这个类有一个方法就是Log,可以在Unity的控制台打印日志。
  • DateTime是C#的类型,在System命名空间下,也是.NET framework的一部分,它会显示现在真正的时间。
const float degreePerHour = 30;
const float degreePerMinute = 6;
private void Awake()
{
    Debug.Log(DateTime.Now);
    HoursTransform.localRotation = Quaternion.Euler(0f, DateTime.Now.Hour * degreePerHour, 0f);
    MinutesTransform.localRotation = Quaternion.Euler(0f, DateTime.Now.Minute * degreePerMinute, 0f);
    SecondsTransform.localRotation = Quaternion.Euler(0f, DateTime.Now.Second * degreePerMinute, 0f);
}

这段代码可以让指针们初始化到现在的时间。其中Quaternion是四元数,我们后面会继续认识它。为了让指针转正确的角度,每个指针的旋转值为现在时间乘相应常量。

但是我们的指针还没有转起来,此时我们只要把Awake改为Update即可。

  • Awake整个生命周期只执行一次,但是Update是每一帧都会执行一次

此时我们的时钟已经像老式挂钟一样转了起来,并且展示了正确的时间。但它还不够丝滑,不能像现代化钟表一样让秒针丝滑地移动以至于不会发出任何噪音。

让时钟更丝滑
首先写一个public的bool类型来判断是否开启这个功能。
然后写两个不同的函数代表两种不同的状态。
下面是脚本中全部的代码:

public class Clock : MonoBehaviour
{
    public Transform HoursTransform;
    public Transform MinutesTransform;
    public Transform SecondsTransform;
    public bool Continuous;

    const float degreePerHour = 30;
    const float degreePerMinute = 6;

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

    private void UpdateDiscrete()
    {
        DateTime time = DateTime.Now;
        HoursTransform.localRotation = Quaternion.Euler(0f, time.Hour * degreePerHour, 0f);
        MinutesTransform.localRotation = Quaternion.Euler(0f, time.Minute * degreePerMinute, 0f);
        SecondsTransform.localRotation = Quaternion.Euler(0f, time.Second * degreePerMinute, 0f);
    }

    private void UpdateContinuous()
    {
        TimeSpan time = DateTime.Now.TimeOfDay;
        HoursTransform.localRotation = Quaternion.Euler(0f, (float)time.TotalHours * degreePerHour, 0f);
        MinutesTransform.localRotation = Quaternion.Euler(0f, (float)time.TotalMinutes * degreePerMinute, 0f);
        SecondsTransform.localRotation = Quaternion.Euler(0f, (float)time.TotalSeconds * degreePerMinute, 0f);
    }
}

关于TimeSpan的详细信息可以了解深入了解C#
到这里我们就成功做出了一个可以活动的时钟,了解了Game Object和Script的基础用法。下面一步我们会让程序中很重要的东西“数学”可视化。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。