作业2-离散仿真引擎基础

1、简答题

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

区别:游戏对象是代表角色、道具和场景的基本对象。它们本身不能完成很多工作,但它们容纳实现实际功能的组件。

资源是游戏或项目中可以使用的对象,可能来自Unity外部创建的文件,也可能是在Unity中创建的。

相对而言,游戏对象更抽象,而资源更具体。

联系:资源可以被游戏对象使用。

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

下载的游戏文件后缀为unitypackage,导入方法是新建一个project,进入project,点击Assets->Import Package->Custom Package…,选择游戏文件,然后选择需要导入的部分进行导入。

资源的目录组织结构如下。可以从文件夹名称看出,有Editor、Prefabs、Resources、Scenes、Scripts、Sprites、Textures。

图片

游戏对象树的层次结构如下。有Canvas、EventSystem、MainCamera

图片

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

基本行为包括 Awake() Start() Update() FixedUpdate() LateUpdate()

常用事件包括 OnGUI() OnDisable() OnEnable()

基本行为:

Awake:始终在任何 Start 函数之前并在实例化预制件之后调用此函数。

Start:仅当启用脚本实例后,才会在第一次帧更新之前调用。

Update:每帧调用一次 Update。这是用于帧更新的主要函数。

FixedUpdate:调用 FixedUpdate 的频度常常超过 Update。如果帧率很低,可以每帧调用该函数多次;如果帧率很高,可能在帧之间完全不调用该函数。在 FixedUpdate 之后将立即进行所有物理计算和更新。在 FixedUpdate 内应用运动计算时,无需将值乘以 Time.deltaTime。这是因为 FixedUpdate 的调用基于可靠的计时器(独立于帧率)。

LateUpdate:每帧调用一次 LateUpdate__(在 Update__ 完成后)。LateUpdate 开始时,在 Update 中执行的所有计算便已完成。

常用事件:

OnGUI:每帧调用多次以响应 GUI 事件。首先处理布局和重新绘制事件,然后为每个输入事件处理布局和键盘/鼠标事件。

OnDisable:行为被禁用或处于非活动状态时,调用此函数。

OnEnable:在启用对象后立即调用此函数。

代码如下:

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

public class test : MonoBehaviour
{
    void Awake () {
        Debug.Log("Awake");
    }
 
    void Start () {
        Debug.Log("Start");
    }
    
    void Update () {
        Debug.Log("Update");
    }
 
    void FixedUpdate () {
        Debug.Log("FixedUpdate");
    }

    void LateUpdate () {
        Debug.Log("LateUpdate");
    }
 
    void OnGUI () {
        Debug.Log("OnGUI");
    }
 
    void OnDisable () {
        Debug.Log("OnDisable");
    }
 
    void OnEnable () {
        Debug.Log("OnEnable");
    }
}

运行后结果如下图:
图片

·查找脚本手册,了解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对象描述:对象的位置、旋转和缩放。场景中的每个对象都有一个变换。 它用于存储和操作对象的位置、旋转和缩放。 每个变换都可以有一个父级,让你能够分层应用位置、旋转和缩放。这是“Hierarchy”面板中显示的层级视图。 它们还支持枚举器。

Component 对象描述:附加到 GameObject 的所有内容的基本类。注意,代码不会直接创建 Component,而是编写脚本代码,然后将该脚本附加到 GameObject。

table 对象(实体)的属性:activeSelf,isStatic,Layer,Tag,Transform

table 的 Transform 的属性:Position(0,0,0),Rotation(0,0,0),Scale(1,1,1)

table 的部件:Mesh Filter,Box Collider,Mesh Renderer

UML图描述三者关系:

图片

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

预设(Prefabs)有什么好处?

预设与对象克隆 (clone or copy or Instantiate of Unity Object) 关系?

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

预设的好处:可以容易地复用实体集,再次使用实体集时不需要再创建拼接对象。

预设与对象克隆的关系:预设的实例之间是相关的,如果预设改变,实例也会相应改变。对象克隆的实例之间是彼此独立的,更改一个实例,其他实例不会变化。

制作table预制的方法在课程网页有详细描述,将table预制资源实例化成游戏对象的代码如下:

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

public class instantiate: MonoBehaviour
{
    public GameObject table;
    
    void Start () {
        GameObject newinstance = (GameObject)Instantiate(table, transform.position, transform.rotation);
    }

}

2、编程实践,小游戏

·游戏内容:井字棋或贷款计算器或简单计算器等等

·技术限制:仅允许使用IMGUI构建UI

·作业目的:

了解 OnGUI() 事件,提升 debug 能力

提升阅读 API 文档能力

将chess.cs的文件拖进层次结构中的MainCamera,chess.cs的代码如下。点击棋盘可以下棋,结果会显示在右侧,点击reset可以清空棋盘,重新开始游戏。

项目保存在 https://github.com/loudax/3d-game/tree/master/tictactoe

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

public class chess : MonoBehaviour
{
    int turn, counter;
    int[,] board = new int[3, 3];

    // Start is called before the first frame update
    void Start()
    {
        init();        
    }

    void init(){
        turn = 1;
        counter = 0;
        for(int i = 0; i < 3; i++){
            for(int j = 0; j < 3; j++){
                board[i, j] = 0;
            }
        }
    }

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

        if((board[0, 0] == board[1, 1] && board[1, 1] == board[2, 2]) || (board[0, 2] == board[1, 1] && board[1, 1] == board[2, 0])){
            return board[1, 1];
        }

        if(counter == 9){
            return 3;
        }

        return 0;
    }

    void OnGUI(){
        if(GUI.Button(new Rect(220, 100, 100, 50),"Restart")){
            init();
        }

        int result = check();
        if(result == 1){
            GUI.Label(new Rect(220, 50, 100, 50), "Player1 wins!");
        }
        else if(result == 2){
            GUI.Label(new Rect(220, 50, 100, 50), "Player2 wins!");
        }
        else if(result == 3){
            GUI.Label(new Rect(220, 50, 200, 50), "No winner, let's play again.");
        }

        for(int i = 0; i < 3; i++){
            for(int j = 0; j < 3; j++){
                if(board[i, j] == 1){
                    GUI.Button(new Rect(50+i*50, 20+j*50, 50, 50), "O");
                }
                if(board[i, j] == 2){
                    GUI.Button(new Rect(50+i*50, 20+j*50, 50, 50), "X");
                }
                if(GUI.Button(new Rect(50+i*50, 20+j*50, 50, 50), "")){
                    if(result == 0){
                        board[i, j] = turn;
                        counter++;
                        if(turn == 1){
                            turn = 2;
                        }
                        else{
                            turn = 1;
                        }
                    }
                }
            }
        }
    }

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

3、思考题【选做】

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

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

模板方法指的是模板决定算法的步骤,具体的实现是使用接口在子类实现,这种方法可以实现逻辑分离,可以在不改变整体的条件下,对子步骤进行修改。XNA引擎的方法更符合模板方法的描述。

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

尝试解释组合模式(Composite Pattern / 一种设计模式)。

使用 BroadcastMessage() 方法,向子对象发送消息。你能写出 BroadcastMessage() 的伪代码吗?

将相似的对象组合起来成为树型结构,使得可以对这一组对象统一处理。

void BoradcastMessage(string msg){
  foreach child
    child.boradcast(msg);
}

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

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

Decorator模式。使用继承设计特殊的游戏对象会导致数量过多管理困难,并且降低了其灵活性。使用Decorator模式可以灵活地向对象加入部件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值