热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

3D游戏编程与设计离散仿真引擎基础作业

简答题1.解释游戏

简答题

1.

解释 游戏对象(GameObjects) 和 资源(Assets)的区别与联系。

GameObject 是运行时在场景中被渲染的实体对象。而 Asset 是游戏的资源,包括预设、图片、脚本、场景等静态文件。
游戏的 GameObject 是游戏资源的载体,GameObject 由预设产生,可以算是预设的实例;GameObject 还可以添加组件,挂载脚本,此时挂载的脚本还可以绑定现有的材质。也就是说,其实 GameObject 就是游戏资源的组装成品以及设置。
特别的,GameObject 也可以产生 Prefab,Prefab 可以产生 GameObject。

2.

下载几个游戏案例,分别总结资源、对象组织的结构(指资源的目录组织结构与游戏对象树的层次结构)

3.

编写一个代码,使用 debug 语句来验证 MonoBehaviour 基本行为或事件触发的条件

  • 基本行为包括 Awake() Start() Update() FixedUpdate() LateUpdate()
  • 常用事件包括 OnGUI() OnDisable() OnEnable()
    添加脚本 TestScript 并挂载到 Directional Light 上:

using UnityEngine;
public class TestScript : MonoBehaviour
{
void Awake()
{
Debug.Log("Awake");
}
void Start()
{
Debug.Log("Start");
}
void FixedUpdate()
{
Debug.Log("FixedUpdate");
}
void Update()
{
Debug.Log("Update");
}
void LateUpdate()
{
Debug.Log("LateUpdate");
}
void OnGUI()
{
Debug.Log("OnGUI");
}
void OnEnable()
{
Debug.Log("OnEnable");
}
void OnDisable()
{
Debug.Log("OnDisable");
}
void OnDestroy()
{
Debug.Log("OnDestroy");
}
}

运行后可以看到如下输出:发现调用顺序为 AwakeOnEnableStartUpdateLateUpdateOnGUIOnDisableOnDestroy
在这里插入图片描述
点击停止按钮后的日志如下:
在这里插入图片描述
可以看到和官方网站提供的 MonoBehaviour 的生命周期一致:
在这里插入图片描述

4.

查找脚本手册,了解 GameObject,Transform,Component 对象

  • 分别翻译官方对三个对象的描述(Description)
  • 描述下图中 table 对象(实体)的属性、table 的 Transform 的属性、 table 的部件
    • 本题目要求是把可视化图形编程界面与 Unity API 对应起来,当你在 Inspector 面板上每一个内容,应该知道对应 API。
    • 例如:table 的对象是 GameObject,第一个选择框是 activeSelf 属性。
  • 用 UML 图描述 三者的关系(请使用 UMLet 14.1.1 stand-alone版本出图)

GameObject

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.
Class GameObject is the base class for all entities in Unity Scenes.

也就是说 GameObject 是 Unity 中表示游戏玩家、场景、物品的基础对象。GameObject 是 Prefab 的实例,GameObject 还是 Component 的容器,一个 GameObject 上可以挂载多个 Component 定制 GameObject 的行为。

Transform

The Transform component determines the Position, Rotation, and Scale of each object in the scene. Every GameObject has a Transform.

表示 GameObject 的位置、方向、缩放。

Component

Components are the nuts & bolts of objects and behaviors in a game. They are the functional pieces of every GameObject. If you don’t yet understand the relationship between Components and GameObjects, read the GameObjects page before going any further.

Component 是描述 GameObject 行为的对象,负责控制 GameObject 的生命周期以及行为,一个 GameObject 上可以有多个 Component。

5.

整理相关学习资料,编写简单代码验证以下技术的实现:

  • 查找对象
  • 添加子对象
  • 遍历对象树
  • 清除所有子对象

查找对象

// Finds a GameObject by name and returns it.
public static GameObject Find(string name);
// Returns a list of active GameObjects tagged tag. Returns empty array if no GameObject was found.
// 参数:
// tag:
// The name of the tag to search GameObjects for.
public static GameObject[] FindGameObjectsWithTag(string tag);
public static GameObject FindGameObjectWithTag(string tag);
// Returns one active GameObject tagged tag. Returns null if no GameObject was found.
// 参数:
// tag:
// The tag to search for.
public static GameObject FindWithTag(string tag);

验证:

// SceneBehaviour,这个脚本绑定在了场景中的某一个对象上
void Start()
{
GameObject table = GameObject.Find("Table");
Debug.Log(table.GetHashCode());
}
// TableBehaviour,这个脚本绑定在了 Table 对象上
void Start()
{
Debug.Log(gameObject.GetHashCode());
}

可以看到两次的输出是一致的,说明找到了同一个对象。
注:C# 默认的 GetHashCode() 函数返回的是对象的地址,可以反映是否是同一个对象。
在这里插入图片描述

添加子对象

void Start()
{
GameObjecttable = GameObject.Find("Table");
GameObject chair5 = GameObject.CreatePrimitive(PrimitiveType.Cube);
chair5.name = "Chair5";
chair5.transform.position = new Vector3(0, 2, 0);
chair5.transform.localScale = new Vector3(1, 0.2f, 1);
chair5.transform.parent = table.transform;
}

可以看到新创建了一个方块:
在这里插入图片描述

遍历对象树

void Traverse(Transform transform)
{
foreach (Transform child in transform)
{
Debug.Log(child.name);
Traverse(child);
}
}

清除所有子对象

foreach (Transform child in parent.transform)
{
Destroy(child.gameObject);
}

6.

资源预设(Prefabs)与 对象克隆 (clone)

  • 预设(Prefabs)有什么好处?
  • 预设与对象克隆 (clone or copy or Instantiate of Unity Object) 关系?
  • 制作 table 预制,写一段代码将 table 预制资源实例化成游戏对象

预设有什么好处?

可以复用相似的游戏对象,减少建模的复杂度。而且复用可以使得批量更改所有的游戏对象。

预设与对象克隆关系?

预设的修改会影响相关的所有游戏对象。但对象克隆后两者其实没有关系,修改其中一个不会影响另一个。

写一段代码将 table 预制资源实例化成游戏对象

编程实践,小游戏

游戏内容: 井字棋 或 贷款计算器 或 简单计算器 等等
技术限制: 仅允许使用 IMGUI 构建 UI
作业目的:提升 debug 能力提升阅读 API 文档能力

游戏截图

在这里插入图片描述

游戏实现

UML 结构图

在这里插入图片描述

GuiComponent

GuiComponent 为所有 2D 元素的基类,因此按钮、计时器、数字显示屏、棋盘都是 GuiComponent 的派生类。

游戏全部使用 IMGUI 构建,由于 IMGUI 过于原始,我们需要自己封装 Gui 类来帮助我们完成工作。

GuiComponent 本身使用了组合模式,每个 GuiComponent 有自己的孩子,每个孩子的定位相对于父组件定位,最后组件形成了组件树。

GuiTileBoard

GuiTile 为棋盘的每一个方块,并维护方块当前状态是未被揭开、已经揭开、插旗等。还负责自己的点击事件的处理。

GuiTileBoard 实现了游戏的逻辑,负责计算当前局面是胜利还是失败。GuiTileBoard 每次都会查询所有的 GuiTile 并维护当前局面形势。

思考题

1

微软 XNA 引擎的 Game 对象屏蔽了游戏循环的细节,并使用一组虚方法让继承者完成它们,我们称这种设计为“模板方法模式”。

  • 为什么是“模板方法”模式而不是“策略模式”呢?

模板方法模式:通过基类定义算法流程,并将算法的实现细节步骤通过抽象方法的方式要求子类实现补全算法。强调补全算法细节,以及强调原本算法本身的结构以及执行流程。
策略模式:允许运行时修改对象行为。强调修改的行为本身的独立性。
此处游戏循环本身是一个算法流程,强调了先初始化,再循环,最后退出的算法流程,我们的任务是补全该算法,实现特定的程序。而这些流程之间是有联系的,是整个算法不可分割的一部分。因此强调行为独立性的策略模式在此不适用。

2

将游戏对象组成树型结构,每个节点都是游戏对象(或数)。

  • 尝试解释组合模式(Composite Pattern / 一种设计模式)。
  • 使用 BroadcastMessage() 方法,向子对象发送消息。你能写出 BroadcastMessage() 的伪代码吗?

组合模式

组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。

BroadcastMessage

我们为 Table 添加 TableScript 如下:

public class TableScript : MonoBehaviour
{
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
BroadcastMessage("SayHello");
}
}
}

Chair 添加 ChairScript 如下:

public class ChairScript : MonoBehaviour
{
void SayHello()
{
Debug.Log("Hello! " + transform.position.x + " " + transform.position.y + " " + transform.position.z);
}
}

运行后点击鼠标可以发现 4 个 chair 对象的坐标都已经被打印出来了。
在这里插入图片描述

自己实现 BroadcastMessage

为了实现 BroadcastMessage,并支持调用相应的重载方法,我们需要遍历所有的函数,并且确保相应函数可以被调用:

public class TableScript : MonoBehaviour
{
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
MyBroadcastMessage("SayHello", this);
MyBroadcastMessage("SayHello", 123);
}
}
public void MyBroadcastMessage(string methodName, params object[] parameters)
{
foreach (Transform child in this.transform)
{
foreach (MonoBehaviour behaviour in child.gameObject.GetComponents<MonoBehaviour>())
{
foreach (var method in behaviour.GetType().GetMethods(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public))
{
if (method.Name == methodName && method.GetParameters().Length == parameters.Length)
{
bool ok = true;
for (int i = 0; i < parameters.Length; ++i)
{
if (!method.GetParameters()[i].ParameterType.IsAssignableFrom(parameters[i].GetType()))
{
ok = false;
break;
}
}
if (ok)
{
method.Invoke(behaviour, parameters);
}
}
}
}
}
}
}

运行之后可以看到两个 SayHello 函数都能被正常调用
在这里插入图片描述

3

一个游戏对象用许多部件描述不同方面的特征。我们设计坦克(Tank)游戏对象不是继承于GameObject对象,而是 GameObject 添加一组行为部件(Component)。

  • 这是什么设计模式?
  • 为什么不用继承设计特殊的游戏对象?

这是什么设计模式?

我认为这合用了模板模式策略模式
其中,Componet 本身使用了模板模式,是完成对象的游戏循环算法的类型,此外,游戏对象本身可以挂载多个 Component,这表明,游戏对象本身使用了策略模式,允许通过 Component 修改 GameObject 本身的行为。

为什么不用继承设计特殊的游戏对象?

  1. Delegation 允许动态修改游戏对象行为,而继承不允许,因此继承的灵活性差
  2. Delegation 性能比继承好
  3. Delegation 允许组合,而继承不能

版权声明:本文为huanghongxun原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/huanghongxun/article/details/100566472
推荐阅读
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了如何使用PHP向系统日历中添加事件的方法,通过使用PHP技术可以实现自动添加事件的功能,从而实现全局通知系统和迅速记录工具的自动化。同时还提到了系统exchange自带的日历具有同步感的特点,以及使用web技术实现自动添加事件的优势。 ... [详细]
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • Python如何调用类里面的方法
    本文介绍了在Python中调用同一个类中的方法需要加上self参数,并且规范写法要求每个函数的第一个参数都为self。同时还介绍了如何调用另一个类中的方法。详细内容请阅读剩余部分。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
author-avatar
我爱你2602912303
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有