Unity3D游戏编程——离散仿真作业

2023-10-26

Unity3D游戏编程——离散仿真作业

1.简答题asd

1.1解释游戏对象(GameObjects)和资源(Assets)的区别与联系
答:游戏对象(GameObjects)是一系列资源的组成序列。资源(Assets)是一系列可以被Unity采用的数据文件(如纹理,材质,音频等),只有有了相应的资源,在Unity项目中才能呈现出相应的效果(比如需要木质表面,项目文件中就必须有木质材质的资源文件),有了资源之后,我们便可以在Unity中利用已有的资源来构建我们各种各样的游戏对象了,游戏对象是游戏过程中的基本操作单位。
1.2下载几个游戏案例,分别总结资源,对象组织的结构(指资源的目录组织结构与游戏对象树的层次结构)
答:我在Github选取了游戏《天天萌泡泡》作为游戏案例来进行分析。它的游戏对象树和资源目录结构如下:

在这里插入图片描述

从游戏对象树我们可以看到,该游戏的游戏对象树的底层先分了几个大的GameObject来承担不同方面的工作,然后各个大GameObject又包含小GameObject来分管某方面的细节性工作。

在这里插入图片描述
从资源目录结构我们可以看出,游戏将资源分为动画,音频,字体,图片,插件等方面来分别存储。

1.3编写一个代码,使用debug语句来验证MonoBehaviour基本行为或事件触发的条件,基本行为包括Awake,Start,Update,FixedUpadate,LateUpdate,常用事件包括OnGUI,OnDisable,OnEnable。
答:

代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FirstBeh : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Debug.Log("This Start!");
    }
    void Awake()
    {
        Debug.Log("This Awake!");
    }
    void FixedUpdate()
    {
        Debug.Log("This FixedUpdate!");
    }
    void LateUpdate()
    {
        Debug.Log("This LateUpdate!");
    }
    void OnGUI()
    {
        Debug.Log("This OnGUI!");
    }
    void OnDisable()
    {
        Debug.Log("This OnDisable!");
    }
    // Update is called once per frame
    void Update()
    {
        Debug.Log("This Update!");
    }
    void OnEnable()
    {
        Debug.Log("This Enabled!");
    }
}

代码运行效果如下:

开始:
在这里插入图片描述
运行中:
在这里插入图片描述
结束
在这里插入图片描述

1.4查找脚本手册,了解GameObject,Transform,Component对象。
翻译官方对三个对象的描述:1.GmaeObject是所有Unity场景中的对象的基类。 2.Transform:是一个对象的位置,大小,角度等属性。每个对象都有Transform属性,Transform也有层次组织,以达到相对位置的效果。 3.Component:每个对象都有的基本类,它包括脚本等组件。
描述Table对象(实体)的属性,Table的Transform的属性,Table的组件:

在这里插入图片描述
我们可以看到Inspector中第一栏就是activeSelf属性,它的Transform属性在第二栏,包括了位置(0,0,0)
,旋转(0,0,0),大小(1,1,1),除了activeSelf都是Component,包括transform,mesh render等,还包括我自己加入的脚本。
UML图如下:
在这里插入图片描述

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

查找对象:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SecnodBeh : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        var ob = GameObject.Find("table");
        if (ob != null)
        {
            Debug.Log("Success");
        }
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

在这里插入图片描述
添加子对象:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SecnodBeh : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        GameObject ob = GameObject.CreatePrimitive(PrimitiveType.Cube);
        ob.name = "chair5";
        ob.transform.position = new Vector3(0, 5, 5);
        ob.transform.parent = this.transform;
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

在这里插入图片描述

遍历对象树:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SecnodBeh : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Debug.Log("begin");
        foreach (Transform child in transform)
        {
            Debug.Log(child.name);
        }
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

在这里插入图片描述

清除所有子对象:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SecnodBeh : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        for(int i = 0; i < transform.childCount; i++)
        {
            Destroy(transform.GetChild(i).gameObject);
        }
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

在这里插入图片描述

1.6资源预设与对象克隆:

预设的好处:预设是指对GameObject的一种描述,它可以很方便的生成多个相同的对象,但他们实质上是同一份,有点类似于指针的感觉,预设能够方便我们重复性的创建某些功能形状都一致的对象。

预设与对象克隆的关系:他们的区别类似于C/C++中的深拷贝和浅拷贝,预设的修改会改变所有相关的对象,但是对象克隆产生的各个对象是独立的。

写一段代码将table预设资源实例化为游戏对象:

(GameObject)Instantiate(Resources.Load("table"));

使用这段代码的前提是要先将table预设进资源库中,此处参考了其它博客。

2.编程实践,小游戏

游戏内容:

井字棋

技术限制:

仅允许使用 IMGUI 构建 UI

作业目的:

了解 OnGUI() 事件,提升 debug 能力
提升阅读 API 文档能力

源代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CoreCode : MonoBehaviour
{
    private bool flag = false;
    private int[, ] state = new int[3, 3];
    private int turn = 1;
    private int AI = 0;
    GUIStyle white = new GUIStyle();
    GUIStyle black = new GUIStyle();
    // Start is called before the first frame update
    void Start()
    {
        for(int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                state[i, j] = 0;
            }
        }

        white.normal.background = null;
        white.normal.textColor = new Color(1, 1, 1);
        white.fontSize = 100;

        black.normal.background = null;
        black.normal.textColor = new Color(0, 0, 0);
        black.fontSize = 100;
    }
    void Restart()
    {
        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                state[i, j] = 0;
            }
        }
        turn = 1;
    }
    int check()
    {
        for (int i = 0; i < 3; i++)
        {
            if (state[i, 0] == state[i, 1] && state[i, 1] == state[i, 2] && state[i, 2] != 0)
            {
                return state[i, 0];
            }
        }

        for (int i = 0; i < 3; i++)
        {
            if (state[0, i] == state[1, i] && state[1, i] == state[2, i] && state[2, i] != 0)
            {
                return state[0, i];
            }
        }

        if (state[0, 0] == state[1, 1] && state[1, 1] == state[2, 2] && state[1, 1] != 0)
            return state[1, 1];

        if (state[2, 0] == state[1, 1] && state[1, 1] == state[0, 2] && state[1, 1] != 0)
            return state[1, 1];
        return 0;
    }
    bool kill(int i,int j)
    {
        state[i, j] = turn;
        if (check() != turn)
        {
            state[i, j] = 0;
            return false;
        }
        else
        {
            state[i, j] = 0;
            return true;
        }
    }
    bool defend(int i,int j)
    {
        state[i, j] = 3 - turn;
        if (check() == 3-turn)
        {
            state[i, j] = 0;
            return true;
        }
        else
        {
            state[i, j] = 0;
            return false;
        }
    }
    bool full()
    {
        bool res = true;
        for(int i = 0; i < 3; i++)
        {
            for(int j = 0; j < 3; j++)
            {
                if (state[i, j] == 0)
                    res = false;
            }
        }
        return res;
    }
    void OnGUI()
    {
        for(int i = 0; i < 3; i++)
        {
            for(int j = 0; j < 3; j++)
            {
                if (state[i, j] == 0)
                {
                    if (GUI.Button(new Rect(i * 100, j * 100, 100, 100), ""))
                    {
                        if (check() != 0)
                            break;
                        state[i, j] = turn;
                        turn = 3 - turn;
                        if (AI == 1)
                        {
                            int done = 0;
                            for(int k = 0; k < 3; k++)
                            {
                                for(int p = 0; p < 3; p++)
                                {
                                    if (state[k, p] == 0)
                                    {
                                        if (kill(k, p))
                                        {
                                            state[k, p] = turn;
                                            done = 1;
                                        }
                                        else if (defend(k, p))
                                        {
                                            state[k, p] = turn;
                                            done = 1;
                                        }
                                    }
                                    if (done == 1)
                                        break;
                                }
                                if (done == 1)
                                    break;
                            }
                            if (done == 0)
                            {
                                for(int k = 0; k < 3; k++)
                                {
                                    for(int p = 0; p < 3; p++)
                                    {
                                        if (state[k, p] == 0)
                                        {
                                            state[k, p] = turn;
                                            done = 1;
                                            break;
                                        }
                                    }
                                    if (done == 1)
                                        break;
                                }
                            }
                            turn = 3 - turn;
                        }
                    }
                }
                else if (state[i, j] == 1)
                    GUI.Button(new Rect(i * 100, j * 100, 100, 100), "O", white);
                else if (state[i, j] == 2) 
                    GUI.Button(new Rect(i * 100, j * 100, 100, 100), "X", black);
            }
        }
        if(check()==1)
            GUI.Label(new Rect(150, 300, 200, 200), "Player1 Win");
        else if(check()==2)
            GUI.Label(new Rect(150, 300, 200, 200), "Player2 Win");
        if (GUI.Button(new Rect(350, 200, 100, 100), "Restart"))
            Restart();
        if (AI == 0)
        {
            if (GUI.Button(new Rect(450, 200, 100, 100), "AI ON"))
            {
                AI = 1;
            }
        }
        else
        {
            if (GUI.Button(new Rect(450, 200, 100, 100), "AI OFF"))
            {
                AI = 0;
            }
        }
        if (full())
        {
            GUI.Label(new Rect(150, 300, 200, 200), "Tied");
        }
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

实现效果:

在这里插入图片描述
在这里插入图片描述

思路解析:

利用IMGUI来搭建简单的界面,参考了官方文档和相关博客。游戏思路是设置一个turn变量来记录当前是谁的回合(白圈是玩家一,黑叉是玩家二),如果点击在空格上则产生相应的相应图案,每帧调用检测函数,暴力检测三纵行,三横行和两对角线是否存在三色相同图案,若存在则产生游戏结果,并停止游戏,Restart用来重置游戏。
后面我又增加了AI功能,我的AI的运行逻辑是先攻击再防御,先判断是否能绝杀,若可以则直接下子,否则判断是否下一步会被对方绝杀,若会则下子防守,否则随机选取一块进行下子。井字棋的规则十分简单,我这种AI逻辑能做到把把平局,效果良好。

思考题

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

首先模板方法是给定一个基类模板,然后由程序员去以该模板实现各个具体类,而策略模式则是给定一系列策略,类似于 if else分支,由用户决定运行过程中的处理方式。XNA屏蔽了游戏循环的细节,用一组虚方法去让继承者完成他们,这说明微软XNA是在一个基类模板上进行子类的开发的,而不是开发出各种各样的类然后由用户进行选择。

2.将游戏对象组成树型结构,每个节点都是游戏对象(或数)。尝试解释组合模式(Composite Pattern / 一种设计模式)。使用 BroadcastMessage() 方法,向子对象发送消息。你能写出 BroadcastMessage() 的伪代码吗?
BroadcastMessage(k):
	For any child i of k:
		Inform(i);
		BroadcastMessage(i);
3.一个游戏对象用许多部件描述不同方面的特征。我们设计坦克(Tank)游戏对象不是继承于GameObject对象,而是 GameObject 添加一组行为部件(Component)。这是什么设计模式?为什么不用继承设计特殊的游戏对象?

这是装饰器模式。继承会造成高耦合,导致代码的复杂度上升,而采用组件可以降低耦合,增强内聚。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Unity3D游戏编程——离散仿真作业 的相关文章

  • 逍遥模拟器导出文件到电脑

    1 确保已经成功连接模拟器 如有问题 请查看 https blog csdn net qq 15228737 article details 81142905 2 用cd命令找到要导出的文件夹 文件 再将该文件夹 文件导出到电脑上 如下图
  • React学习--JSX与react事件

    1 JSX 1 1 表达式 在React中使用JSX来描述HTML页面 而且可以与js混合使用 使用JavaScript表达式时要将表达式包含在大括号里 const user firstName Harper lastName Perez
  • 关于虚方法virtual和抽象方法以及多态的研究

    虚方法virtual定义 当类中的方法声明前加上了virtual 修饰符 我们称之为虚方法 反之为非虚 使用了virtual 修饰符后 不允许再有static abstract 或override 修饰符 必须是Public 为了实现多态
  • 御剑WEB指纹识别系统教程,图文教程(超详细)

    作者简介 CSDN top100 阿里云博客专家 华为云享专家 网络安全领域优质创作者 推荐专栏 对网络安全感兴趣的小伙伴可以关注专栏 网络安全入门到精通 御剑WEB指纹识别 一 基本使用 二 内置字典 三 自定义字典 四 扫描原理 御剑W
  • Content-Type 属性值

    数据请求headers常见的Content Type值 Content Type 属性值众多 每个值都有其特定的作用和使用场景 下面是一些常见的 Content Type 值和对应的作用 Content Type application x
  • 算法-宽度优先搜索

    算法 宽度优先搜索 一 宽度优先搜索 广度优先或横向优先搜索 是一种图形搜索算法 简单的说 BFS是从根节点开始 沿着树的宽度遍历树的节点 如果所有节点均被访问 则算法中止 DFS Depth First Search 深度优先搜索 对每一
  • 解决Mac版微信小程序开发工具打开后无法显示二维码

    问题描述 正常情况下 打开微信小程序开发工具后 首页提示扫描二维码进行登陆 但是如果不显示二维码 当然无法登陆 解决方案 无法显示二维码肯定是程序运行哪里出错了 我们直接点击桌面图标是无法排查错误 所以需要切换至命令行进行启动 打开命令行
  • 华为交换机开局配置

    sysname SWITCH aaa undo local aaa user password policy administrator local user admin password irreversible cipher admin
  • 四、无人机知识笔记(初级:基本运动原理)

    笔记来源于 沈阳无距科技 工业级无人机的中国名片 编程外星人 目录 一 多旋翼直升机 二 基本飞行姿态 三 多旋翼飞行原理 四 反扭力与偏航运动 五 螺旋桨 六 有刷电机和无刷电机 七 电调与PWM信号 八 动力电池 九 遥控器 十 机架设
  • C++ ——STL(上)

    前言 STL基本概念 1 STL Standard Template Library 标准模板库 2 STL从广义上分为 容器 container 算法 algorithm 迭代器 iterator 3 容器和算法之间通过迭代器进行无缝连接
  • SQL注入***

    SQL注入 是 对数据库进行 的常用手段之一 随着B S模式应用开发的发展 使用这种模式编写应用程序的程序员也越来越多 但是由于程序员的水平及经验也参差不齐 相当大一部分程序员在编写代码的时候 没有对用户输入数据的合法性进行判断 使应用程序
  • npm 安装卸载模块 & ionic插件安装与卸载

    npm安装模块 npm install xxx利用 npm 安装xxx模块到当前命令行所在目录 npm install g xxx利用npm安装全局模块xxx 本地安装时将模块写入package json中 npm install xxx
  • 用回车键实现MFC对话框中TAB键控制输入焦点在控件中跳转的效果

    用回车键实现MFC对话框中TAB键控制输入焦点在控件中跳转的效果 以下转载自 http blog csdn net ghgk archive 2004 10 20 144795 aspx 近日在为一个数据应用写数据输入界面 大量的编辑框要想
  • maven本地仓库批量上传私服

    最近做项目遇到一个问题 从别的地方拿过来的工程是用maven构建的 而且用了许多自有的依赖包 如果一个个的上传到私服简直是浪费时间 于是用Python 写了一个批量上传的工具 简化自己的工作量 使用的是Python3 分别依赖了os sub
  • Run-Time Check Failure #2 - Stack around the variable ‘password(数组名)‘ was corrupted.

    记录一些小小的bug 使用visaul 2019编辑c语言程序 程序可以正常运行 但程序结束退出时忽然报错闪退 原来是我定义password 数组时没有规定数组大小 导致栈溢出 正确的做法只要给数组规定一个大小就行了 以下讲解来自chatg
  • 芯片的英文手册需要全部看吗?

    以下文章来源于 公 众 号开源电子网 读取更多技术文章 请扫码关注 芯片的英文手册需要全部看吗 进入嵌入式行业的人都知道 必定和英文手册打交道的 例如使用一款PHY芯片设置电路 那么首要任务就是查找该PHY芯片的手册以及相关资料 这些资料呢
  • 用房屋建筑方式理解软件构建

    如果你是在建一栋房子 那么这个建造过程就会复杂得多 而糟糕的设计所引发的后果也更严重 首先你要决定准备建一个什么类型的房子 在软件开发里的类似事项称为问题定义 problem definition 接下来 你必须和某个建筑师 archite
  • java代码规范(转载整合)

    1 标识符命名规范 1 1 概述 标识符的命名力求做到统一 达意和简洁 1 1 1 统一 统一是指 对于同一个概念 在程序中用同一种表示方法 比如对于供应商 既可以用supplier 也可以用provider 但是我们只能选定一个使用 至少
  • 数据库文件被.eight后缀勒索病毒加密?不要惊慌,91数据恢复专家教您应对处理!

    当企业遭受勒索病毒攻击时 数据库文件被加密 这会导致企业无法访问其重要的业务数据 会给企业带来较大的困扰 本篇文章 91数据恢复专家将会针对 tsai shen zohomail eu eight勒索病毒 介绍如何恢复被 tsai shen
  • keras部分介绍

    1 keras 关于batch normalization函数参数axis 3的解释 https www zhihu com question 318398221 tips BN层的作用 1 加速收敛 2 控制过拟合 可以少用或不用Drop

随机推荐

  • 2023年面试问答-二分查找

    正常实现 Input 1 2 3 4 5 key 3 return the index 2 public int binarySearch int nums int key int l 0 h nums length 1 while l l
  • 一键端2

    新仙剑ol 链接 http pan baidu com s 1i3xZHLb 密码 hyly 链接 http pan baidu com s 1c0HgGKw 密码 druj 本帖隐藏的内容 龙之谷133服务端 链接 http pan ba
  • 索琦c语言程序设计第二版第七章,C语言程序设计自学考试大纲(2000年7月版).doc...

    天津市高等教育自学考试课程考试大纲 课程名称 应用程序基础及设计 课程代码 1115 4874 第一部分 课程性质与设置目的 一 课程性质与特点 应用程序基础及设计 课程是高等教育自学考试电子信息工程专业的必修课 是该专业一门重要的基础课
  • Qt实现TCP客户端和服务器通讯程序

    复习的心态过一遍之前基础的一些东西 Qt封装了QTcpServer和QTcpSocket两个类 其中QTcpServer继承自QObject 通过listen 函数监听传入的客户端连接 当Client连接上时 QTcpServer会发出ne
  • 使 QComboBox 下拉一个带复选框的树形列表

    背景 在项目开发过程中需要使 QComboBox 下拉一个树形列表 直接通过 setModel 和 setView 设置 combox 控件可以实现 但是在单击节点箭头按钮时也会隐藏下拉框的显示 因此需要重新实现 QComboBox 的方法
  • 解决vue 路由传参 页面刷新或者后退参数丢失的问题

    vue路由传递参数如果用params传递参数 那么页面刷新就会丢失数据 可以改用query来传递参数 这样刷新就不会丢失 this router push path business bizInspectionTaskSub query f
  • Db2 v11.1 Upgrade to V11.5 HADR 模式

    https www ibm com docs en db2 11 5 topic methods universal versus product specific fix packs Universal versus product sp
  • RocketMQ重置消费位点源码分析

    这里是weihubeats 觉得文章不错可以关注公众号小奏技术 文章首发 拒绝营销号 拒绝标题党 背景 最近在使用RocketMQ的重置消费位点的时候经常出现报错 所以就打算研究下RocketMQ是如何重置消费者的消费位点的 RocketM
  • 图像形态学处理(膨胀腐蚀开闭运算)——数字图像处理学习八(C++版)

    一 基本概念 1 形态学的基本思想是利用一种特殊的结构元来测量或提取输入图像中相应的形状或特征 以便进一步进行图像分析和目标识别 2 图像的形态学处理是对二值图像进行处理 所以在形态学处理前需要将图像二值化 3 结构元可以是任意形状 结构元
  • 可信执行环境(TEE)技术介绍(Trusted Execution Environment)

    本文对当前流行的移动终端TEE技术做简要概述 并对一些细节展开讨论 1 当前移动安全背景 当前移动终端面临这严重的安全威胁 威胁点如下图所示 因此移动厂商 用户 服务提供商等各方都对移动安全提出了强烈的需求 2 REE介绍 Rich Exe
  • 线程安全

    线程安全 多线程的执行顺序不可重现 但是必须要求执行结果必须可以重现 线程的共享数据操作不完整性就一定会出现数据被破坏 而导致结果无法预知的问题 线程的安全问题 同步处理的引入 在java语言中存在两种内建的synchronized语法 s
  • ng-model

    ng model指令用来将input select text area或自定义表单控件同包含它们的作用域中的属性进行绑定 它可以提供并处理表单验证功能 在元素上设置相关的CSS类 ng valid ng invalid等 并负责在父表单中注
  • 【解决】2021-07-30Caused by: com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException:

    Caused by org springframework beans factory BeanCreationException Error creating bean with name sqlTemplate defined in U
  • python实现向图像随机添加高斯白噪声,并修改尺寸

    基于python向图像随机添加高斯噪声 并修改尺寸 噪声分布设置为 均值为0 方差分布在0 50之间 coding utf 8 Created on Nov Mon 29 14 09 45 2021 author 瀛台夜雪 import o
  • 【opencv】基于opencv实现人脸识别,从环境搭建到代码实现(超详细教程)

    前言 目标 让计算机通过训练做到认识我或者检测出视频中的人是谁 本文是一个学习笔记 记录一下自己的实现过程 在实现过程中遇到的问题以及个人对知识的理解 一 环境配置 1 软件安装 首先先安装一下必须的软件 python pycharm op
  • 通俗易懂的java设计模式(6)-代理模式

    1 什么是代理模式 为某个对象提供一个代理对象 通过这个代理对象 可以控制对原对象的访问 通俗的解释 我们电脑桌面上的一个个快接方式 当我们点击这个快捷方式的时候 我们就间接地访问到了这个程序 2 静态代理 何为静态 即在程序运行之前 代理
  • java后端解决重复提交问题

    一 为什么会出现重复提交 主要是由于网络的延迟问题以及页面刷新的操作 二 表单的重复提交会导致的问题 主要能够造成很多脏数据 三 解决的办法 3 1 前端解决办法 通过前端的方法将提交按钮变灰 对于前端的办法这里就不做演示了 因为前端的控制
  • C++11标准中按值传递类对象参数的使用时机

    严正声明 本文系作者davidhopper原创 未经许可 不得转载 作为一名资深C 程序员 在C 98 03标准时代 一直将 不得按值传递类对象参数 的规定奉为圭臬 例如 void SetParam const std string nam
  • 自定义实现Java ListNode链表

    写在前面 今天写代码的时候 发现我居然被Java的ListNode的输入卡了半天 所以就打算写一篇博客来整理一下ListNode 链表的定义 首先ListNode就是链表 它的基本结构如下 及一个包含数据 和指针的结构 我们将一个节点的指针
  • Unity3D游戏编程——离散仿真作业

    Unity3D游戏编程 离散仿真作业 1 简答题asd 1 1解释游戏对象 GameObjects 和资源 Assets 的区别与联系 答 游戏对象 GameObjects 是一系列资源的组成序列 资源 Assets 是一系列可以被Unit