1、简答题【建议做】
- 解释 游戏对象(GameObjects) 和 资源(Assets)的区别与联系。
-
游戏对象表示某些资源的具体实例化,出现在游戏的场景中,游戏对象一般有敌人,场景,摄像机等非实体虚拟父类,子类一般为游戏内的实体
-
资源表示硬盘中的文件,存储在Unity工程的Assets文件中,资源可以被多个对象使用,也可以作为模板实例化成游戏内的实体,一般划分为材质,对象,场景,预设,声音,脚本,贴图等子文件夹中。
-
- 下载几个游戏案例,分别总结资源、对象组织的结构(指资源的目录组织结构与游戏对象树的层次结构)
- GameObject的组织结构
-
-
Assets的组织结构
-
- GameObject的组织结构
- 编写一个代码,使用 debug 语句来验证 MonoBehaviour 基本行为或事件触发的条件
- 基本行为包括 Awake() Start() Update() FixedUpdate() LateUpdate()
- 常用事件包括 OnGUI() OnDisable() OnEnable()
-
Awake() :当一个脚本实例被载入时被调用
-
Start() : 在所有update()函数被调用之前调用
-
Update() : 当行为启用时其Update()在每一帧被调用
-
FixedUpdate(): 当行为启动时其Update()在每一时间片被调用
-
LateUpdate() : 当行为启用时,在所有Update()执行完后执行
-
Onable() : 当对象变为可用或激活状态时此函数被调用,OnEnable不能用于协同程序(物体启动时被调用)
-
Ondisable() : 当对象变为不可用或非激活状态时此函数被调用。当物体被销毁时他被调用,并且可用于任意清理代码 。当脚本编译完成之后重新加载时,该函数被调用,OnEnable()在脚本被载入后被调用。(物体被禁用时调用)
-
OnGUI() : 绘制GUI时触发。一般在这个函数里绘制GUI菜单(GUI显示函数只能在OnGUI中被调用)
-
- 查找脚本手册,了解 GameObject,Transform,Component 对象
- 分别翻译官方对三个对象的描述(Description)
-
GameObeject:Base class for all entities in Unity Scenes.
-
翻译:Unity场景中所有实体的基类
-
Transform:Position, rotation and scale of an object.Every object in a Scene has a Transform. It's used to store and manipulate the position, rotation and scale of the object. Every Transform can have a parent, which allows you to apply position, rotation and scale hierarchically.
-
翻译:对象的位置旋转和比例。场景中每个对象都有一个变换。他用于操作对象的位置,缩放和旋转。每个转换都可以拥有一个父类,允许分层应用位置。
-
Component:Base class for everything attached to GameObjects.
-
翻译:所有附加到GameObject的东西的基类。
- 描述下图中 table 对象(实体)的属性、table 的 Transform 的属性、 table 的部件
- 本题目要求是把可视化图形编程界面与 Unity API 对应起来,当你在 Inspector 面板上每一个内容,应该知道对应 API。
- 例如:table 的对象是 GameObject,第一个选择框是 activeSelf 属性。
-
-
table:第一个选择框时便签Tag:当前选择的是未加标签。第二个选择框是层,当前是默认属性。第三个属性是预设。
-
Transform:有三个属性:Position,Rotation,Scale:表示位置,旋转,比例
-
组件:Mesh Filter,Box Collider,Mesh Renderer
- 用 UML 图描述 三者的关系(请使用 UMLet 14.1.1 stand-alone版本出图)
-
- 资源预设(Prefabs)与 对象克隆 (clone)
- 预设(Prefabs)有什么好处?
-
使游戏对象可重复使用,这个游戏对象已经配置完成,可以直接加入到游戏中去,提高了工作效率。
- 预设与对象克隆 (clone or copy or Instantiate of Unity Object) 关系?
-
预设与克隆都可以由一个对象生成大量相同的对象,但是预设出的对象在本体改变时回随着本体进行改变,而克隆出的对象之间没有联系,可以随意更改。
- 制作 table 预制,写一段代码将 table 预制资源实例化成游戏对象
-
先绘制出桌子,然后拖入Assets框中,做成预制资源
-
之后写一个脚本,如图:
-
-
之后应用脚本,然后把预制好的table资源拖入框中如图:
-
2、 编程实践,小游戏
- 游戏内容: 井字棋 或 贷款计算器 或 简单计算器 等等
- 技术限制: 仅允许使用 IMGUI 构建 UI
- 作业目的:
- 了解 OnGUI() 事件,提升 debug 能力
- 提升阅读 API 文档能力
主要代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewBehaviourScript : MonoBehaviour
{
private int[,] chessBoard = new int[3, 3];
private int turn = 1;//决定到哪一方
void Start()
{
Reset();//初始化界面
}
int checkWin()//判断胜负
{
for (int i = 0; i < 3; i++)
{
if (chessBoard[i, 0] == chessBoard[i, 1] && chessBoard[i, 0] == chessBoard[i, 2] && chessBoard[i, 0] != 0)
return chessBoard[i, 0];//]
}//竖着赢
for (int i = 0; i < 3; i++)
{
if (chessBoard[0, i] == chessBoard[1, i] && chessBoard[0, i] == chessBoard[2, i] && chessBoard[0, i] != 0)
return chessBoard[0, i];
}//横着赢
if (chessBoard[0, 0] == chessBoard[1, 1] && chessBoard[0, 0] == chessBoard[2, 2] && chessBoard[0, 0] != 0)
return chessBoard[0, 0];//斜着赢
if (chessBoard[2, 0] == chessBoard[1, 1] && chessBoard[2, 0] == chessBoard[0, 2] && chessBoard[2, 0] != 0)
return chessBoard[2, 0];//斜着赢
int count = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (chessBoard[i, j] != 0)
{
count++;
}
}
}
if (count == 9)//被填满仍无人胜利,平局
return 0;
return 3;
}
void OnGUI()
{
if (GUI.Button(new Rect(300, 50, 150, 50), "Start Game"))
{
Reset();//点击Start Game按钮重置游戏
}
GUISkin skin = GUI.skin;
skin.button.normal.textColor = Color.green;
skin.button.hover.textColor = Color.blue;//设置按钮样式
int State = checkWin();//判断当前状态2:x赢1:O赢0:平局
if (State == 2)
{
skin.button.normal.textColor = Color.red;
GUI.Label(new Rect(300, 105, 50, 50), "X Win!");
}
else if (State == 1)
{
skin.button.normal.textColor = Color.red;
GUI.Label(new Rect(300, 105, 50, 50), "O Win");
}
else if (State == 0)
{
skin.button.normal.textColor = Color.red;
GUI.Label(new Rect(300, 105, 50, 50), "Tied");
}
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (chessBoard[i, j] == 1)
{
// GUI.Label(new Rect(400, 105, 50, 50), "X's turn.");
GUI.Button(new Rect(300 + 50 * i, 130 + j * 50, 50, 50), "O");
}
else if (chessBoard[i, j] == 2)
{
//GUI.Label(new Rect(400, 105, 50, 50), "O's turn.");
GUI.Button(new Rect(300 + 50 * i, 130 + j * 50, 50, 50), "X");
}
if (GUI.Button(new Rect(300 + 50 * i, 130 + j * 50, 50, 50), ""))
{//按钮没被点击时,被点击后改变棋盘状态,然后根据棋盘状态改变按钮显示
if (State == 3)
{
if (turn == 1)
chessBoard[i, j] = 1;
else if (turn == -1)
chessBoard[i, j] = 2;
turn = -turn;
}
}
}
}
}
void Reset()
{//重置棋盘
turn = 1;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
chessBoard[i, j] = 0;
}
}
}
void Update()
{
}
}
3、思考题【选做】
- 微软 XNA 引擎的 Game 对象屏蔽了游戏循环的细节,并使用一组虚方法让继承者完成它们,我们称这种设计为“模板方法模式”。
- 为什么是“模板方法”模式而不是“策略模式”呢?
-
Game对象看作一个类,它使用一组虚方法来声明出该对象的细节功能,然后由子类将剩余的逻辑实现,当游戏对象遇到不同的环境,只有其中一个或几个方法需要不同的实现方法时,但是其他方法并不全部需要改变时,这样就可以只替换其中一个方法,也就是说使用不同的子类来提供不同的实现,这样就大大提高了代码的可复用性。而策略模式是,把不同的算法包装成统一的接口,在不影响客户端的情况下选择不同的算法来进行实现。
总得来说,模板方法可以通过不同的实现来达到不同的效果,而策略模式以不同的实现方法来达到相同的效果。
-
- 为什么是“模板方法”模式而不是“策略模式”呢?
- 将游戏对象组成树型结构,每个节点都是游戏对象(或数)。
- 尝试解释组合模式(Composite Pattern / 一种设计模式)。
-
组合模式可以把一组对象按照树型结构组合成一种层次结构,这种层次结构可以把一组对象表现为一个整体,通过对这个整体进行处理来完成对一个对象和对象的组合的处理。组合模式实现的最关键的地方是简单对象和复合对象必须实现相同的接口
- 使用 BroadcastMessage() 方法,向子对象发送消息。你能写出 BroadcastMessage() 的伪代码吗?
-
foreach childObject
-
sendMessage();
-
- 一个游戏对象用许多部件描述不同方面的特征。我们设计坦克(Tank)游戏对象不是继承于GameObject对象,而是 GameObject 添加一组行为部件(Component)。
- 这是什么设计模式?
-
Decorator模式
- 为什么不用继承设计特殊的游戏对象?
-
因为需要对对象动态的添加功能,采用继承需要修改的代码过多,采用Decorate模式,可以在不修改原来代码的情况下增加新的功能核模块。
-