Tôi đã quyết định tôi muốn viết một lớp ResourceManager / ResourceCache trung tâm cho công cụ trò chơi sở thích của mình, nhưng gặp khó khăn khi thiết kế sơ đồ bộ đệm.
Ý tưởng là ResourceManager có một mục tiêu mềm cho tổng bộ nhớ được sử dụng bởi tất cả các tài nguyên của trò chơi cộng lại. Các lớp khác sẽ tạo các đối tượng tài nguyên, sẽ ở trạng thái không tải và chuyển chúng đến ResourceManager. Sau đó, Trình quản lý tài nguyên sẽ quyết định khi nào tải / dỡ các tài nguyên đã cho, giữ nguyên giới hạn mềm.
Khi một lớp khác cần một tài nguyên, một yêu cầu được gửi đến ResourceManager cho nó, (sử dụng id chuỗi hoặc mã định danh duy nhất). Nếu tài nguyên được tải, thì một tham chiếu chỉ đọc đến tài nguyên được chuyển đến chức năng gọi, (được bao bọc trong một tham chiếu được đếm yếu_ptr). Nếu tài nguyên không được tải, thì người quản lý sẽ đánh dấu đối tượng sẽ được tải vào cơ hội tiếp theo, (thường là ở phần cuối của bản vẽ khung).
Lưu ý rằng, mặc dù hệ thống của tôi thực hiện một số tính năng tham chiếu, nhưng nó chỉ tính khi tài nguyên đang được đọc, (vì vậy số tham chiếu có thể là 0, nhưng một thực thể vẫn có thể theo dõi nó là uid).
Cũng có thể đánh dấu các tài nguyên để tải tốt trước khi sử dụng lần đầu tiên. Dưới đây là một bản phác thảo về các lớp tôi đang sử dụng:
typedef unsigned int ResourceId;
// Resource is an abstract data type.
class Resource
{
Resource();
virtual ~Resource();
virtual bool load() = 0;
virtual bool unload() = 0;
virtual size_t getSize() = 0; // Used in determining how much memory is
// being used.
bool isLoaded();
bool isMarkedForUnloading();
bool isMarkedForReload();
void reference();
void dereference();
};
// This template class works as a weak_ptr, takes as a parameter a sub-class
// of Resource. Note it only hands give a const reference to the Resource, as
// it is read only.
template <class T>
class ResourceGuard
{
public:
ResourceGuard(T *_resource): resource(_resource)
{
resource->reference();
}
virtual ~ResourceGuard() { resource->dereference();}
const T* operator*() const { return (resource); }
};
class ResourceManager
{
// Assume constructor / destructor stuff
public:
// Returns true if resource loaded successfully, or was already loaded.
bool loadResource(ResourceId uid);
// Returns true if the resource could be reloaded,(if it is being read
// it can't be reloaded until later).
bool reloadResource(ResourceId uid)
// Returns true if the resource could be unloaded,(if it is being read
// it can't be unloaded until later)
bool unloadResource(ResourceId uid);
// Add a resource, with it's named identifier.
ResourceId addResource(const char * name,Resource *resource);
// Get the uid of a resource. Returns 0 if it doesn't exist.
ResourceId getResourceId(const char * name);
// This is the call most likely to be used when a level is running,
// load/reload/unload might get called during level transitions.
template <class T>
ResourceGuard<T> &getResource(ResourceId resourceId)
{
// Calls a private method, pretend it exits
T *temp = dynamic_cast<T*> (_getResource(resourceId));
assert(temp != NULL);
return (ResourceGuard<T>(temp));
}
// Generally, this will automatically load/unload data, and is called
// once per frame. It's also where the caching scheme comes into play.
void update();
};
Vấn đề là, để giữ cho tổng mức sử dụng dữ liệu lơ lửng xung quanh / dưới giới hạn mềm, người quản lý sẽ phải có một cách thông minh để xác định đối tượng nào sẽ dỡ tải.
Tôi đang nghĩ đến việc sử dụng một số loại hệ thống ưu tiên, (ví dụ: Ưu tiên tạm thời, Ưu tiên thường xuyên được sử dụng, Ưu tiên vĩnh viễn), kết hợp với thời gian của quy định cuối cùng và quy mô của tài nguyên, để xác định khi nào nên xóa nó. Nhưng tôi không thể nghĩ ra một sơ đồ hợp lý để sử dụng, hoặc các cấu trúc dữ liệu phù hợp cần có để nhanh chóng quản lý chúng.
Ai đó đã thực hiện một hệ thống như thế này có thể đưa ra một cái nhìn tổng quan về cách thức hoạt động của họ. Có một mẫu thiết kế rõ ràng tôi đang bỏ lỡ? Tôi đã làm điều này quá phức tạp? Lý tưởng nhất là tôi cần một hệ thống hiệu quả và khó lạm dụng. Có ý kiến gì không?