Học Unity
»
Lập trình Unity 3D
»
Bài hướng dẫn
»
Tái sử dụng tài nguyên bằng Object Pool Unity3D
Danh hiệu: Newbie
Nhóm: Registered
Gia nhập: 15-04-2015(UTC) Bài viết: 2 Đến từ: việt nam
|
1.Tại sao phải dùng Object Pooling? Trong quá trình làm game, 1 điều quan trọng là phải tránh tối đa các thao tác Destroy/ Instantiate object, 2 thao tác này rất nặng với hệ thống, hệ thống phải cấp phát bộ nhớ khi khởi tạo, rồi lại thu hồi bộ nhớ khi hủy, việc này rất tốn thời gian, lại thường tạo ra rác. Với những game ít object cần Destroy/Instatiate thì không đáng kể, nhưng nếu nhiều object (Ví dụ: Game bắn súng, số lượng đạn Instantiate/Destroy là rất lớn) sẽ khiến game bị Lag. Và Object Pooling là 1 phương pháp được ưa chuộng để giải quyết vấn đề trên. 2.Ý tưởng của Object Pooling là gì? Khá là đơn giản, đó là thay vì Destroy object thì bạn sẽ move object ra ngoài cửa sổ game rồi disable nó đi, khi nào cần dùng lại bạn lại move object về cửa sổ game và active nó. Do vậy thao tác Destroy/Instantiate đã được giảm. 3.Cách dùng Object Pooling Dựa theo ý tưởng trên các bạn có thể tự viết script cho mình hoặc làm theo script mẫu sau:
Trích dẫn: using UnityEngine; using System.Collections; using System.Collections.Generic; public class ObjectPool : MonoBehaviour { public static ObjectPool instance; /// /// The object prefabs which the pool can handle. /// public GameObject[] objectPrefabs; /// /// The pooled objects currently available. /// public List[] pooledObjects; /// /// The amount of objects of each type to buffer. /// public int[] amountToBuffer; public int defaultBufferAmount = 3; /// /// The container object that we will keep unused pooled objects so we dont clog up the editor with objects. /// protected GameObject containerObject; void Awake () { instance = this; } // Use this for initialization void Start () { containerObject = new GameObject("ObjectPool"); //Loop through the object prefabs and make a new list for each one. //We do this because the pool can only support prefabs set to it in the editor, //so we can assume the lists of pooled objects are in the same order as object prefabs in the array pooledObjects = new List[objectPrefabs.Length]; int i = 0; foreach ( GameObject objectPrefab in objectPrefabs ) { pooledObjects[i] = new List(); int bufferAmount; if(i < amountToBuffer.Length) bufferAmount = amountToBuffer[i]; else bufferAmount = defaultBufferAmount; for ( int n=0; n { GameObject newObj = Instantiate(objectPrefab) as GameObject; newObj.name = objectPrefab.name; PoolObject(newObj); } i++; } } /// /// Gets a new object for the name type provided. If no object type exists or if onlypooled is true and there is no objects of that type in the pool /// then null will be returned. /// /// /// The object for type. /// /// /// Object type. /// /// /// If true, it will only return an object if there is one currently pooled. /// public GameObject GetObjectForType ( string objectType , bool onlyPooled ) { for(int i=0; i { GameObject prefab = objectPrefabs[i]; if(prefab.name == objectType) { if(pooledObjects[i].Count > 0) { GameObject pooledObject = pooledObjects[i][0]; pooledObjects[i].RemoveAt(0); pooledObject.transform.parent = null; pooledObject.SetActiveRecursively(true); return pooledObject; } else if(!onlyPooled) { return Instantiate(objectPrefabs[i]) as GameObject; } break; } } //If we have gotten here either there was no object of the specified type or non were left in the pool with onlyPooled set to true return null; } /// /// Pools the object specified. Will not be pooled if there is no prefab of that type. /// /// /// Object to be pooled. /// public void PoolObject ( GameObject obj ) { for ( int i=0; i { if(objectPrefabs[i].name == obj.name) { obj.SetActiveRecursively(false); obj.transform.parent = containerObject.transform; pooledObjects[i].Add(obj); return; } } } }
Cách dùng script trên: a. Cho script trên vào project của bạn (tất nhiên rồi Wink b. Add script này vào một Game Object trong cửa sổ Hierarchy (Ví dụ bạn có thể new 1 GameObject r add script này vào). c.Ở mảng Object Prefabs, bạn add các object cần tái sử dụng trong game (Ví dụ như prefab của đạn, chướng ngại vật....). d.Ở mảng Amount To Buffer, bạn thêm số lượng của mỗi object tương ứng trên mảng Object Prefabs (Ví dụ bạn cần khởi tạo 10 viên đạn => objectPrefabs[i] = đạn, amountToBuffer[i] = 10). Default amount to Buffer là số lượng object mặc định nếu bạn không set Amout To Buffer. e.Ở trong game, Thay vì trước đây bạn dùng lệnh Instantiate để khởi tạo thì bây giờ bạn dùng ObjectPool.instance.GetObjectForType(objectType, onlyPooled). objectType là tên của object, nếu bạn để onlyPooled là true -> nó sẽ chỉ lấy object trong ObjectPooled(hiểu nôm na là nơi chứa các object không sử dụng được move tới), ngược lại nếu để onlyPooled là false nó sẽ Instantiate ra 1 object mới do vậy chúng ta thường nên đặt là true để Object Pooling hiệu quả hơn. Ví dụ mình muốn khởi tạo đạn có tên là bulletObject => GameObject obj = ObjectPool.instance.GetObjectForType("bulletObject", true), sau đó obj này sẽ được dùng bình thường như một object được Instantiate khác. Tương tự để hủy object, thì thay vì dùng Destroy bạn phải làm 1 việc là đưa object này về ObjectPooled, cách dùng ObjectPool.instance.PoolObject(gameObject). Bạn cần nắm rõ lúc nào nên gọi object từ ObjectPooled và move object về ObjectPooled để tài nguyên được luân chuyển sử dụng. Tương tự nếu game của bạn có thêm object là Effect, bạn dùng thêm script này vào GameObject của mình:
Trích dẫn: using UnityEngine; using System.Collections; public class Effect : MonoBehaviour { /// /// The array of emitters to fire when the effect starts. /// public ParticleEmitter[] emitters; /// /// The length of the effect in seconds. After which the effect will be reset and pooled if needed. /// public float effectLength = 1f; /// /// Should the effect be added to the effects pool after completion. /// public bool poolAfterComplete = true; /// /// Resets the effect. /// public virtual void ResetEffect () { if(poolAfterComplete) { ObjectPool.instance.PoolObject(gameObject); } else { Destroy(gameObject); } } /// /// Starts the effect. /// public virtual void StartEffect () { foreach ( ParticleEmitter emitter in emitters ) { emitter.Emit(); } StartCoroutine(WaitForCompletion()); } public IEnumerator WaitForCompletion () { //Wait for the effect to complete itself yield return new WaitForSeconds(effectLength); //Reset the now completed effect ResetEffect(); } }
Sửa bởi quản trị viên 15/04/2015 lúc 07:59:14(UTC)
| Lý do: Chưa rõ
|
|
|
|
Học Unity
»
Lập trình Unity 3D
»
Bài hướng dẫn
»
Tái sử dụng tài nguyên bằng Object Pool Unity3D
Di chuyển
Bạn không thể tạo chủ đề mới trong diễn đàn này.
Bạn không thể trả lời chủ đề trong diễn đàn này.
Bạn không thể xóa bài của bạn trong diễn đàn này.
Bạn không thể sửa bài của bạn trong diễn đàn này.
Bạn không thể tạo bình chọn trong diễn đàn này.
Bạn không thể bỏ phiếu bình chọn trong diễn đàn này.