1、简答题
1.1 解释 游戏对象(GameObjects) 和 资源(Assets)的区别与联系。
游戏对象(GameObjects),游戏程序空间中的事物,可能是 Empty(空,最有用的事物)、2D、3D、光线、摄像机等
游戏资源(Assets),构造游戏对象、装饰游戏对象、配置游戏的物体和数据。即序列化的或存储格式的游戏对象或数据
联系:资源能够被导入到游戏中,被游戏对象使用,影响游戏对象的属性。资源还可以实例化为具体的游戏对象。
1.2 下载几个游戏案例,分别总结资源、对象组织的结构(指资源的目录组织结构与游戏对象树的层次结构)
- 资源的目录组织结构分两层,内容与插件。内容主要包含动画、音频、文档材料、模型、加工、预制件、场景、脚本、标准资源、材质这几个部分。
- 游戏对象树就如同Windows的文件资源管理器一样,树目录结构:一个游戏对象(文件夹)包含多个子对象(子文件夹),子对象(子文件夹)又可以继续包含多个子对象(子文件夹)。
分为游戏控制器,环境,玩家,目标,符合游戏的各个必要的环节
1.3 编写一个代码,使用 debug 语句来验证 MonoBehaviour 基本行为或事件触发的条件
- 基本行为包括 Awake() Start() Update() FixedUpdate() LateUpdate()
- 常用事件包括 OnGUI() OnDisable() OnEnable()
// C# Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour {
// 判断是否执行过相应函数
private bool isUpdate = false;
private bool isFixedUpdate = false;
private bool isLateUpdate = false;
private bool isOnGUI = false;
// 当一个脚本实例被载入时 Awake 被调用
void Awake () {
Debug.Log ("Awake");
}
// Start 仅在 Update 函数第一次被调用前调用
void Start () {
Debug.Log ("Start");
}
// 当 MonoBehaviour 启用时,其 Update 在每一帧被调用
void Update () {
// 确保函数只被执行一次
if (!isUpdate) {
Debug.Log ("Update");
isUpdate = true;
}
}
// 当 MonoBehaviour 启用时,其 FixedUpdate 在每一帧被调用
void FixedUpdate () {
// 确保函数只被执行一次
if (!isFixedUpdate) {
Debug.Log ("Fixed Update");
isFixedUpdate = true;
}
}
// 当 Behaviour 启用时,其 LateUpdate 在每一帧被调用
void LateUpdate () {
// 确保函数只被执行一次
if (!isLateUpdate) {
Debug.Log ("Late Update");
isLateUpdate = true;
}
}
// 当对象变为不可用或非激活状态时此函数被调用
void OnDisable () {
Debug.Log ("On Disable");
}
// 当对象变为可用或激活状态时此函数被调用
void OnEnable () {
Debug.Log ("On Enable");
}
// 渲染和处理 GUI 事件时调用
void OnGUI () {
// 确保函数只被执行一次
if (!isOnGUI) {
Debug.Log ("On GUI");
isOnGUI = true;
}
}
}
运行得到如下结果
该顺序满足各事件触发的条件。
- MonoBehaviour 基本行为或事件触发的条件
- Awake 当一个游戏对象实例被载入时Awake被调用,或者脚本构造时调用。
- Start 第一次进入游戏循环时调用
- FixUpdate 每个游戏循环,由物理引擎调用
- Update 所有 Start 调用完后,被游戏循环调用
- LastUpdate 所有 Update 调用完后,被游戏循环调用
- OnGUI 游戏循环在渲染过程中,场景渲染之后调用
- OnDisable 当对象变为不可用或非激活状态时被调用
- OnEnable 当对象变为可用或激活状态时此函数被调用。
1.4 查找脚本手册,了解 GameObject,Transform,Component 对象
- 分别翻译官方对三个对象的描述(Description)
GameObjects are the fundamental objects in Unity that represent characters, props and scenery. They do not accomplish much in themselves but they act as containers for Components, which implement the real functionality.
游戏对象是Unity中的基本对象,表示角色、道具和场景。它们本身不完成很多工作,但它们充当Component的容器,由Component来实现真正的功能。
The Transform component determines the Position, Rotation, and Scale of each object in the scene. Every GameObject has a Transform.
转换组件决定场景中每个对象的位置、旋转和比例。
Components are the nuts & bolts of objects and behaviors in a game.They are the functional pieces of every GameObject.
组件是游戏中对象和行为之间的螺母和螺丝。它们是每个游戏对象的功能部件。
- 描述下图中 table 对象(实体)的属性、table 的 Transform 的属性、 table 的部件
- 本题目要求是把可视化图形编程界面与 Unity API 对应起来,当你在 Inspector 面板上每一个内容,应该知道对应 API。
- 例如:table 的对象是 GameObject,第一个选择框是 activeSelf 属性。
table 对象(实体)的属性:
- table 的对象是 GameObject
- activeSelf(勾选框):对象是否启用——启用
- ObjectName(文本框):对象名——table
- Tag(选择框):标签——untagged
- Layer(选择框):层级——default
table 的 Transform 的属性:
- Position(位置)
- Rotation(旋转)
- Scale(尺寸)
table 的部件:
包括Transform(转换),Cube(立方体,网格过滤器),Box Collider(盒碰撞体),Mesh Renderer(网格渲染器),Materials(材质)。
- 用 UML 图描述 三者的关系(请使用 UMLet 14.1.1 stand-alone版本出图)
1.5 资源预设(Prefabs)与 对象克隆 (clone)
- 预设(Prefabs)有什么好处?
- 预制(Prefabs),文件存储的游戏对象与属性的组合,可一次性方便地加载到内存。
- 如果说基本游戏对象是原材料,预制就是半成品。
- 预制可以被置入多个场景中,也可以在一个场景被多次置入。
- 可以用预制管理相似物体,当需要批量的修改同一类构成体时,只需要修改原prefabs文件。
- 预设与对象克隆 (clone or copy or Instantiate of Unity Object) 关系?
- 克隆要求游戏场景中已有对象存在,而预设不要求。
- 克隆出的对象各自的属性相互独立,不能同时更改;而预设原型改变,所有预设实例都会随之改变。
- 制作 table 预制,写一段代码将 table 预制资源实例化成游戏对象
代码如下,然后将其挂在一个新建的游戏对象上:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Instantiate : MonoBehaviour
{
public GameObject obj; //传入的预设
void Start()
{
GameObject instance = (GameObject)Instantiate(obj, transform.position, transform.rotation);
}
}
最终结果如下:
2、 编程实践,小游戏
游戏内容: 井字棋 或 贷款计算器 或 简单计算器 等等
技术限制: 仅允许使用 IMGUI 构建 UI
作业目的:
了解 OnGUI() 事件,提升 debug 能力
提升阅读 API 文档能力
简单计算器
3、 思考题
3.1 微软 XNA 引擎的 Game 对象屏蔽了游戏循环的细节,并使用一组虚方法让继承者完成它们,我们称这种设计为“模板方法模式”。
- 为什么是“模板方法”模式而不是“策略模式”呢?
模板方法(Template Method)模式的定义如下:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
策略模式则定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
微软XNA引擎给出一组虚方法,形成算法骨架,而将方法的实现交由子类完成,属于模板方法模式。
3.2 将游戏对象组成树型结构,每个节点都是游戏对象(或数)。
- 尝试解释组合模式(Composite Pattern / 一种设计模式)。
又叫作部分-整体模式,它是一种将对象组合成树状的层次结构的模式,用来表示“部分-整体”的关系,使用户对单个对象和组合对象具有一致的访问性。
优点:
1.组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码;
2.更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”;
缺点:
1.设计较复杂,客户端需要花更多时间理清类之间的层次关系;
2.不容易限制容器中的构件;
3.不容易用继承的方法来增加构件的新功能;
- 使用 BroadcastMessage() 方法,向子对象发送消息。你能写出 BroadcastMessage() 的伪代码吗?
为父类对象table添加方法:
void Start () {
this.BroadcastMessage("Message");
}
为子类对象chair添加方法:
void Message(){
Debug.Log("Hello!");
}
3.3 一个游戏对象用许多部件描述不同方面的特征。我们设计坦克(Tank)游戏对象不是继承于GameObject对象,而是 GameObject 添加一组行为部件(Component)。
- 这是什么设计模式?
装饰器模式 - 为什么不用继承设计特殊的游戏对象?
(1)难以用继承机制描述各类事物;
(2)多重继承太复杂;
(3)继承、多态这种机制会导致对象行为变得异常复杂。
为了保证引擎的通用性,我们用 Component 装饰游戏对象,赋予它各种能力。
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。