logo
Khóa học lập trình game server - smartfox - game đa người chơi Học lập trinh game online 3dvietpro Sửa chữa và thiết kế website .net
Welcome Guest! To enable all features please Đăng nhập or Đăng ký.

Thông báo

Icon
Error

Tùy chọn
Xem
Xem bài viết cuối Go to first unread
danhngoctan1993  
#1 Đã gửi : 15/04/2015 lúc 08:39:30(UTC)
danhngoctan1993

Danh hiệu: Newbie

Nhóm: Registered
Gia nhập: 15-04-2015(UTC)
Bài viết: 2
Japan
Đế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õ

Bạn bình luận ngay tại đây
Ai đang xem chủ đề này?
Guest
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.

Powered by YAF 2.1.0 | YAF © 2003-2024, Yet Another Forum.NET
Thời gian xử lý trang này hết 0.152 giây.