Unity3D功能开发入门系列(二)
一、资源
(一)资源文件
1. Assets 目录下的文件,称为资源
常见类型:
- 模型文件 Model(*.fbx)
- 图片文件 Texture(*.jpg / png / psd / tif)
- 音频文件 AudioClip(*.mp3 / wav / aiff)
- 脚本文件 Script(*.cs)
- 材质文件 * .mat ,场景文件 *.unity ……
2. 目录式的资源管理,和 Windows 类似
几个操作:
-
在文件夹窗口查看,Show In Explorer
-
添加、删除目录
-
添加资源文件(直接拖拽到项目中),文件会被拷贝到项目中
-
复制资源:选中资源,Ctrl + D
-
缩略图比例调节、列表模式
3. Meta,描述文件
每一个资源文件 / 文件夹,都对一个 *.meta 描述文件
(二)场景文件
1. 场景文件 *.unity,记录了场景中的节点数据
包含:
- 场景全局设置
- 节点
- 节点下的组件
- 每个组件的参数值
2. 一个场景代表一个关卡,可以创建多个场景
几个操作:
-
添加场景
-
打开场景:双击
-
编辑场景,保存 Ctrl+S
(三)资源包
1. 资源包 Unity Package,即对 Assets 下的资源打包
演示:
- 选择一个资源文件,或者一个目录
- 右键,Export Package
- 生成 *.unitypackage 资源包
2. 导入资源包
直接把 *.unitypackage 拖到 Project 窗口,拖到其他窗口没反应
(四)Unity 资源商店
资源商店 Asset Store,https://assetstore.unity.com/
也可以在 Unity 打开,Windows | Asset Store
有一些免费或收费的资源,包含模型、材质纹理等
(五)项目资源的导入
- 导入资源: *.unitypackage
- 查看资源:模型 / 材质 / 脚本
- 查看示例场景:
有的资源包下有示例场景,一般叫 AF demo scene
二、父子关系
(一)轴心
1. 轴心 Pivot,指一个物体的操作基准点
演示:
- 移动一个物体
- 旋转一个物体
对于基本体来说,轴心点默认位于几何中心
2. 轴心 Pivot 可以在任意位置,不一定是在几何中心(Center)
注意,轴心的位置是在建模软件中指定的
(二)父子关系
1. 父子级,指两个物体之间的关系
在 Hierarchy 窗口中,拖动物体 B 到物体 A 下,子物体会随着父物体一并移动,删除父物体时,子物体一并删除
2. 相对坐标:子物体的坐标,是相对于父物体的
移动父物体时,观察子物体的坐标,可以发现,不管这么移动、旋转父物体,子物体的坐标都不会有任何变化
(三)空物体
1. 空物体 EmptyObject,即空对象、空节点
演示:
-
添加一个空物体
-
空物体不可见(没有网格)
-
空物体没有坐标,可以移动
2. 空物体很常见,其作用:
-
用于节点的组织和管理(谁做父节点都不合适)
轴心只能在建模软件修改,我们可以用空物体代替原先的轴心
-
用于标记一个位置
3. GameObject,其实是一个节点 / 容器
一般所谓的 “物体” ,即有形状的东西,对应的 Mesh
(四)Global 与 Local
1. Global,即世界坐标系(默认使用)
- 以世界中心为轴
- 6 个方向代表:上下 东西 南北(无法向前运动)
2. Local,即本地坐标系
- 以物体自身为轴
- 6 个方向代表:上下 前后 左右
- y 轴称为
up
,z 轴称为forward
,x 轴称为right
- 一般的,要求
模型的正脸与 z 轴方向一致
(五)Pivot 与 Center
1. Pivot,轴心(默认使用)
2. Center,几何中心
一般来说,物体的轴心并不在几何中心处,我们更喜欢用 Pivot 模式
三、组件
(一)组件
组件 Component,代表一个功能
例如:
- Light,光源
- Mesh Filter,网格过滤器
- Mesh Renderer,网格渲染器
(二)添加删除组件
通过此操作,可让一个空节点,变成一个实实在在的物体。组件,代表一个功能,需要什么功能,就添加什么组件
(三)AudioSource 组件
AudioSource 组件,用于播放音乐 / 音效
- 添加一个音乐文件,*.mp3 / wav / aiff
- 创建一个物体
Add Component,Audio | Audio Source
将音乐拖到 AudioSourse.AudioClip 属性
在 3D 窗口上方,选 Toggle Audio On
(四)Transform 组件
1. Transform,称为变换组件
物体的基本参数:
- Position,位置(相对坐标,相对父物体而言,没有父物体就是世界坐标)
- Rotation,旋转(欧拉角)
- Scale,缩放
2. Transform 组件特点
- 所以物体都有
- 不能被删除
(五)摄像机
1. 摄像机 Camera,负责拍摄游戏画面
演示:
- 调整窗口布局,Scene / Game 并排显示
- 选中摄像机,观察镜头范围
- 摄像机的 z 轴指向,即为拍摄方向
- 拍到的画面,呈现在 Game 窗口中(Game 窗口中的画面,即为玩家最终所见画面)
2. 调整摄像机的角度,两种方法
- 手工 移动、旋转 摄像机,对准目标
- Align with View,与 3D 视图对齐
先在 3D 视图里摆好角度,此为观察者视角;然后选中 Main Camera,执行 Align with View(Ctrl + Shift + F
)
此时,摄像机视角与观察者视角完全相同
四、脚本
(一)脚本
脚本 Script,用于驱动游戏逻辑
(动态效果、添加用户交互的实现方式)
1. 添加一个脚本
- 右键,Create | C# Script
- 文件名必须规范(规范命名:遵循Pascal命名法则,单词首字母大写,例如:MyFristScript),文件名即为类名(不能使用中文、标点符号、空格等)
2. 双击在 VS 中打开脚本,检查类名与文件名是否一致
如果不一致,后面是没法使用的
3. 在 VS 中编辑代码
添加一行打印输出,其中,Debug 是 Unity API 中的一个工具类
4. CTRL + S ,保存代码 ,并闭 VS
5. 编译
编译过程是自动的。保存脚本,回到Unity时会自动重新编译。
6. 挂载脚本
两种办法:
- 点 Add Component ,选 Scripts | Simple Logic
- 或者,直接将脚本拖到 Inspector 窗口的最下方
7. 运行游戏
- 点 Play 按钮,运行游戏
- 在 Console 窗口中,观察输出
若 Console 窗口未显示,则 Window | General | Console 调出此窗口 - 再次点 Play 按钮,停止游戏
注:
- C# 文件名必须和类型一致,否则无法挂载(反射机制),如果不一致,要修改类名,必须在 VS 中双击类名+右键 重命名
- 脚本必须挂载到物体上,才会被调用
(二)当前物体
1. 在 SimpleLogic.cs 中,获取当前物体
- this,当前脚本组件
- this.gameObject,当前物体
this.gameObject.name,当前物体的名字 - this.gameObject.transform,当前物体下的 Transform 组件(为了简化书写,也可以写作 this.transform,效果相同)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SimpleLogic : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Debug.Log("** 我的第一个脚本");
GameObject obj = this.gameObject;
string name = obj.name;
Debug.Log("** 物体名字:" + name);
Transform tr = obj.transform;
Vector3 pos = tr.position; // 三维向量
Debug.Log("物体的位置:" + pos.ToString("F3")); // 保留3位小数
}
// Update is called once per frame
void Update()
{
}
}
2. API 中的大部分类型,来自于 UnityEngine
- 基类 MonoBehaviour
- 游戏物体 GamrObject
- 变换组件 Transform
- 三维向量 Vector3
(三)物体的坐标
1. 物体的坐标
- transform.position,世界坐标(相对于世界中心点)
- transform.localPosition,本地坐标(相对于父物体)
一般使用的是 localPosition,与 Inspector 中的值一致
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SimpleLogic : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Debug.Log("** 开始测试..");
Vector3 pos1 = this.gameObject.transform.position;
Debug.Log("物体世界坐标:" + pos1.ToString("F3"));
Vector3 pos2 = this.gameObject.transform.localPosition;
Debug.Log("物体本地坐标:" + pos2.ToString("F3"));
}
// Update is called once per frame
void Update()
{
}
}
2. 为了简化书写,以下两种写法等效
this.gameObject.transform.position、this.transform.position,其中,this.transform 指向的就是 this.gameObject.transform
3. Vector3 类型,即三维向量,含 x y z 三个分量(float)
设置物体的坐标:
this.transform.localPosition = new Vector3(1.5f, 0, 2.0f);
// 其中,float 型的数值,在书写时应以 f 结尾
(四)播放模式
- Edit Mode,编辑模式
- Play Mode,播放模式
在播放模式下,实时显示
场景中的物体和属性,游戏中的状态不可保存
(You must exit play mode to save the scene!)
五、帧更新
(一)帧更新
Frame,一个游戏帧
FrameRate,帧率 / 刷新率
FPS(Frames Per Second),每秒更新多少帧
Update( ),称为帧更新,此方法会被游戏引擎定时调用,以更新游戏的状态
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SimpleLogic : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Debug.Log("** SimpleLogic : Start()");
}
// Update is called once per frame
void Update()
{
Debug.Log("** Update 帧更新 ..");
}
}
1. 帧率观察
- Time.time,游戏时间(从游戏启动开始已经经过了多长时间)
- Time.deltaTime,距上次更新的 时间差
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SimpleLogic : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Debug.Log("** SimpleLogic : Start()");
}
// Update is called once per frame
void Update()
{
Debug.Log("** Update 帧更新 .. time =" + Time.time + " 时间差 =" + Time.deltaTime);
}
}
显然,帧率是不固定的,Unity 会尽量较快的更新
2. Unity 不支持固定帧率,但可以设定一个近似帧率
// 在 Start() 中设置
Application.targetFrameRate = 60;
其中,指示 Unity 尽量以 FPS = 60 的帧率更新游戏
(二)移动物体
1. 在 Update( ) 中,移动物体的位置
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SimpleLogic : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Debug.Log("** SimpleLogic : Start()");
// 设置一下帧率,让电脑不要太卡
Application.targetFrameRate = 60;
}
// Update is called once per frame
void Update()
{
Debug.Log("** Update 帧更新 .. time =" + Time.time + " 时间差 =" + Time.deltaTime);
Vector3 pos = this.transform.localPosition;
pos.x += 0.01f;
this.transform.localPosition = pos;
}
}
物体的运动并不是匀速的,每次运动 0.01 米,但时间间隔 deltaTime 不固定
2. 匀速运动
使用 deltaTime,可以实现让物体匀速运动
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SimpleLogic : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Debug.Log("** SimpleLogic : Start()");
// 设置一下帧率,让电脑不要太卡
Application.targetFrameRate = 60;
}
// Update is called once per frame
void Update()
{
Debug.Log("** Update 帧更新 .. time =" + Time.time + " 时间差 =" + Time.deltaTime);
float speed = 3;
float distance = speed * Time.deltaTime;
Vector3 pos = this.transform.localPosition;
pos.x += distance; //0.01f;
this.transform.localPosition = pos;
}
}
完