虚拟现实100天的第2天:通过统一空间射击教程一


嘿!欢迎回到2我100天虚拟现实中的“一天”!

我们最后一次停止学习团结滚球教程。我已经学习了很多关于如何在Unity中编码,以及如何使用他们现有的一些应用编程接口。更重要的是,我学会了如何导航和使用统一编辑器!

与通过代码创建一切的网络或移动开发相比,编辑器绝对是不同的,但是编辑器确实让事情变得更容易!

今天是第二天,我开始看2团结课Unity Space Shooter。我从之前的教程中学到了很多关于Unity的知识,甚至可能足以让我开始开发自己的简单游戏(在StackOverflow的大量帮助下),但相反,我决定通过再学习1-2个教程来巩固我的基础。

由于工作的原因,我没有在第一天走得那么远,但是我完成了第一部分:

游戏设置、玩家和相机

设置项目

与之前的教程不同,我们只是使用简单的材料和形状,这次我不得不使用实际的资产。

我要做的第一件事是下载教程中提供的资源。

当您在Unity中创建新项目时,我看到了这一点。如果你点击那个标签,你可以看到这个项目,你可以在那里下载它(或者从Unity asset store)。

然后,当您创建新项目时,只需确保将资产包添加到资源中:

在设置了统一教程之后,我发现你可以调整你的游戏的屏幕分辨率,方法是点击游戏选项卡,选择下面的分辨率选项来设置和创建你的游戏的分辨率。

到目前为止还不错,没有什么太复杂的!

玩家游戏对象

现在我已经建立了这个项目,我已经开始创建玩家游戏对象。

这与我在之前的教程中学到的没有太大的不同,除了这次,我不是创建一个3D球体,而是拖动一个提供给我的现有模型资产。

酷船!

在这段视频中需要注意的一些有趣的事情:

网格碰撞器、网格过滤器和网格渲染器

看看船上的组件,我们看到有一个网格过滤器和一个网格渲染器。

从一个简单的谷歌搜索:网格过滤器组件接受一个网格,这是一个由三角形创建的3D对象(三角形,因为它是图形用户界面编程中处理的最有效的形状)。网格过滤器将根据你提供的网格创建你的游戏对象的形状。然后,如果你想看到你的模型,你需要一个网格渲染器,它会将你的网格渲染并在上面应用一个材质——这个材质就是你上面看到的船的外壳。

最后,我们添加了网格碰撞器组件,它包含一个网格。这使我们能够创造出一个与我们的飞船形状完全匹配的对撞机。

考虑我们必须做出的游戏性和性能的权衡是很重要的。更多的细粒度碰撞器= >统一做更多的工作= >较慢的性能。然而,另一方面,我们可能不想在我们的飞船上创建一个立方体对撞机。

如果我们这样做,我们可能会与船前面没有网格的东西相撞。

在一个更精细的控制游戏中,比如这个太空射手,那就不好了。

改变你的游戏转换值的简单方法

另外,在另一个不相关的注释中,我为编辑发现了一个巧妙的技巧。如果您想尝试使用值,而不是手动输入值,您实际上可以左键单击此图片中的属性

从那里,上下拖动鼠标来更改值。这比手工输入值要容易得多!

照相机和照明

在下一个视频中,我们用相机和灯光玩了一会儿。

照相机

在相机组件中,您可以设置背景。在我们的例子中,我们只是设置了一个黑色背景,使得游戏标签中的所有东西都是黑色的,除了我们的飞船。

照明设备

在后期的统一版本中,这个项目已经有了一个方向灯,但是这些光源,正如你所期望的,照亮了你的游戏!

定向光就是从某个方向向下发光的光。

你可以调整光线的颜色、光线的强度、光线的方向以及其他许多东西。然而,在这种情况下,我们只是玩了一会儿移动它和光的强度,让我们的船看起来像我们想要的那样。

添加背景

创建背景的方式与向现有形状对象添加材质非常相似。在这个项目中,我们创建了一个四边形,你可以把它想象成一个平面,你根本不能改变Y比例。

我们有一个现有的. tif文件,提供给我们用来创建一个对象,但我们的四元对象只需要材料。我们如何让它工作?

事实证明如果你把。tif文件,它会自动为你创建你可以使用的材料。

着色器

另一个简短讨论的主题是着色器。据我所知,着色器用于渲染材质效果。它让我们能够在现有图像上应用亮度、颜色和其他特殊效果。

幸运的是,我们还不需要学习如何做到这些,我们可以使用Unity提供给我们的现有工具。框架真棒!

在视频中,我们应用了一个不亮纹理着色器效果,使我们的背景图像看起来更亮。

移动飞船

最后,既然我们已经设置好了环境,我们终于开始做一些编码了。

using UnityEngine;
using System.Collections;

[System.Serializable]
public class Boundary
{
    public float xMin, xMax, zMin, zMax;
}

public class PlayerController : MonoBehaviour
{
    public float speed;
    public float tilt;
    public Boundary boundary;

    void FixedUpdate ()
    {
        float moveHorizontal = Input.GetAxis ("Horizontal");
        float moveVertical = Input.GetAxis ("Vertical");

        Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
        rigidbody.velocity = movement * speed;

        rigidbody.position = new Vector3 
        (
            Mathf.Clamp (rigidbody.position.x, boundary.xMin, boundary.xMax), 
            0.0f, 
            Mathf.Clamp (rigidbody.position.z, boundary.zMin, boundary.zMax)
        );

        rigidbody.rotation = Quaternion.Euler (0.0f, 0.0f, rigidbody.velocity.x * -tilt);
    }
}

让我们把这段代码分解一下。

刚体

现在最重要的是在Unity 5中。x,这段代码其实不会运行。这是因为我们将不再像现在这样获得刚体组件。

我们必须做一些类似于滚球教程的事情,并在Start()函数中保存刚体的一个实例,如下所示:

using UnityEngine;
using System.Collections;

[System.Serializable]
public class Boundary
{
    public float xMin, xMax, zMin, zMax;
}

public class PlayerController : MonoBehaviour
{
    public float speed;
    public float tilt;
    public Boundary boundary;
    public RigidBody rigidbody;

    void Start()
    {
        Rigidbody = GetComponent<RigidBody>();
    }

    void FixedUpdate ()
    {
        float moveHorizontal = Input.GetAxis ("Horizontal");
        float moveVertical = Input.GetAxis ("Vertical");

        Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
        rigidbody.velocity = movement * speed;

        rigidbody.position = new Vector3 
        (
            Mathf.Clamp (rigidbody.position.x, boundary.xMin, boundary.xMax), 
            0.0f, 
            Mathf.Clamp (rigidbody.position.z, boundary.zMin, boundary.zMax)
        );

        rigidbody.rotation = Quaternion.Euler (0.0f, 0.0f, rigidbody.velocity.x * -tilt);
    }
}

我们现在必须使用GetComponent <刚体>来访问我们游戏对象的组件。

分界线

你可能注意到的第一件事是还有另一个类:边界。它有[系统。可序列化]在它上面。

[System.Serializable]
public class Boundary {
 public float xMin, xMax, zMin, zMax;
}

可序列化的意思是,你告诉Unity如果你把这个类变成一个公共变量,它会把这个类中的变量公开给你在检查器中使用。

我们将使用这个边界来设定我们的船在游戏中能走多远。特别是,防止我们的飞船偏离屏幕。

活动

为了移动飞船,我们应用了一些与第一天的球教程非常相似的东西。

我们看到我们仍然使用相同的FixedUpdate()函数,并且我们以相同的方式抓取玩家的移动输入。

新的有趣部分是更多地使用统一的库。

Unity有自己的数学库Mathf。图书馆为我们提供了漂亮的游戏计算。

rigidbody.position = new Vector3 
(
  Mathf.Clamp (rigidbody.position.x, boundary.xMin, boundary.xMax), 
  0.0f, 
  Mathf.Clamp (rigidbody.position.z, boundary.zMin, boundary.zMax)
);

在这种情况下,我们使用Mathf。夹钳有助于设置位置边界,因此如果我们的位置超过最小值,它将保持在最小值,如果超过最大值,它将保持在最大值。

创建镜头

所以现在我们有了一艘船和一些运动,我们开始了全新的拍摄!

  • 我们创造子弹就像我们创造背景一样。
  • 我们制作一个四边形对象,然后使用. tif文件创建一个材质(或者只使用现有的一个)并附加该材质。
  • 我们在上面应用了一些着色器。我们可以通过使用移动着色器而不是普通着色器来优化我们的性能。移动着色器提供的控件较少,但结果是,它们的计算强度较低。

最后,我们有了向前推进的代码:

using UnityEngine;
using System.Collections;

public class Mover : MonoBehaviour
{
    public float speed;

    void Start ()
    {
        rigidbody.velocity = transform.forward * speed;
    }
}

代码本身非常简单;我们只需将刚体的速度设置为某个值,它就会一直朝这个方向运动。

射击

既然我们已经在前一课中创建了子弹的预制体,我们就可以开始拍摄了。在视频中,我们展示的是我们创建了一个新的“主人”游戏对象。一个玩家基本上只是一个空的游戏对象,我们用它的位置来创建新的项目符号。

这里最重要的是让主人成为玩家游戏对象的孩子,这样它相对于我们的飞船来说总是保持一致的。在我们的脚本中,我们为项目符号预置和种子点位置添加了一个公共变量。

using UnityEngine;
using System.Collections;

[System.Serializable]
public class Boundary
{
    public float xMin, xMax, zMin, zMax;
}

public class PlayerController : MonoBehaviour
{
    public float speed;
    public float tilt;
    public Boundary boundary;

    public GameObject shot;
    public Transform shotSpawn;
    public float fireRate;

    private float nextFire;

    void Update ()
    {
        if (Input.GetButton("Fire1") &amp;amp;&amp;amp; Time.time &amp;gt; nextFire)
        {
            nextFire = Time.time + fireRate;
            Instantiate(shot, shotSpawn.position, shotSpawn.rotation);
        }
    }

    void FixedUpdate ()
    {
        float moveHorizontal = Input.GetAxis ("Horizontal");
        float moveVertical = Input.GetAxis ("Vertical");

        Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
        rigidbody.velocity = movement * speed;

        rigidbody.position = new Vector3 
        (
            Mathf.Clamp (rigidbody.position.x, boundary.xMin, boundary.xMax), 
            0.0f, 
            Mathf.Clamp (rigidbody.position.z, boundary.zMin, boundary.zMax)
        );

        rigidbody.rotation = Quaternion.Euler (0.0f, 0.0f, rigidbody.velocity.x * -tilt);
    }
}

我们真正感兴趣的代码部分是我们新的Update()函数:

    void Update ()
    {
        if (Input.GetButton("Fire1") && Time.time > nextFire)
        {
            nextFire = Time.time + fireRate;
            Instantiate(shot, shotSpawn.position, shotSpawn.rotation);
        }
    }

在代码中,我们使用输入类来检测用户何时点击开火按钮(左键)并检查射击延迟。

有趣的是我们如何创造子弹。这是通过实例化函数在Unity中完成的。我们只需要传入我们想要创建的游戏对象,它的起始位置和旋转。

就这样!

结论

第二天,我完成了太空射手教程的第一部分。同样,许多学习实际上是在代码之外通过编辑器完成的。

好消息是,我开始看到使用游戏对象、材料和预置来举一些例子的类似的事情。

就代码而言,一切似乎都很简单。现在我可能会有偏见,因为我已经知道如何编码了,但是我有一种很好的感觉,我们将再次看到许多这样的应用编程接口。

这是我的希望,我会看到模式,我用它来制作我自己的游戏。

我的目标是充分了解Unity中的可用功能,这样我就可以扩展并开始编写自己的代码了。

附言:哇,这些文章真长!我真的想知道什么需要更长的时间,浏览视频,学习和理解正在发生的事情,或者写下这些解释!

Day 1|100 Days of VR|Day 3