Unity学习第一日

  • 前言
  • Unity介绍
  • 游戏开发技术
  • 技术实现与游戏设计
  • 第一章 Unity脚本概览
  • 1.1 控制物体的移动
  • 1.1.1 新建脚本并挂载
  • 1.1.2 Start 和 Updata 事件
  • 1.1.3 修改物体位置
  • 1.1.4 读取和处理输入
  • 1.1.5 实例:实现一个移动的小球
  • 1.2 触发器事件
  • 1.2.1 创建触发器
  • 1.2.2 触发器事件函数
  • 1.2.2 实例:吃金币


前言

 Unity 是实时3D互动内容创作和运营平台。
 使用Unity前我们需要先了解这个游戏引擎。
Unity官网

Unity介绍

游戏开发技术

  • 游戏设计 (游戏的灵魂)
  • 美术制作 (游戏的外表)
  • 技术实现 (游戏的骨骼和血肉)

技术实现与游戏设计

  游戏技术与游戏设计互相促进:技术为设计带来可能性的空间,设计指导者技术的发展方向。

第一章 Unity脚本概览

 本章主在让读者体会脚本编程的思路和整体方法。

1.1 控制物体的移动

 本节将详细讲解创建脚本、改变物体位置、处理用户输入等基本操作。

1.1.1 新建脚本并挂载

  • 脚本的创建
  • 方法一:
    在Project(工程)窗口某个文件夹中,单机鼠标右键选择:Create->C# Script选项。
  • 方法二:
    先新建一个球体,即在Hierarchy窗口,单机鼠标右键选择:3D object->Sphere选项。
    然后选中球体,在Insperctor(检视)窗口单击:Add Component(添加组件)按钮,在菜单中选择:New script (新建脚本)选项,输入脚本文件名单击:Create and Add(创建并添加)。
  • 脚本的挂载
  • 方法一:
    拖拽脚本到场景中的球体上。
  • 方法二:
    拖拽脚本到Inspector窗口中项目的最后面。(推荐使用)
  • 脚本组件的删除
     在组件名称上单击鼠标右键,选择:Remove Component(删除组件)。
  • 注意事项
     Unity 规定:能够挂载到物体上的脚本文件必须是“脚本组件”,脚本组件要继承自MonoBehaviour,且脚本代码中的class名称必须与文件名一致。(因此在修改脚本文件名时,必须同时修改class名称)。
     Unity 支持一个物体挂载多个同样的脚本组件。

1.1.2 Start 和 Updata 事件

  • 双击脚本文件打开脚本,目前脚本中的内容是自动生成的,包括:
    using UnityEngine(使用UnityEngine这个命名空间)
    Start(函数)
    Update(函数)
  • Start和Update函数
    Start函数在游戏开始运行依次,适合进行组件初始化。
    Update函数每帧都会执行,根据系统资源情况,帧率可能实时变化,因此Update的执行频率(每秒执行次数)是变化的。
    Start和Update又被称为“事件”,因为它们分别是在“组件开始运行”和“更新该组件”这两个事件发生时被调用的。
  • Debug.Log函数
    作用:向Console(控制台)窗口输出一串信息。
    用处:写代码、调试代码,是最简单、最可靠的一种调试手段。
  • Time类
    Time.time:显示游戏运行时间。
    Time.deltaTime:表示从上一帧到当前帧时间,时间增量。
    Time.timeScale函数(时间缩放:默认值为1,游戏的暂停为0,游戏的快进可为2)。
    Time类详解

1.1.3 修改物体位置

  • 在Unity 中,修改物体位置实际上就是修改Transform(变换)组件的数据。
  • Inspector窗口展示了组件的位置(Position)、旋转(Rotation)、缩放(Scale)参数。
  • 在界面上可以修改的内容一定可以在脚本中修改,但在脚本中修改的内容不一定能在节目中修改,因为脚本的功能比界面展示的功能要多得多。
  • 修改Transform组件中的Position的两种常用方法:
  • 使用Translate()函数。
    即:tansform.Translate(x,y,z)。其中x、y、z为float类型量,若为常量要加上后缀f表示float类型,否则C# 认为其为double类型。如 3.12为double类型,3.12f为float类型。 (代码写于脚本函数中)
  • 直接指定新的位置
    即:tansform.position = new Vector3(x,y,z)。
  • 上述两种方法的区别:Translate函数默认为局部坐标系,而修改position的方法是世界坐标系。
  • 类型转换
    int可以隐式转换为float,所以x、y、z如果没有小数位可以不加f后缀,但int转float精度会降低(题外话)。
    类型转换
  • 位置移动代码
void Update(){
	tansform.Translate(0,0,0.1f);
	tansform.position += new Vector3(0,0,0.1f);
}
  • 游戏设计注意事项
     由于系统繁忙时无法保证稳定的帧率,因此对于上述代码,会导致小球的移动速度和帧率成正比。
    是“每帧移动距离相同”还是“每秒移动距离相同”呢?这需要根据游戏设计来确定,大多情况下是”每秒移动距离相同“,因此移动的距离应该针对帧率去确定,”每秒移动距离相同“的代码如下。
void Update(){
	tansform.Translate(0,0,5*Time.deltaTime);
	tansform.position += new Vector3(0,0,5*Time.deltaTime);
}
  •  代码中5表示速度,上述代码的改进原理基于:距离 = 速度 ✖ 时间 。两帧画面之间的变化基于两帧之间间隔的时间Time.deltaTime。要记住Updata函数是每帧执行。

1.1.4 读取和处理输入

void Update()
    {
        float v = Input.GetAxis("Vertical");
        float h = Input.GetAxis("Horizontal");
        Debug.Log("当前输入 纵向:" + v + "横向:" + h);
        transform.position += new Vector3( h*speed, v * speed, 0);
    }
  • Input.GetAxis返回取值范围为[-1,1]的float类型值。若传入参数"Vertical"表示返回沿纵轴的输入,传入参数"Horizontal"表示返回沿纵轴的输入。上述代码可能存在问题,那就是针对帧率不同按键后小球速度不一致,所以应再乘以Time.deltaTime。
  • 字符串拼接

1.1.5 实例:实现一个移动的小球

  • 代码如下:
using UnityEngine;
	
	public class SphereScript : MonoBehaviour
	{
	    public float speed = 10;
	    // Start is called before the first frame update
	    void Start()
	    {
	        Debug.Log("组件执行开始函数!");
	        gameObject.GetComponent<Renderer>().material.color = Color.red;
	        transform.position = new Vector3(0, 0, 5f);
	    }
	
	    // Update is called once per frame
	    void Update()
	    {
	        float v = Input.GetAxis("Vertical");
	        float h = Input.GetAxis("Horizontal");
	        Debug.Log("当前输入 纵向:" + v + "横向:" + h);
	        transform.position += new Vector3( h * speed * Time.deltaTime, v * speed * Time.deltaTime,0);
	    }
	}
  • 使用上述代码拖动到小球上,调整摄像机的Rotation朝向为(0,0,0),运行即可移动小球。
  • 代码解读
    public float speed = 10;(设置速度)
    gameObject.GetComponent().material.color = Color.red;(设置小球颜色)
  • 注意事项
  • 脚本中的public类型变量可以在Inspector窗口看到和修改。若将public改为private,则变量在窗口中不可见、不可改。
  • 在不同条件下修改脚本中的变量值有不同的作用时间(如下表所示)

值类型

脚本中

未运行时Inspector窗口中

运行时Inspector窗口中

作用时间

脚本创建后

永久

运行中

 创建脚本时设置了公开(public)变量,则其代码中的初始值会生效。
 当运行时,在Inspector窗口对脚本中的public变量进行修改,会在当次运行的以后时间里生效。
 当未运行时,在Inspector窗口对脚本中的public变量进行修改,会在当前Unity 项目窗口中生效。退出项目窗口时若选择Save保存,则其值会在项目中生效。
 以上内容意味着:
  当创建完脚本后,每一次修改脚本中的值,但在Unity 项目中不会生效。
  当游戏运行中,修改变量,游戏结束后修改的值不会保存。(若在游戏中时事调整参数,对需要保存的数据应以记录)
  当游戏未运行时,修改变量,以后每一次运行值都会生效。如果退出项目窗口时保存,则下一次打开项目窗口也会生效。

1.2 触发器事件

 触发器是一个组件,它定义了一个范围。当其他带有碰撞体组件的物体进入了这个范围时,就会产生一个触发事件。脚本捕捉到这个事件的时候,就可以做出相应的处理。

1.2.1 创建触发器

 Unity 中,触发器和碰撞体共用了同一组件:Collider,实际上两者是不同的概念。创建一个Cube,它自带一个碰撞器,在Inspector窗口勾选Box Collider面板中的 Is Trigger 选项,碰撞体就变成了同样外形的触发器。对小球和Cube都添加一个Rigibody(刚体)组件,勾选组件中的 Is Kinematic(动力学)选项,若不勾选物体会一直下落。

1.2.2 触发器事件函数

 碰撞和触发总是发射在两个物体之间,所以根据不同情况,可以选择其中一个物体进行碰撞或者触发的处理。给Cube添加一个脚本,并且脚本内容如下。

using System.Collections;
	using System.Collections.Generic;
	using UnityEngine;
	
	public class Coin : MonoBehaviour
	{
	    // Start is called before the first frame update
	    void Start()
	    {
	        
	    }
	
	    // Update is called once per frame
	    void Update()
	    {
	        
	    }
	    private void OnTriggerEnter(Collider other)
	    {
	        Debug.Log(other.name + "碰到了我");
	    }
	}

 运行游戏,在场景中拖拽球体,让它和立方体接触,就可以看到碰撞出发信息了。

  • 注意事项
    在游戏中进行的修改游戏结束后会还原,即使是在游戏中对物体添加了组件,游戏结束后也会还原运行前状态。
    如若球体没有Rigidbody组件,则不会出发碰撞消息。

1.2.2 实例:吃金币

文中内容引用或参考《Unity3D脚本编程与游戏开发》马瑶-沈琰