程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> Unity3D 學習教程 13 C# 銷毀炮彈,

Unity3D 學習教程 13 C# 銷毀炮彈,

編輯:C#入門知識

Unity3D 學習教程 13 C# 銷毀炮彈,


gameObject.renderer.enabled
//是控制一個物體是否在屏幕上渲染或顯示  而物體實際還是存在的 只是想當於隱身 而物體本身的碰撞體還依然存在的

GameObject.Destroy() 
//表示移除物體或物體上的組件 代表銷毀該物體  實際上該物體的內存並沒有立即釋放 而是在你下下個場景中槽釋放內存資源,就是你a場景中Destroy了 一般是在c場景中才真正釋放該物體的內存資源(這是我的體會 不知道理解錯誤沒)

gameObject.active  
//是否在場景中停用該物體   在你gameObject.active =false中 則你在場景中用find找不到該物體 
//如果該物體有子物體 你要用SetActiveRecursively(false) 來控制是否在場景中停用該物體(遞歸的)

 

我們要介紹是銷毀物體Destroy() 

 1 using UnityEngine;
 2 using System.Collections;
 3 
 4 public class acc : MonoBehaviour {
 5 
 6     // Use this for initialization
 7     public Transform Q;
 8     int speed=50;
 9     void Start () {
10 
11     }
12     
13     // Update is called once per frame
14     void Update () {
15         float x = Input.GetAxis("Horizontal") * Time.deltaTime * speed;//左右移動
16         float z = Input.GetAxis("Vertical") * Time.deltaTime * speed;//    前後移動
17         //主攝像機物體    移動
18         transform.Translate(x,0,z);
19 
20         if(Input.GetKeyDown(KeyCode.Mouse0))
21         {
22 
23             //實列化子彈
24             Transform n = Instantiate(Q) as Transform;
25             //發射子彈的位置為物體的位置
26             n.position = transform.position;
27             
28             Vector3 f = transform.TransformDirection(Vector3.forward);
29             n.gameObject.rigidbody.AddForce(f*3000);
30             Destroy(n.gameObject,5);
31                                                       //Destroy(n.gameObject);
32             //Destroy(gameObject);
33         }
34 
35 
36     }
37 }

5秒後 銷毀物體

Destroy(n.gameObject,5);

立即銷毀物體

Destroy(n.gameObject);

 

如果文件綁定在物體上用

Destroy(gameObject);

來銷毀物體

 

 

Unity資源內存申請和釋放

1.資源類型

GameObject, Transform, Mesh, Texture, Material, Shader, Script和各種其他Assets。

2.資源創建方式

  • 靜態引用,在腳本中加一個public GameObject變量,在Inspector面板中拖一個prefab到該變量上,然後在需要引用的地方Instantiate;
  • Resource.Load,資源需要放在Assets/Resources目錄下;
  • AssetBundle.Load, Load之後Instantiate。

    3. 資源銷毀方式

  • GameObject.Destroy(gameObject),銷毀該物體;
  • AssetBundle.Unload(false),釋放AssetBundle文件內存鏡像,不銷毀Load創建的Assets對象;
  • AssetBundle.Unload(true),釋放AssetBundle文件內存鏡像同時銷毀所有已經Load的Assets內存鏡像;
  • Resources.UnloadAsset(Object),釋放已加載的Asset對象;
  • Resources.UnloadUnusedAssets,釋放所有沒有引用的Asset對象。

    4. 生命周期

    實驗篇

    實驗中創建了一個簡單場景,場景中創建了一個Empty GameObject,上面掛了一個腳本,在Awake函數中通過協程函數來創建資源,具體的Coroutine函數下面都有。 實驗中創建的Prefab是一個坦克車,加入場景中場景內存增加3M左右,同時創建了一個AssetBundle資源供AssetBundle使用。

    1. Resources.Load方式加載一個Prefab, 然後Instantiate GameObject

    代碼如下:
   IEnumerator LoadResources()
    {
        // 清除干淨以免影響測試結果
        Resources.UnloadUnusedAssets();
        // 等待5秒以看到效果
        yield return new WaitForSeconds(5.0f);

        // 通過Resources.Load加載一個資源
        GameObject tank = Resources.Load("Role/Tank") as GameObject;
        yield return new WaitForSeconds(0.5f);

        // Instantiate一個資源出來
        GameObject tankInst = GameObject.Instantiate(tank, Vector3.zero, Quaternion.identity) as GameObject;
        yield return new WaitForSeconds(0.5f);

        // Destroy一個資源
        GameObject.Destroy(tankInst);
        yield return new WaitForSeconds(0.5f);

        //釋放無用資源
        tank = null;
        Resources.UnloadUnusedAssets();

        yield return new WaitForSeconds(0.5f);
    }

執行結果如下:

下面是統計結果:

數據描述MemoryTextureMeshMaterialGameObjectsObjects in SceneTotal Objects 初始 72.8M 1271/8.0M 35/223.0K 25/10.2K 7 211 2187 Resources.Load 72.8M 1271/8.0M 36/0.8M 25/10.2K 7 211 2280 Instantiate 75.3M 1272/9.3M 36/0.8M 26/10.7K 52 303 2375 Destroy 74.7M 1272/9.3M 36/0.8M 26/10.7K 7 211 2283 Resources.UnloadUnusedAssets 72.3M 1271/8.0M 35/223.0K 25/10.2K 7 211 2187

從這裡我們得出如下結論:

  • Resouces.Load一個Prefab相對於Instantiate一個資源來說是相對輕量的一個操作,上述過程中,Resources.Load加載一個Prefab幾乎沒有消耗內存,而Instantiate消耗了2.5M的資源空間。Resources.Load增加了Mesh和Total Object的數量,而Instantiate增加了GameObjects,Objects In Scene和Total Objects的數量;
  • Destroy一個GameObject之後,內存有所減少,但是比較少,本例中減少了0.6M;Instantiate和Destroy前後Material和Texture沒有還原,用以後面繼續進行Instantiate之用。

若沒有調用Resources.UnloadUnusedAssets,則結果如下:

 

統計結果如下:

數據描述MemoryTextureMeshMaterialGameObjectsObjects in SceneTotal Objects 初始 58.9M 1258/7.5M 34/219.2K 22/9.0K 7 117 2078 Resources.Load 60.0M 1258/7.5M 35/0.8M 22/9.0K 7 117 2171 Instantiate 62.5M 1259/8.9M 36/0.8M 23/9.5K 52 209 2256 Destroy 61.8M 1259/8.9M 35/0.8M 23/9.5K 7 117 2174

得出如下結論: 如果不手動執行Resources.UnloadUnusedAssets,則多余的Mesh,Material和Object不會主動釋放。

2. 以AssetBundle.Load的方式加載一個Prefab,然後Instantiate一個GameObject

代碼如下:

 IEnumerator LoadAssets(string path)
    {
        // 清除干淨以免影響測試結果
        Resources.UnloadUnusedAssets();

        // 等待5秒以看到效果
        yield return new WaitForSeconds(5.0f);

        // 創建一個WWW類
        WWW bundle = new WWW(path);
        yield return bundle;
        yield return new WaitForSeconds(0.5f);

        // AssetBundle.Load一個資源
        Object  obj =  bundle.assetBundle.Load("tank");
        yield return new WaitForSeconds(0.5f);

        // Instantiate一個資源出來
        GameObject tankInst = Instantiate(obj) as GameObject;
        yield return new WaitForSeconds(0.5f);

        // Destroy一個資源
        GameObject.Destroy(tankInst);
        yield return new WaitForSeconds(0.5f);

        // Unload Resources
        bundle.assetBundle.Unload(false);
        yield return new WaitForSeconds(0.5f);

        // 釋放無用資源
        //obj = null;
        //Resources.UnloadUnusedAssets();

        yield return new WaitForSeconds(0.5f);
    }

執行結果如下: 統計結果如下:

數據描述MemoryTextureMeshMaterialGameObjectsObjects in SceneTotal Objects 初始 59.9M 1267/7.8M 35/223.0K 25/10.2K 7 127 2099 new WWW 62.0M 1267/7.8M 35/223.0K 25/10.2K 7 127 2099 AssetBundle.Load 64.5M 1268/9.2M 36/0.8M 26/10.5K 7 127 2196 Instantiate 65.6M 1268/9.2M 36/0.8M 26/10.7K 52 219 2288 Destroy 63.9M 1268/9.2M 36/0.8M 26/10.7K 7 127 2196 AssetBundle.Unload 63.7M 1268/9.2M 36/0.8M 26/10.7K 7 127 2196 Resources.UnloadUnusedAssets 61.8M 1267/7.8M 35/223.0K 25/10.2K 7 127 2099

得出如下結論: 通過WWW Load AssetBundle的方式加載一個資源時會自動加載相應的Mesh,Texture和Material,而通過Resouces.Load方式進行加載只會加載Mesh信息。因此通過AssetBundle方式加載後Instantiate一個資源的內存消耗較小,本例中AssetBundle.Load增加了2.5M的內存,而Instantiate增加了1.1M的內存。相比較Resources.Load後Instantiate的內存增量要小很多。

3. 通過靜態綁定的方法來Instantiate一個資源

代碼如下:

    IEnumerator InstResources()
    {
        Resources.UnloadUnusedAssets();
        yield return new WaitForSeconds(5.0f);

        GameObject inst = GameObject.Instantiate(tank, Vector3.zero, Quaternion.identity) as GameObject;
        yield return new WaitForSeconds(1f);

        GameObject.Destroy(inst);
        yield return new WaitForSeconds(1f);

        //釋放無用資源
        tank = null;
        Resources.UnloadUnusedAssets();

        yield return new WaitForSeconds(1f);
    }

執行結果如下:

統計結果如下:

數據描述MemoryTextureMeshMaterialGameObjectsObjects in SceneTotal Objects 初始 62.0M 1268/7.9M 36/0.8M 25/10.2K 7 134 2202 Instantiate 64.4M 1269/9.2M 36/0.8M 26/10.7K 8 137 2207 Destroy 64.0M 1269/9.2M 36/0.8M 26/10.7K 7 134 2204 UnloadUnused Resources 62.3M 1268/7.9M 35/226.3K 25/10.2K 7 134 2107

得出結論如下: 通過靜態綁定的方式各種資源的加載順序和Resources.Load的方式是一樣的,一個GameObject創建時,其Component中靜態綁定的GameObject只會加載Mesh信息,只有當該GameObject Instantiate出來之後才會加載Texture和Material信息。

理論篇

加載資源的過程可以分為兩個階段,第一階段是使用Resources.Load或者AssetBundle.Load加載各種資源,第二階段是使用GameObject.Instantiate克隆出一個新的GameObject。 Load的資源類型包括GameObject, Transform, Mesh, Texture, Material, Shader和Script等各種資源,但是Resources.Load和AssetBundle.Load是有區別的。 使用Resources.Load的時候在第一次Instantiate之前,相應的Asset對象還沒有被創建,直到第一次Instantiate時才會真正去讀取文件創建這些Assets。它的目的是實現一種OnDemand的使用方式,到該資源真正使用時才會去創建這些資源。 而使用AssetBundle.Load方法時,會直接將資源文件讀取出來創建這些Assets,因此第一次Instantiate的代價會相對較小。 上述區別可以幫助我們解釋為什麼發射第一發子彈時有明顯的卡頓現象的出現。

然後我們再來了解一下Instantiate的過程。Instantiate的過程是一個對Assets進行Clone(復制)和引用相結合的過程,Clone的過程需要申請內存存放自己的數據,而引用的過程只需要直接一個簡單的指針指向一個已經Load的資源即可。例如Transform是通過Clone出來的,Texture和TerrainData是通過引用復制的,而Mesh,Material,PhysicalMaterial和Script是Clone和引用同時存在的。以Script為例,Script分為代碼段和數據段,所有需要使用該Script的GameObject使用的代碼是一樣的,而大家的數據有所區別,因此對數據段需要使用Clone的方式,而對代碼段需要使用引用的方式來復制。 因此Load操作其實Load一些數據源出來,用於創建新對象時被Clone或者被引用。

然後是銷毀資源的過程。當Destory一個GameObject或者其他實例時,只是釋放實例中那些Clone出來的Assets,而並不會釋放那些引用的Assets,因為Destroy不知道是否有其他人在引用這些Assets。等到場景中沒有任何物體引用到這些Assets之後,它們就會成為UnusedAssets,此時可以通過Resources.UnloadUnusedAssets來進行釋放。AssetBundle.Unload(false)不行,因為它只會釋放文件的內存鏡像,不會釋放資源;AssetBunde.Unload(true)也不行,因為它是暴力的釋放,可能有其他對象在引用其中的Assets,暴力釋放可能導致程序錯誤。 另外需要注意,系統在加載新場景時,所有的內存對象都會被自動銷毀,這包括了Resources.Load加載的Assets, 靜態綁定的Assets,AssetBundle.Load加載的資源和Instantiate實例化的對象。但是AssetBundle.Load本身的文件內存鏡像(用於創建各種Asset)不會被自動銷毀,這個必須使用AssetBundle.Unload(false)來進行主動銷毀。推薦的做法是在加載完資源後立馬調用AssetBunble.Unload(false)銷毀文件內存鏡像。 下圖可以幫助理解內存中的Asset和GameObject的關系。

總結篇

  • 為了不出現首次Instantiate時卡頓的現象,推薦使用AssetBundle.Load的方式代替Resources.Load的方式來加載資源;
  • 加載完資源後立馬調用AssetBunble.Unload(false)釋放文件內存鏡像;
  • Unity自身沒有提供良好的內存申請和釋放管理機制,Destroy一個GameObject會馬上釋放內存而不是進行內部的緩存,因此應用程序對頻繁不用的對象如NPC,FX等進行對象池管理是必要的,減少內存申請次數;
  • 何時進行Resources.UnloadUnusedAssets是需要討論的一個問題。

 

520 520小說 小說520 小說520 5200 小說5200 5200小說 5200小說網

www.520books.com

http://www.cnblogs.com/goodchenqing/

http://blog.sina.com.cn/goodchenqing

http://goodchenqing.bokee.com/

http://blog.csdn.net/abc288abcd/article/category/2786567

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved