一、简答题
1.解释游戏对象(GameObjects)和资源(Assets)的区别和联系 。
答:
区别:资源是储存在磁盘的文件,保存在Unity Project的Assets文件夹中。包括了各种原材料、3D模型、影像片段等等。 游戏对象是序列化数据的集合,是用于描述资源的实例。包括了mesh、sprite、AudioClip、AnimationClip等。
联系:游戏对象可使用资源作为模板来创建;游戏对象则可以作为资源被保存。
2.下载几个游戏案例,分别总结资源、对象组织的结构(指资源的目录组织结构与游戏对象树的层次结构)
答:
资源是目录组织结构,按照文件类型分类我们可以把他们放到不同的文件夹,包括预设、动画、脚本、场景、材质等,不同资源放到对应的文件夹方便游戏制作过程中对资源的调用。
游戏对象是树层次结构,通过整体-部分的关系构成层次结构,不同层次之间的对象通过树层次结构可以更方便地将游戏过程分解成不同部分。
3.编写一个代码,使用 debug 语句来验证 MonoBehaviour 基本行为或事件触发的条件
基本行为包括 Awake() Start() Update() FixedUpdate() LateUpdate()
常用事件包括OnGUI() OnDisable() OnEnable()
答:
编写代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MyMonoBehaviourTestScript : MonoBehaviour {
void Start () {
Debug.Log("start");
}
void Update () {
Debug.Log("update");
}
private void Awake()
{
Debug.Log("awake");
}
private void FixedUpdate()
{
Debug.Log("fixedupdate");
}
private void LateUpdate()
{
Debug.Log("lateupdate");
}
private void OnGUI()
{
Debug.Log("ongui");
}
private void OnDisable()
{
Debug.Log("ondisable");
}
private void OnEnable()
{
Debug.Log("enable");
}
}
运行代码,根据结果,可以总结各触发条件如下:
Awake() 当一个脚本实例被载入时被调用;Start() 在所有Update函数之前被调用;Update() 当行为启用时,其Update在每一帧被调用;FixedUpdate() 当行为启用时,其 FixedUpdate 在每一时间片被调用;LateUpdate 当Update调用结束时调用;OnGUI 在需要处理和渲染时被调用;OnEnable 当行为变为Enable时调用 ;OnDisable 当行为变为Disable时调用。
4.查找脚本手册,了解GameObject、Transform、Component对象。
(1)分别翻译官方对三个对象的描述(Description)
答: GameObject:在Unity场景中所有实体的基类。
Transform:对象的位置、旋转、以及比例。
Component:所有附加到GameObjects的东西的基类。
(2)描述下图中 table 对象(实体)的属性、table 的 Transform 的属性、 table 的部件
答:table的对象属性:第一个选择框是activeSelf属性,第二个是tag属性,第三个是layer属性;
table的Trasnsform属性第一个是position属性,第二个是rotation属性,第三个是localScale属性。
table的部件:Transform、Cube、BoxCollider、Mesh Renderer等部件。
(3)用 UML 图描述 三者的关系(请使用 UMLet 14.1.1 stand-alone版本出图)
5.资源预设(Prefabs)与 对象克隆 (clone)
(1)预设(Prefabs)有什么好处?
使用资源预设可以使我们更加方便快捷地创建多个相同对象。
(2)预设与对象克隆 (clone or copy or Instantiate of Unity Object) 关系?
对象克隆是生成一个和原有对象完全相同的对象,只是单纯的复制,与原有对象独立,预设更像一个模板,相比对象克隆更加灵活,修改预设可以修改所有通过预设创建的对象,而对象克隆产生的对象直接是相互独立的。
(3)制作 table 预制,写一段代码将 table 预制资源实例化成游戏对象。
代码如下:
public GameObject object;
void Start () {
GameObject instance = (GameObject)Instantiate(object.gameObject, transform.position, transform.rotation);
}
二、编程实践(井字棋)
见github连接
https://github.com/Jan-Jsr/3dhomework2
三、思考题
1.微软 XNA 引擎的 Game 对象屏蔽了游戏循环的细节,并使用一组虚方法让继承者完成它们,我们称这种设计为“模板方法模式”。为什么是“模板方法”模式而不是“策略模式”呢?
答:模板方法定义了一个过程或算法中的核心步骤,而对于子步骤或是子方法则是使用继承或接口在子类中实现,从而使得可以通过不改变整体而对一些子步骤进行重构;策略模式则是指对象具备某个行为,但是在不同的场景中,该行为有不同的实现算法。对于微软的XNA引擎,其屏蔽了游戏循环的细节,并使用一组虚方法由继承者完成,目的就是使得可以在不改变代码基本结构的情况下将一些具体模块交由继承者具体实现,这明显更符合“模板方法”,而非“策略模式”。
2.将游戏对象组成树型结构,每个节点都是游戏对象(或数)。
(1)尝试解释组合模式(Composite Pattern / 一种设计模式)。
将对象组合成树形结构以表示“部分整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
(2)使用 BroadcastMessage() 方法,向子对象发送消息。你能写出 BroadcastMessage() 的伪代码吗?
子对象:
public class child1 : MonoBehaviour {
void test(int i){
Debug.Log ("tested for " + i);
}
}
父对象:
public class father1 : MonoBehaviour {
void Update () {
var object = GameObject.Find ("object");
object.BroadcastMessage ("tested", 5.0);
}
}
3.一个游戏对象用许多部件描述不同方面的特征。我们设计坦克(Tank)游戏对象不是继承于GameObject对象,而是 GameObject 添加一组行为部件(Component)。
(1) 这是什么设计模式?
Decorator模式。
(2)为什么不用继承设计特殊的游戏对象?
Decorator模式允许向一个现有的对象添加新的功能,同时又不改变其结构。与Decorator模式相比,使用多重继承容易使代码变得脆弱且不易理解,并且使得耦合变得很高。因此,我们应该优先使用模式,而非继承,从而能够更加灵活地给对象添加额外的职责,并更加清晰的划分各个代码模块。