文章目录
1、简单题
1.1 解释游戏对象(GameObjects) 和 资源(Assets)的区别与联系。
区别:
游戏对象是出现在场景中的各种物体或场景。 即游戏中的每个对象都是一个游戏对象。游戏对象自己不做任何事。他们需要专有属性,才可以成为一个角色,一个环境,或一种特殊效果。游戏对象更像是一种容器。
资源是项目中的素材,包括图像、音乐文件、脚本文件、预制文件等。
联系:
游戏对象可保存为资源(以便重复利用),资源可以作为组件或游戏对象创建游戏对象实例。
1.2 下载几个游戏案例,分别总结资源、对象组织的结构(指资源的目录组织结构与游戏对象树的层次结构)
资源的目录组织结构: 资源文件夹将作用相似的资源放在同一个文件夹中。
游戏对象树的层次结构: 游戏对象树类似于树,一个游戏对象往往是包括了多个子对象。子对象又包括了它的子对象
1.3 编写一个代码,使用 debug 语句来验证 MonoBehaviour 基本行为或事件触发的条件
基本行为包括 Awake() Start() Update() FixedUpdate() LateUpdate()
常用事件包括 OnGUI() OnDisable() OnEnable()
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class init : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Debug.Log("It is in Start");
}
// Update is called once per frame
void Update()
{
Debug.Log("It is in Update");
}
private void Awake()
{
Debug.Log("It is in Awake");
}
private void FixedUpdate()
{
Debug.Log("It is in FixedUpdate");
}
private void LateUpdate()
{
Debug.Log("It is in LateUpdate");
}
private void OnGUI()
{
Debug.Log("It is in OnGUI");
}
private void OnDisable()
{
Debug.Log("It is in OnDisable");
}
private void OnEnable()
{
Debug.Log("It is in OnEnable");
}
}
执行效果:
解释:
awake:当一个脚本实例被载入时被调用
start:在所有update函数之前被调用一次,用于初始化
update:当行为启用时,其update在每一帧被调用
fixedupdate:当行为启用时,其fixedupdate在每一时间片被调用
LateUpdate:在每帧执行完毕调用,在所有update结束后才执行,比较适合用于命令脚本的执行。
OnGUI:渲染和处理GUI事件时调用,一般在这个函数里绘制GUI菜单
OnEnable:当对象变为可用或激活状态时被调用
OnDisable:当对象变为不可用或非激活状态时被调用
1.4 查找脚本手册,了解 GameObject,Transform,Component 对象
分别翻译官方对三个对象的描述(Description)
描述下图中 table 对象(实体)的属性、table 的 Transform 的属性、 table 的部件
本题目要求是把可视化图形编程界面与 Unity API 对应起来,当你在 Inspector 面板上每一个内容,应该知道对应 API。
例如:table 的对象是 GameObject,第一个选择框是 activeSelf 属性。
用 UML 图描述 三者的关系(请使用 UMLet 14.1.1 stand-alone版本出图)
翻译:
GameObject:游戏对象是Unity中表示游戏角色,游戏道具和游戏场景的基本对象。他们自身无法完成许多功能,但是他们构成了那些给予他们实体功能的组件的容器。
Transform:转换组件决定了游戏场景中每个游戏对象的位置,旋转和缩放比例。每个游戏对象都有转换组件。
Component:组件是游戏中对象和行为的细节。它是每个游戏对象的功能部分。
table对象属性:
table 的对象是 GameObject,第一个选择框是activeSelf:可以定义对象的名称,动静态等属性;第二个选择框是Transform:可以定义对象的位置、面向方向、大小;第三个选择框是Box Collider:可以调整坐标系的位置、大小;第四个选择框是Component:可以给对象增加行为
table 的 Transform 的属性:
Position为(0,0,0);Rotation为(0,0,0)、Scale为(1,1,1)。
table 的部件:
Tranform、Mesh Filter、Box Collider、Mesh Renderer
UML图:
1.5 整理相关学习资料,编写简单代码验证以下技术的实现:
查找对象
public static GameObject Find(string name);
//通过名字查找
public static GameObject FindWithTag(string tag);
//通过标签查找单个对象
public static GameObject[] FindGameObjectsWithTag(string tag);
//通过标签查找多个对象
添加子对象
public static GameObect CreatePrimitive(PrimitiveTypetype)
遍历对象树
foreach (Transform child in transform) {
Debug.Log(child.gameObject.name);
}
清除所有子对象
foreach (Transform child in transform) {
Destroy(child.gameObject);
}
1.6 资源预设(Prefabs)与 对象克隆 (clone)
预设(Prefabs)有什么好处?
预设像一个类模板,可以迅速方便创建大量相同属性的对象、操作简单,代码量少,减少出错概率。修改的复杂度降低,一旦需要修改所有相同属性的对象,只需要修改预设即可,所有通过预设实例化的对象都会做出相应变化。
预设与对象克隆 (clone or copy or Instantiate of Unity Object) 关系?
修改预设后,所有通过预设实例化的对象都会做出相应变化。但是克隆只是复制它,这个对象独立于原来的对象,在修改克隆体不会影响原有的。这类似于C++值复制和引用的差别。
制作 table 预制,写一段代码将 table 预制资源实例化成游戏对象
public GameObject table;
void Start () {
Debug.Log("ITStart");
GameObject newTable = (GameObject)Instantiate(table.gameObject);
}
2、编程实践,小游戏
游戏内容: 井字棋 或 贷款计算器 或 简单计算器 等等
技术限制: 仅允许使用 IMGUI 构建 UI
作业目的:
了解 OnGUI() 事件,提升 debug 能力
提升阅读 API 文档能力
在阅读IMGUI的API后实现,具体代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class newGame : MonoBehaviour
{
//引入图片
public Texture letterX;
public Texture circle;
public Texture2D backGround;
private int[,] board = new int[3, 3]; //储存棋盘信息,0为X,1为O,
private int turn = 1; //标记轮到谁,1为O,0为X
private int count = 0; //统计棋盘棋子数量
private bool finished = false; //标记游戏是否结束
// Start is called before the first frame update
void Start()
{
Reset();
}
void OnGUI()
{
GUI.Label(new Rect(100, 50, 210, 50), "Tic - Tac - Toe"); //游戏标题
if (GUI.Button(new Rect(400, 50, 100, 50), "RESET")) { //重置游戏按钮
Reset();
}
//游戏过程
for (int i = 0; i < 3; ++ i) {
for (int j = 0; j < 3; ++ j) {
//模拟轮次点击过程
if (board[i, j] == 1) {
GUI.Button(new Rect(400 + 50 * i, 150 + 50 * j, 50, 50), circle);
}
else if (board[i, j] == 0) {
GUI.Button(new Rect(400 + 50 * i, 150 + 50 * j, 50, 50), letterX);
}
else {
if (GUI.Button(new Rect(400 + 50 * i, 150 + 50 * j, 50, 50), backGround)) {
if (finished == true) //游戏结束便保持现状
continue;
count++;
if (turn == 1) {
board[i, j] = 1;
turn = 0;
}
else if (turn == 0) {
board[i, j] = 0;
turn = 1;
}
}
}
}
}
//得到结果并输出
if (count >= 5)
{
int State = getResult(); //-2表示游戏未结束,-1表示平局,0表示X胜利,1表示O胜利
if (State == 0) {
GUI.Label(new Rect(400, 100, 100, 50), "X WIN!");
finished = true;
}
else if (State == 1) {
GUI.Label(new Rect(400, 100, 100, 50), "O WIN!");
finished = true;
}
else if (State == -1 && count == 9) {
GUI.Label(new Rect(400, 100, 210, 50), "NO ONE WIN");
}
}
}
int getResult()
{
//检验行是否存在满足胜利的条件
for (int i = 0; i < 3; ++ i) {
if (board[i, 0] == board[i, 1] && board[i, 0] == board[i, 2] && board[i, 0] != -1) {
return board[i, 0];
}
}
//检验列是否存在满足胜利的条件
for (int j = 0; j < 3; ++ j) {
if (board[0, j] == board[1, j] && board[0, j] == board[2, j] && board[0, j] != -1) {
return board[0, j];
}
}
//检验对角线是否存在满足胜利的条件
if (board[0, 0] == board[1, 1] && board[0, 0] == board[2, 2] && board[0, 0] != -1)
return board[0, 0];
if (board[0, 2] == board[1, 1] && board[0, 2] == board[2, 0] && board[0, 2] != -1)
return board[0, 2];
//判断是否平局
int counts = 0;
for (int i = 0; i < 3; ++ i) {
for (int j = 0; j < 3; ++ j) {
if (board[i, j] != -1) {
counts++;
}
else
return -2;
}
}
if (counts == 9) {
return -1;
}
return -2;
}
// Update is called once per frame
void Update()
{
}
//重置游戏
void Reset()
{
turn = 1;
count = 0;
finished = false;
for (int i = 0; i < 3; ++ i) {
for (int j = 0; j < 3; ++ j) {
board[i, j] = -1;
}
}
}
}
3 思考题【选做】
3.1
微软 XNA 引擎的 Game 对象屏蔽了游戏循环的细节,并使用一组虚方法让继承者完成它们,我们称这种设计为“模板方法模式”。为什么是“模板方法”模式而不是“策略模式”呢?
模板方法模式定义了一个算法的步骤或者骨架,并允许子类别为一个或多个步骤提供其实践方式。让子类别在不改变算法架构的情况下,重新定义算法中的某些步骤。而策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。从二者的定义来分析,微软 XNA 引擎的 Game 对象的游戏循环的步骤一直都是一样的,故更符合模板方法模式。
3.2
将游戏对象组成树型结构,每个节点都是游戏对象(或数)。尝试解释组合模式(Composite Pattern / 一种设计模式)。
组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。组合模式是将对象组合成树形结构以表示“部分-整体”的层次结构,它使得用户对单个对象和组合对象的使用具有一致性。
使用 BroadcastMessage() 方法,向子对象发送消息。你能写出 BroadcastMessage() 的伪代码吗?
父对象代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class father : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Debug.Log("It is in fatherStart");
this.BroadcastMessage("testBroad", "hello sons!");
}
// Update is called once per frame
void Update()
{
}
}
子对象代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class son : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Debug.Log("It is in sonStart");
}
// Update is called once per frame
void Update()
{
}
public void testBroad(string str)
{
print("son receive message: " + str);
}
}
结果: