1.简答题
· 解释 游戏对象(GameObjects)和 资源(Assets) 的区别与联系。
区别:游戏对象是场景中所有物体的总称,是场景中可以看到的任何东西,可以是各种类别的物体。资源是指项目文件中需要用到的材料,可以是图片、音频等,统一存放在文件夹内。
联系: 游戏对象可以保存在资源里,游戏对象可以是资源实例化出来的物体。资源也可以是游戏对象的属性。资源可以创建对象,一个资源可以创建多个对象。
· 下载几个游戏案例,分别总结资源、对象的组织结构。(指资源的目录组织结构和游戏对象树的层次结构)
资源的目录组织结构:
性质相同的资源以文件夹的情形时放在一个文件里。资源主要包括动画,文本,场景,素材,模型,预设以及使用说明等。
游戏对象树的层次结构:
可以理解为树的分差,一个对象包含有多个子对象,子对象包含多个子对象
· 编写一个代码,使用 debug 语句来验证 MonoBehaviour 基本行为或事件触发的条件
基本行为包括 Awake() Start() Update() FixedUpdate() LateUpdate()
常用事件包括 OnGUI() OnDisable() OnEnable()
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewBehaviourScript1 : MonoBehaviour {
void Start()
{
Debug.Log("Start");
}
private void Awake()
{
Debug.Log("Awake");
}
void Update()
{
Debug.Log("Update");
}
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("OnEnable");
}
}
运行结果如下
awake:当一个脚本实例被载入时被调用
start:在所有update函数之前被调用一次
update:当行为启用时,其update在每一帧被调用
fixedupdate:当行为启用时,其fixedupdate在每一时间片被调用
OnGUI:渲染和处理GUI事件时调用
OnEnable:当对象变为可用或激活状态时被调用
OnDisable:当对象变为不可用或非激活状态时被调用
· 查找脚本手册,了解 GameObject,Transform,Component 对象
· 分别翻译官方对三个对象的描述(Description)
1) 游戏对象(GameObject) 用于表示任何可以存在于场景中的事物。
游戏中的每个对象(从角色和可收集物品到光源、摄像机和特效)都是 游戏对象。但是,游戏对象本身无法执行任何操作;您需要向游戏对象提供属性,然后游戏对象才能成为角色、环境或特效。
游戏对象 是 Unity 中的基础对象,表示角色、道具和景物。它们本身并没有取得多大作为,但它们充当 组件 的容器,而组件可实现功能。
为了向游戏对象提供成为光源、树或摄像机所需的属性,需要向游戏对象添加组件。根据要创建的对象类型,可以向游戏对象添加不同的组件组合。
2) 变换组件(Transform) 用于存储游戏对象的位置、旋转、缩放和父子化状态,因此非常重要。游戏对象始终附加一个变换组件,无法删除变换组件或创建没有变换组件的游戏对象。
3) 组件(Component) 是每个 游戏对象 的功能部件。组件包含可以编辑以定义游戏对象行为的属性。有关组件和游戏对象之间关系的详细信息,请参见游戏对象。
· 描述下图中 table 对象(实体)的属性、table 的 Transform 的属性、 table 的部件
本题目要求是把可视化图形编程界面与 Unity API 对应起来,当你在 Inspector 面板上每一个内容,应该知道对应 API。
例如:table 的对象是 GameObject,第一个选择框是 activeSelf 属性。
自制了一个table预制
table 的对象是 GameObject
第一个选择框是activeSelf:可以定义对象的名称,动静态等属性
第二个选择框是Transform:可以定义对象的位置、面向方向、大小
第三个选择框是Add Component:可以添加对象的属性组件
UML图如下:
· 资源预设(Perfabs)和对象克隆(clone)
预设(Perfabs)有什么好处?
Unity 的预设系统允许创建、配置和存储游戏对象及其所有组件、属性值和子游戏对象作为可重用资源。预设资源充当模板,在此模板的基础之上可以在场景中创建新的预制件实例。如果要在场景中的多个位置或项目中的多个场景之间重用以特定方式配置的游戏对象,比如非玩家角色 (NPC)、道具或景物,则应将此游戏对象转换为预设。这种方式比简单复制和粘贴游戏对象更好,因为预制件系统可以自动保持所有副本同步。
预设与对象克隆(clone or copy or Instantiate of Unity Object)关系?
预设与克隆都能创建出相同的对象。预设创建出的对象与源预设依然有联系,后者的更改会影响到前者。但是克隆出的对象与源对象不再有联系。
制作table预制,写一段代码将table预制资源实例化成游戏对象
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LoadTable : MonoBehaviour {
public transform table;
void Start()
{
GameObject newobj=Instantiate<Transform>(table,this.tranform).gameObject;
newobj.transform.position=new Vector3(0,Random.range(-5,5),0);
}
}
2.编程实践,小游戏
游戏内容: 井字棋 或 贷款计算器 或 简单计算器 等等
技术限制: 仅允许使用 IMGUI 构建 UI
选择:井字棋
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class GUIgame : MonoBehaviour
{
private int[,] chess = new int[3, 3];
private int empty=9;
private int turn = 1;
void Start()
{
Init();
}
private void OnGUI()
{
GUI.skin.button.fontSize = 20;
GUI.skin.label.fontSize = 30;
if (GUI.Button(new Rect(450, 400, 200, 80), "Restart"))
{
Init();
}
int result = is_Win();
if (result == 1)
{
GUI.Label(new Rect(500, 20, 100, 50), "O wins");
}
else if (result == 2)
{
GUI.Label(new Rect(500, 20, 100, 50), "X wins");
}
else if (result == 3)
{
GUI.Label(new Rect(470, 20, 200, 50), "no one wins");
}
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (chess[i, j] == 1)
GUI.Button(new Rect(i * 100 + 400, j * 100 + 80, 100, 100), "O");
if (chess[i, j] == 2)
GUI.Button(new Rect(i * 100 + 400, j * 100 + 80, 100, 100), "X");
if (GUI.Button(new Rect(i * 100 + 400, j * 100 + 80, 100, 100), ""))
{
if (result == 0)
{
if (turn == 1) chess[i, j] = 1;
if (turn == 2) chess[i, j] = 2;
empty--;
if (empty % 2 == 1)
{
turn = 1;
}
else
{
turn = 2;
}
}
}
}
}
}
int is_Win()
{
int temp = chess[1, 1];
if (temp != 0)
{
if (temp == chess[0, 0] && temp == chess[2, 2])
{
return temp;
}
if (temp == chess[0, 2] && temp == chess[2, 0])
{
return temp;
}
if (temp == chess[0, 1] && temp == chess[2, 1])
{
return temp;
}
if (temp == chess[1, 0] && temp == chess[1, 2])
{
return temp;
}
}
//判断是否中心的十字形或者X字形
temp = chess[0, 0];
if (temp != 0)
{
if (temp == chess[0, 1] && temp == chess[0, 2])
{
return temp;
}
if (temp == chess[1, 0] && temp == chess[2, 0])
{
return temp;
}
}
//判断是否是第一行或者第一列相同
temp = chess[2, 2];
if (temp != 0)
{
if (temp == chess[2, 0] && temp == chess[2, 1])
{
return temp;
}
if (temp == chess[0, 2] && temp == chess[1, 2])
{
return temp;
}
}
//判断是否是第三行或者第三列相同
if (empty == 0)
{
return 3;//没有空的地方,因此双方平局
}
else
{
return 0;//还未分出胜负
}
}
void Init()
{
empty = 9;
turn = 1;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
chess[i, j] = 0;
}
}