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开发的软件:
原神
王者荣耀
明日方舟
使命召唤手游
炉石传说 - 百度百科
- 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 读取和处理输入
- Unity 支持的输入设备
如:键盘⌨、鼠标🖱、手柄🎮等。
Unity 支持的多种输入设备 - Input.GetAxis函数
示例代码如下
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脚本编程与游戏开发》马瑶-沈琰