本篇博客是Unity3D第一周课程作业,包含对Unity3D基本概念的详尽解释和井字棋开发指南。若有疏漏,欢迎大家在评论区指正,谢谢~!
概念解答
解释 游戏对象(GameObjects) 和 资源(Assets)的区别与联系
区别
游戏对象
游戏对象是游戏场景中的所有实体的统称。它不仅包含游戏中的实体,同时也包含摄像机、光源等。正是他们之间的互动构成了游戏。
资源
资源包含材质、音乐、脚本等等,他们通常附着于游戏对象而发挥作用,但同时,也包含可以直接实例化为游戏对象的对象的预制。
联系
资源可以附着在游戏对象上,也可以实例化为对象而发挥作用,但是独立的资源不能直接发挥作用。
下载几个游戏案例,分别总结资源、对象组织的结构(指资源的目录组织结构与游戏对象树的层次结构)
资源目录结构
资源目录一般下属多个文件夹以区分不同的资源类型,如预制、材质、场景、脚本、音乐等,在文件夹下放置对应的资源,如此方便制作者对不同资源的管理。
游戏对象树结构
如同资源目录一般,根据用途被划分为几个大的空对象,来区分不同的游戏对象。实际起作用的对象作为这些对象的子对象而存在。常见的花粉中包含:光源、背景、实体、边界、事件、文字、摄像机等。
编写一个代码,使用 debug 语句来验证 MonoBehaviour 基本行为或事件触发的条件
基本行为包括 Awake() Start() Update() FixedUpdate() LateUpdate()
常用事件包括 OnGUI() OnDisable() OnEnable()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BehaviourTest : MonoBehaviour {
void Start () {
Debug.Log ("Test: Start!");
}
void Update () {
Debug.Log ("Test: Update!");
}
private void Awake() {
Debug.Log ("Test: Awake!");
}
private void FixedUpdate() {
Debug.Log ("Test: FixedUpdate!");
}
private void LateUpdate() {
Debug.Log ("Test: LateUpdate!");
}
private void OnGUI() {
Debug.Log ("Test: OnGUI!");
}
private void OnDisable() {
Debug.Log ("Test: OnDisable!");
}
private void OnEnable() {
Debug.Log ("Test: OnEnable!");
}
}结论:结合代码测试结果和官方文档解释得出
- Start: 在脚本被启用情况下的第一帧被调用,先于所有的Update
- Update: 在每一帧都被调用
- Awake: 在脚本被实例化并加载时就调用,调用顺序在Start之前
- FixedUpdate: 在每个时间片,而不是每一帧调用
- LastUpdate: 在Update被调用后调用
- OnGUI: 在GUI事件被触发时调用
- OnDisable: 在脚本被禁用时调用,仅在状态切换时调用,保持时不调用
- OnEnable: 在脚本被启用时调用,仅在状态切换时调用,保持时不调用
查找脚本手册,了解 GameObject,Transform,Component 对象
分别翻译官方对三个对象的描述(Description)
GameObject
- Scripting: 在Unity场景中的所有实体的基类。
- Manual: 游戏对象在Unity中是那些表现角色、道具和场景基础对象。他们本身并不十分完整,但她们作为组件(Components)的容器而存在,这使得她们得以实现她们真正的功能。
Transform
Scripting: 一个对象的位置、旋转(角度)和缩放。每个对象都有一个Transform。它被用于存储、和操作对象的位置、旋转角和缩放。 每个Transform都有一个父元素,这允许分层地应用这些属性。这也就是在层级窗口所呈现的层级。
Manual: Transform组件决定了场景中每个对象的位置、旋转(角度)和缩放。每个游戏对象都有一个Transform。
Component
Scripting: 所有附着于游戏对象类的东西的基类。
描述下图中 table 对象(实体)的属性、table 的 Transform 的属性、 table 的部件
table
1
2
3
4
5// class GameObject
bool activeSelf = true;
int layer; // 为默认值(Default)
string tag = ""; // Untagged
bool isStatic = false;table’s Transform
1
2
3
4// class Transform
Vector3 Position = new Vector3 (0,0F, 0.0F, 0.0F);
Quaternion rotation = new Quaternion (0.0F, 0.0F, 0.0F, 1);
Vector3 localScale = new Vector3 (1, 1, 1);table’s components
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// 基类均为 Components
// class MeshFilter
Mesh mesh = cube;
// class BoxCollider
bool isTrigger = false;
PhysicMaterial material = null;
Vector3 Center = new Vector3 (0.0F, 0.0F, 0.0F);
Vector3 Size = new Vector3 (1, 1, 1);
// class MeshRenderer
Rendering.ShadowCastingMode shadowCastingMode = On;
bool receiveShadows = true;
MotionVectorGenerationMode motionVectorGenerationMode = Object;
Rendering.LightProbeUsage lightProbeUsage = BlendProbes;
Rendering.ReflectionProbeUsage reflectionProbeUsage = BlendProbes;
GameObject lightProbeProxyVolumeOverride = null;
用 UML 图描述 三者的关系
整理相关学习资料,编写简单代码验证以下技术的实现:
查找对象
1
2
3
4
5static GameObject Find (string name) // 通过对象名来查找单个对象
static GameObject FindWithTag (string tag) // 通过对象的tag来查找单个对象
static GameObject[] FindGameObjectsWithTag (string tag) // 通过对象的tag来寻找所有对象
static Object FindObjectOfType(Type type) // 通过对象的类型来寻找对象
static Object[] FindObjectsOfType(Type type) // 通过对象的类型来寻找所有的对象添加子对象
1
2
3GameObject parentObj = GameObject.Find([ParentName]);
GameObject childObj = GameObject.Find([ChildName]);
childObj.transform.parent = parentObj.transform;遍历对象树
如前文所述,FindObjectsOfType函数可以通过对象类型寻找对象,因而将其type令为GameObject即可得到所有的对象的一个列表,遍历列表即可遍历整个对象树
1
2
3for (var obj in GameObject.FindObjectsOfType(typeof(GameObject))) {
// your code here
}清除所有子对象
1
2
3for (int i = 0; i < transform.childCount; i++) {
Destroy (transform.GetChil(i).gameObject);
}此处值得说明的是,在Destory之后,childCount并不会立即减少,
资源预设(Prefabs)与 对象克隆 (clone)
预设(Prefabs)有什么好处?
- 提高设计的复用性,降低设计成本
- 提高资源的复用性,降低游戏空间复杂度
- “类化”游戏对象,提高逻辑复用性
- 变相提供相对统一的设计风格
预设与对象克隆 (clone or copy or Instantiate of Unity Object) 关系?
- 二者都可以创造一类相同/相似的对象
- 由同个预设创造的对象在预设更改时也会同步更改,但是克隆出来的对象是互相独立的
制作 table 预制,写一段代码将 table 预制资源实例化成游戏对象
1
2GameObject prefab = Resources.Load("Prefabs/table") as GameObject;
GameObject instance = Instantiate(prefab);
尝试解释组合模式(Composite Pattern / 一种设计模式
是一种树状层级式的组织结构,它允许使用者递归地处理对象间的关系。在这种模式下,复杂对象和简单对象被一视同仁——复杂对象的内部细节对外部是隐藏的,从而使得客户程序与复杂元素的内部结构解耦。一个形象的例子是计算机的文件系统——文件夹和单个文件从外部看都是一致的。
使用 BroadcastMessage() 方法向子对象发送消息
1
2
3
4
5
6// 父类对象通过BroadcastMessage方法发送字符串消息,子类对象的同名方法将被调用
this.BroadcastMessage("Hey"); // 父类对象发出消息
/*---*/
void Hey(){
// This part will be executed
} // 子类对象同名方法将被调用
开发实验:井字棋
注:仓库地址
有空再写~只看官方文档写游戏真是……