2018-03-24 10:04:01 happy990 阅读数 117

##解释 游戏对象(GameObjects) 和 资源(Assets)的区别与联系。
游戏对象是unity中表示角色,道具和场景的基本对象。他们本身不能达到什么,但他们作为组件的容器实现真正的功能。
资源:资源可以被一个或多个对象使用。有些资源作为模板,可实例化成游戏中具体的对象。
##资源、对象组织的结构
游戏对象是父类和子类的关系。
资源文件夹通常有对象、材质、场景、声音、预设、贴图、脚本、动作,在这些文件夹下可以继续划分。
##编写一个代码,使用 debug 语句来验证 MonoBehaviour 基本行为或事件触发的条件

void Awake() {
    Debug.Log ("onAwake");
}
void Start () {
    Debug.Log ("onStart");
}

void Update () {
    Debug.Log ("onUpdate");
}
void FixedUpdate() {
    Debug.Log ("onFixedUpdate");
}
void LateUpdate() {
    Debug.Log ("onLateUpdate");
}
void OnGUI() {
    Debug.Log ("onGUI");
}
void Reset() {
    Debug.Log ("onReset");
}
void OnDisable() {
    Debug.Log ("onDisable");
}
void OnDestroy() {
    Debug.Log ("onDestroy");
}

result

##查找脚本手册,了解 GameObject,Transform,Component 对象
游戏对象是unity中表示角色,道具和场景的基本对象。他们本身不能达到什么,但他们作为组件的容器实现真正的功能。
Transform组件决定了场景中每一个对象的位置,旋转和缩放。每一个游戏对象都有一个transform。
component是任何与gameobject相关的东西的基类。
table的对象是GameObject,属性有activeInHierarchy, activeSelf, isStatic, layer, scene, tag, transform.
Component有Cube, Box Collider, Mesh Renderer.
UML

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

  • 查找对象
    1.通过名字查找:public static GameObject Find(string name)
    2.通过标签查找单个对象:public static GameObject FindWithTag(string tag)
    3.通过标签查找多个对象:public static GameObject[] FindGameObjectsWithTag(string tag)
  • 添加子对象: public static GameObect CreatePrimitive(PrimitiveTypetype)
  • 遍历对象树:foreach (Transform child in transform) {};
  • 清除所有子对象: foreach (Transform child in transform) { Destroy(child.gameObject);}

##资源预设(Prefabs)与 对象克隆 (clone)
预设 (Prefab) 是一种资源 - 存储在工程视图 (Project View) 中可重复使用的游戏对象 (GameObject)。预设 (Prefabs) 可放入到多个场景中,且每个场景可使用多次。向场景添加一个预设 (Prefab) 时,就会创建它的一个实例。
所有预设 (Prefab) 实例都链接到原始预设 (Prefab),实质上是原始预设的克隆。不管您的工程中有多少个实例,您对预设 (Prefab) 作薄出任何更改时,您会看到这些更改应用于所有实例。而对象克隆本体和克隆出的对象是不相影响的。

GameObject anotherTable=(GameObject)Instantiate(table.gameObject);

##尝试解释组合模式(Composite Pattern / 一种设计模式)。使用 BroadcastMessage() 方法向子对象发送消息

组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。组合模式是将对象组合成树形结构以表示“部分-整体”的层次结构,它使得用户对单个对象和组合对象的使用具有一致性。

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour {
    void ApplyDamage(float damage) {
        print(damage);
    }
    void Example() {
        BroadcastMessage("ApplyDamage", 5.0F);
    }
}
2018-03-27 22:04:30 Runner1st 阅读数 404

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

  • 游戏对象:出现在游戏场景中的实体,是一些资源的集合体,是资源整合的具体表现。
  • 资源:资源可以被多个对象利用,成为组件中的属性或者行为;还可以将游戏对象预设成资源,当做模板重复使用。

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

  • 资源:一般包括脚本,声音,图像,预设,场景,材质等,在这些文件夹下可以继续划分
  • 游戏对象:一般包括玩家,敌人,环境,摄像机等虚拟父类,这些父类本身为空对象,但他们的子类包含了游戏中出现的对象。

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

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

public class NewBehaviourScript : MonoBehaviour {

	void Awake () {
		Debug.Log ("onAwake");
	}
	// Use this for initialization
	void Start () {
		Debug.Log("onStart");
	}
	
	// Update is called once per frame
	void Update () {
		Debug.Log("onUpdate");
	}

	void FixedUpdate(){
		Debug.Log ("onFixedUpdate");
	}

	void LateUpdate(){
		Debug.Log ("onLateUpdate");
	}

	void OnGUI(){
		Debug.Log ("onGUI");
	}

	void OnDisable(){
		Debug.Log ("onDisable");
	}

	void OnEnable(){
		Debug.Log ("onEnable");
	}
}

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

  • 分别翻译官方对三个对象的描述(Description)

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.

翻译:游戏对象是Unity中表示游戏角色,游戏道具和游戏场景的基本对象。它们自身无法完成许多功能,但是它们充当了那些给予他们实体功能的组件的容器。

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

翻译: 转换组件决定了游戏场景中每个游戏对象的位置,旋转度和大小。每个游戏对象都有转换组件。

Component :Components are the nuts & bolts of objects and behaviors in a game. They are the functional pieces of every GameObject.

翻译: 组件是游戏中对象和行为的细节。它是每个游戏对象的功能部分。


  • 描述下图中 table 对象(实体)的属性、table 的 Transform 的属性、 table 的部件

本题目要求是把可视化图形编程界面与 Unity API 对应起来,当你在 Inspector 面板上每一个内容,应该知道对应 API。

例如:table 的对象是 GameObject,第一个选择框是 activeSelf 属性。

答:table对象的属性:activeInHierarchy(表示GameObject是否在场景中处于active状态)、activeSelf(GameObject的本地活动状态)、isStatic(仅编辑器API,指定游戏对象是否为静态)、layer(游戏对象所在的图层。图层的范围为[0 … 31])、scene(游戏对象所属的场景)、tag(游戏对象的标签)、transform(附加到这个GameObject的转换)

table的Transform的属性:Position、Rotation、Scale,从文档中可以了解更多关于Transform的属性

table的部件有:Mesh Filter、Box Collider、Mesh Renderer

  • 用 UML 图描述 三者的关系(请使用 UMLet 14.1.1 stand-alone版本出图)

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

  • 查找对象
//通过名字查找:
public static GameObject Find(string name)  
//通过标签查找单个对象:
public static GameObject FindWithTag(string tag)  
//通过标签查找多个对象:
public static GameObject[] FindGameObjectsWithTag(string tag)  
  • 添加子对象
public static GameObject CreatePrimitive(PrimitiveTypetype)  
  • 遍历对象树
foreach (Transform child in transform) {  
    Debug.Log(child.gameObject.name);  
}  
  • 清除所有子对象
foreach (Transform child in transform) {  
    Destroy(child.gameObject);  
} 

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

  • 预设(Prefabs)有什么好处?

预设相当于一个对象的模板,当某个对象需要重复出现时,用预设可以提高效率,方便管理。预设使得修改的复杂度降低,一旦需要修改所有相同属性的对象,只需要修改预设即可,所有通过预设实例化的对象都会做出相应变化。


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

修改预设会使通过预设实例化的所有对象都做出相应变化,而对象克隆本体和克隆出的对象是不相影响的。


  • 制作 table 预制,写一段代码将 table 预制资源实例化成游戏对象
    void Start () {  
        GameObject anotherTable = (GameObject)Instantiate(table.gameObject);  
    } 

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

将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。组合模式实现的最关键的地方是——简单对象和复合对象必须实现相同的接口,这就是组合模式能够将组合对象和简单对象进行一致处理的原因。


  • 使用 BroadcastMessage() 方法向子对象发送消息

    父对象方法:

public class NewBehaviourScript : MonoBehaviour {
    void message() {
        Debug.Log("HelloWorld!");
    }
    void Start () {
        this.BroadcastMessage("message");
    }
}

    子对象方法:

public class NewBehaviourScript1 : MonoBehaviour {
    void message() {
        Debug.Log("HelloWorld!");
    }
}

2018-03-25 01:10:37 Z_J_Q_ 阅读数 632

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

游戏对象是出现在场景中的所有物体。
资源是项目中的素材,包括图像、视频、脚本文件、预制文件等。

联系:
游戏对象可保存为资源,资源可以作为组件或整个游戏对象创建游戏对象实例。

资源、对象组织的结构(资源的目录组织结构与游戏对象树的层次结构)

资源通过文件夹的形式来组织,可按照文件类型分类放到不同的文件夹。
案例中资源下包含两个文件夹,code文件夹存放脚本文件,GameObject文件夹存放一个制作好的游戏对象。
这里写图片描述
这里写图片描述
游戏对象通过整体-部分的关系构成层次结构。
案例中游戏对象包含摄像机、灯光和table对象,table下包含4个chair对象组成桌椅套件。
这里写图片描述

验证 MonoBehaviour 基本行为或事件触发的条件

MonoBehaviour是每一个脚本对象的基类,它有一些方法可以覆盖,这些方法会在运行的特定时间被调用

  • 基本行为包括 Awake() Start() Update() FixedUpdate() LateUpdate()
  • 常用事件包括 OnGUI() OnDisable() OnEnable()
  • 行为和事件的区别:行为由游戏引擎调用,事件由游戏对象或系统状态触发

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class table : MonoBehaviour {
    
        void Awake () {
            Debug.Log ("Table Awake");
        }
    
        void Start () {
            Debug.Log ("Table Start");
        }
    
        void Update () {
            Debug.Log ("Table Update");
        }
    
        void FixedUpdate () {
            Debug.Log ("Table FixedUpdate");
        }
    
        void LateUpdate () {
            Debug.Log ("Table LateUpdate");
        }
    
        void OnGUI () {
            Debug.Log ("Table OnGUI");
        }
    
        void OnEnable () {
            Debug.Log ("Table OnEnable");
        }
    
        void OnDisable () {
            Debug.Log ("Table OnDisable");
        }
    
        void OnDestroy () {
            Debug.Log ("Table OnDestroy");
        }
    
    }
    
  • 启动
    这里写图片描述

  • 每一帧
    这里写图片描述

  • 结束
    这里写图片描述

  • 执行顺序

这里写图片描述

GameObjectTransformComponent

  • GameObject: 场景中所有实体的基类
  • Transform: 对象的位置、旋转(角度)和大小
    这里写图片描述
  • Component: GameObject所有附加物的基类
    这里写图片描述
    案例中table对象是GameObject

    把可视化图形编程界面与 Unity API 对应起来
    这里写图片描述
    点击该按钮,打开Manual文档
    这里写图片描述
    点击切换到对应的Unity API

    右侧Inspector面板上依次为:

  • 用 UML 图描述三者的关系

这里写图片描述

验证以下技术:

  • 查找对象 GameObject.Find

    GameObject table, chair1;
    table = GameObject.Find("table");
    Debug.Log (table.name);
    table = GameObject.Find("/table");
    Debug.Log (table.name);
    chair1 = GameObject.Find("chair1");
    Debug.Log (chair1.name);
    chair1 = GameObject.Find("/table/chair1");
    Debug.Log (chair1.name);
    

    这里写图片描述

  • 添加子对象

    public GameObject prefab;
    void Start () {
        GameObject container = GameObject.Find("Container");
        GameObject prefabInstance = Instantiate(prefab);
        prefabInstance.transform.parent = container.transform;
    }

    这里写图片描述
    运行前将对象拖进来

  • 遍历对象树

    直接子对象

    void Example() {
        foreach (Transform child in transform) {
            child.position += Vector3.up * 10.0F;
        }
    }

    所有子对象

    void Example() {
        Recursive(gameObject);
    }
    
    private void Recursive(GameObject parentGameObject){
        //Do something you want
        //......
        foreach (Transform child in parentGameObject.transform){
            Recursive(child.gameObject);
        }
    }
  • 清除所有子对象

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

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

  • Prefabs(预设)是一种可被重复使用的游戏对象,具有以下特点:

    1. 它可以被置入多个场景中,也可以在一个场景中多次置入。
    2. 当你在一个场景中增加一个Prefabs,你就实例化了一个Prefabs。
    3. 所有Prefabs实例都是Prefab的克隆,所以如果实在运行中生成对象会有(Clone)的标记。
    4. 只要Prefabs原型发生改变,所有的Prefabs实例都会产生变化。
  • 预设与对象克隆 (clone or copy or Instantiate of Unity Object) 关系

    预设与克隆都能创建出相同的对象。预设创建出的对象与源预设依然有联系,后者的更改会影响到前者。但是克隆出的对象与源对象不再有联系。

  • 制作 table 预制,将 table 预制资源实例化成游戏对象

    先在Asset目录下创建一个名为Resources的文件夹,这个命名是U3D规定的方式,然后把table放进Resources文件夹。

    GameObject newTable = Instantiate(Resources.Load ("table") as GameObject);
    newTable.transform.parent = this.transform;

组合模式(Composite Pattern)

组合模式将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性,像修改配置文件一样简单的完成本来需要流程控制语句来完成的功能。

  • 使用 BroadcastMessage() 方法向子对象发送消息

    父对象

    void res(){
        Debug.Log (this.gameObject.name);
    }
    void Start () {
        this.BroadcastMessage ("res");
    }

    子对象

    void res(){
        Debug.Log (this.gameObject.name);
    }

    这里写图片描述

小游戏

  • 游戏内容: 井字棋
  • 技术限制: 使用 IMGUI 构建 UI
  • 实践目的:
    • 提升 debug 能力
    • 提升阅读 API 文档能力

《IMGUI小游戏(井子棋)》

参考资料

https://www.jianshu.com/p/c987b9259896
http://gad.qq.com/content/coursedetail/5562
https://blog.csdn.net/u010145745/article/details/39160141
https://blog.csdn.net/yy763496668/article/details/51576694
https://www.cnblogs.com/wangchengfeng/p/3664895.html
https://blog.csdn.net/jukaiblog/article/details/10088021
https://blog.csdn.net/alayeshi/article/details/51093624

2019-09-11 18:39:49 Jundesky 阅读数 72


1. 简答题

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

游戏对象(GameObject)是Unity场景里面所有实体的基类.,可以用来创建对象实例,使用者可以在Inspector界面调整对象实例的属性。对象实例可以直接出现在场景中,可以按照一定的层次结构组织起来。对象是组件(Component)的容器。

资源(Assets就是我们在Unity项目中可以直接使用的文件,包括图像、视频、脚本文件、预制文件等,它们会按照文件类型放到不同的文件夹,通过文件夹的形式来组织。资源的存在不依赖于Unity项目。

二者的区别:游戏对象是游戏中的概念,依赖于Unity项目;而大部分游戏资源是来自外部的文件,仅作为游戏对象的组成部分(比如模型、动画、音乐等)。
二者的联系:对象可以保存为资源,资源可以用来创建对象,一个资源可以创建多个对象。


· 下载几个游戏案例,分别总结资源、对象组织的结构(指资源的目录组织结构与游戏对象树的层次结构)
在Asset Store中,下载免费3D游戏案例Nature Starter Kit 2:
在这里插入图片描述

资源的根目录下,有Animations、Editor、Materials、Nature、Scene、Standard Assets、Textures七个目录以及info文件;Point light、Terrain、Trees等游戏对象是处于同一层次的,而Trees又有多个子对象,包括多种tree和bush。
总结:资源是按照文件夹的形式来组织的,根目录一般是各种类型的资源目录以及说明文件,各资源目录下则是该类型的资源文件。游戏对象树由对象之间的父子关系构成的,父亲对象作为根节点,孩子对象作为子节点。


· 编写一个代码,使用debug语句来验证 MonoBehaviour 基本行为或事件触发的条件。
其中,基本行为包括Awake() Start() Update() FixedUpdate() LateUpdate()
基本事件包括OnGUI() OnDisable() OnEnable()

根据官方文档,上述基本行为或事件的触发条件为:
Awake() 在脚本实例被加载时即被调用
Start() 仅在Update函数第一次被调用前调用
Update() 每一帧触发一次
FixedUpdate() 在自设定的帧频下,每一帧触发一次
LateUpdate() 当Behaviour是enabled的情况下,在所有Update函数调用后被调用
OnGUI() 当渲染和处理GUI事件时被调用
OnDisable() 当行为变得无效的时候被调用
OnEnable() 当对象启用并激活的时候被调用

回到SampleScene项目中,新建3D对象Cube,并给它添加C#脚本,代码如下:

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对象
(1) 分别翻译官方对三个对象的描述(Description)
GameObject:

The GameObject is the most important concept in the Unity Editor.
Every object in your game is a GameObject, from characters and collectible items to lights, cameras
and special effects. However, a GameObject can’t do anything on its own; you need to give it properties before it can become a character, an environment, or a special effect.
You can think of a GameObject as an empty cooking pot, and components as different ingredients that make up the recipe of your game.

GameObject是Unity Editor中最重要的概念。
游戏中的每个对象都是GameObject,从角色和收藏品到灯光,相机和特效。
 但是,GameObject本身无法做任何事情; 您需要先赋予它属性才能成为一个角色,一个环境或一个特殊的效果。
您可以将GameObject视为一个空的烹饪锅,并将组件视为构成游戏配方的不同成分。

Transform

The Transform is used to store a GameObject’s position, rotation, scale and parenting state and is thus very important. A GameObject will always have a Transform component attached - it is not possible to remove a Transform or to create a GameObject without one.

Transform用于存储GameObject的位置,旋转,缩放和父亲状态,因此非常重要。 
GameObject将始终附加一个Transform组件 - 
无法删除该组件或创建没有该组件的GameObject。

Component

Components are the nuts & bolts of objects and behaviors in a game. They are the functional pieces of every GameObject.
A GameObject is a container for many different Components. By default, all GameObjects automatically have a Transform Component. This is because the Transform dictates where the GameObject is located, and how it is rotated and scaled. Without a Transform Component, the GameObject wouldn’t have a location in the world.
Even empty GameObjects have a Transform Component
Remember that you can always use the Inspector to see which Components are attached to the selected GameObject. As Components are added and removed, the Inspector will always show you which ones are currently attached. You will use the Inspector to change all the properties of any Component (including scripts).

组件是游戏中对象和行为的基本要素。 它们是每个GameObject的功能部分。
GameObject是许多不同组件的容器。 默认情况下,所有GameObjects都自动拥有一个Transform Component。 
这是因为Transform指示了GameObject的位置,以及它是如何旋转和缩放的。 
如果没有变换组件,GameObject将没有世界上的位置。
即使是空的GameObject也有一个Transform Component
请记住,您始终可以使用Inspector查看哪些组件附加到选定的GameObject。 
随着组件的添加和删除,Inspector将始终显示当前连接的组件。 您将使用Inspector更改任何Component(包括脚本)的所有属性。

(2) 描述下图中 table 对象(实体)的属性、table 的 Transform 的属性、 table 的部件

table对象的属性:activeInHierarchy(表示GameObject是否在场景中处于active状态)、activeSelf(GameObject的本地活动状态)、isStatic(仅编辑器API,指定游戏对象是否为静态)、layer(游戏对象所在的图层)、scene(游戏对象所属的场景)、tag(游戏对象的标签)、transform(游戏对象的转换,最常见的部件)
table的Transform的属性:Position、Rotation、Scale
table的部件有:Mesh Filter、Box Collider、Mesh Renderer


(3) 用 UML 图描述 三者的关系(请使用 UMLet 14.1.1 stand-alone版本出图)


· 整理相关学习资料,编写简单代码验证以下技术的实现:
(1) 查找对象
通过名字查找:

public static GameObject Find(string name)

例:创建Cube对象cube1,标签为Finish:

查找代码:

 GameObject tmp = GameObject.Find("cube1");
 Debug.Log(tmp.name);

输出:


通过标签查找:

public static GameObject FindWithTag(string tag))

查找代码:

GameObject tmp = GameObject.FindGameObjectWithTag("Finish");
Debug.Log(tmp.name+"000");

输出:


通过类别查找:

public static FindObjectOfType(System.Type type)

注:上述查找方式,也可一次查找多个对象。

(2) 添加子对象
代码:

 GameObject cube = GameObject.Find("cube1");
 GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
 obj.transform.position = new Vector3(0, -2, 0);
 obj.name = "cube2";
 obj.transform.parent = cube.transform;

发现cube1多了一个子对象cube2:
在这里插入图片描述

(3) 遍历对象树

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

(4) 清除所有子对象

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

· 资源预设(Prefabs)与 对象克隆 (clone)
(1) 预设(Prefabs)有什么好处?

Unity的Prefab系统允许用户创建,配置和存储GameObject及其所有组件,属性值和子GameObjects作为可重用资源。预设资产充当模板,用户可以在该模板中在场景中创建新的预设实例。
如果要重新使用以特定方式配置的GameObject(如非玩家角色(NPC),道具或场景 - 在场景中的多个位置或项目中的多个场景中),则应将其转换为预设。这比简单地复制和粘贴GameObject要好,因为Prefab系统允许用户自动保持所有副本同步。
用户对Prefab资产所做的任何编辑都会自动反映在该预制件的实例中,使用户可以轻松地对整个项目进行广泛的更改,而无需对资产的每个副本重复进行相同的编辑。

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

预设和克隆的作用都是通过复制产生对象,区别是:预设的对象是统一的,“牵一发而动全身”;而克隆的对象是互不影响的,修改一个并不会影响到另一个。

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

void Start () {  
    GameObject anotherTable = (GameObject)Instantiate(table.gameObject);  
} 

2. 编程实践,小游戏

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

我完成的是一款简单的“数字华容道”,具体见Github传送门


3. 思考题【选做】

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

模板方法模式:定义一个算法流程,将一些特定步骤的具体实现、延迟到子类。使得可以在不改变算法流程的情况下,通过不同的子类、来实现“定制”流程中的特定的步骤。
策略模式:使不同的算法可以被相互替换,而不影响客户端的使用。
微软XNA只是给出了虚方法,等待子类实现,而不是给出现成的算法,所以是“模板方法模式”而不是“策略模式”。


· 将游戏对象组成树型结构,每个节点都是游戏对象(或数)。
(1) 尝试解释组合模式(Composite Pattern / 一种设计模式)。
(2) 使用 BroadcastMessage() 方法,向子对象发送消息。你能写出 BroadcastMessage() 的伪代码吗?

组合模式(Composite Pattern),又叫部分整体模式,允许用户将对象组合成树形结构来表现”部分-整体“的层次结构,使得客户以一致的方式处理单个对象以及对象的组合。它创建了对象组的树形结构,创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。

void Start () {
		this.BroadcastMessage("Message");
}

void Message(){
		Debug.Log("Hello!");
}

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

装饰器模式。

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

装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。它是作为现有的类的一个包装,创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
而继承则限制了系统的灵活性,增强了耦合,因为继承是侵入式的,子类必须拥有父类的所有方法和属性。

2017-10-13 17:20:20 qq_16072507 阅读数 257
要绘制一个gameobject到屏幕上,unity需要调用图像api(dx,opengl)。
图像api对每一个绘制请求都需要做大量的工作,例如输入资源校验,顶点空间信息转换。
特别是在切换不同材质球的时候,图形api要做的工作更多,因为要切换状态(透明,不透明,贴图输入,渲染方式,加载shader,调用gpu驱动api前,获取/组织/封装输入参数)。
而图形api(dx,opengl)是在cpu上运行的,所以draw call的调用会增加cpu负载,消耗cpu时间
(unity--draw call-->dx/opengl  || CPU  ||  -->显卡驱动|| GPU ||);

优化思路:减少draw call 数量,减少状态切换
                每个mesh,每个材质,每个pass 都会产生一个draw call调用。
                所以,最有效的方法是合并mesh来减少draw call数量。
                unity有内置(好处:引擎代码层面可以独立控制每个物体)的两种合并mesh技术:
                    A:针对足够小的动态网格体,使用动态批处理(Dynamic batching),把类似的顶点分组,一次绘制。
                             限制:1、shader中最多使用900个顶点属性(例如:vert函数输出中有vertex position,normal,uv三个属性,那么输入网格最多能有300个顶点,才能加入到动态批处理)(动态批处理的每个顶点都有开销)
                                     2、空间上存在镜像的多个物体不能一起使用动态批处理(例如:A物体的Transform_scale_x是1,B物体的Transform_scale_x是-1)
                                     3、使用不同的材质实例不能动态批处理,即使是同一材质的不同实例,原因是阴影投射渲染的异常?   
                                     4、有附加渲染参数(lightmap index offset/scale)的光照贴图游戏物体。通常动态光照贴图游戏物体应该指向定位在批处理里的相同光照贴图?
                                     5、多pass shader不能批处理。
                                                在前向(forward rendering)渲染模式中,unity shader 支持多灯光,附加像素光源对应的pass不能批处理。
                                                传统的延后(defferred(light pre-pass))渲染不支持批处理,因为延后渲染要绘制物体两次。
                               动态批处理要在CPU上将游戏物体的所有顶点变换到世界空间。这样变换的开销比图形api(dx,opengl)执行draw call的开销更小才有意义。
                                draw call要求的资源受很多因素影响,主要是dx/opengl api使用的资源。例如:主机或苹果平台上draw call的开销较小,动态批处理没有什么优势。
                    B:针对静态物体,合并成一个大网格体,叫静态批处理(static batching)
                          静态批处理会增加内存消耗。即使批处理前共享网格的N个物体,也会增加N-1份内存消耗。
                          例如:茂密的树林,标记为静态,使用静态批处理,就会有大量的内存消耗。这时可以考虑不标记为静态,消耗时间,节省内存开销
                            处理过程:将静态游戏物体转换到世界空间,
                                            创建一个大的顶点集(64K 顶点数  和索引缓存(64K 索引数(48K opengles,32K macos));
                                            然后,对同意批次中的可见游戏对象,执行一系列简单的,几乎没有状态切换的draw call。
                                            技术上没有减少draw call 数量,当大量减少了状态切换(dx/opengl重大开销的部分)
                这两种批处理技术能够减少的draw call数的一个重要因素是:合并的物体共享材质的程度。
                因为,不同材质不可能使用同一个draw call(排除阴影绘制)
                只有共享材质的多个物体,合并成一个大网格体后,才能显著降低draw call数
                例如,10个共享材质(1个pass)的静态物体
                           没有使用静态批处理是10个draw call;
                            使用后为1个draw call,降低了90%的draw call 数。
                可使用批处理的渲染器:Mesh Renderers,Trail Renderers,Line Renderers,PaticleSystems,Sprite Renderers
                不能使用批处理的渲染器:skinned Meshes,cloth,other
                只有同类型的渲染器可以批处理。
                半透明物体比不透明物体更少的机会使用批处理,因为要从后到前的顺序获取半透明物体(确保透明效果),然后才批处理,顺序严格,获得批处理的机会更少。
                通过3d模型软件或Mesh.CombineMeshes手动合并相邻的网格物体是一个替换批处理的好方法。
                例如一个有多个绘制器的静态碗柜合并成一个网格是好的。
结论:多个物体共享材质(合并贴图,shader减少pass,少分支判断语句),多标为静态物体,是有效减少draw call,state changes,进而减少图形api(dx,opengl)/CPU负载,同时降低GPU负载的有效途径。

Unity3D作业一

阅读数 76

Unity3D第一次作业

阅读数 36

没有更多推荐了,返回首页