Trong lập trình game nói chung và lập trình game với Cocos2d-x nói riêng, việc xử lý “cứng” các đối tượng (như vị trí, tỷ lệ, góc quay,…) là điều nên tránh. Khi đem sản phẩm lên màn hình có tỷ lệ khác, vị trí các đối tượng có thể sẽ không còn được như mong muốn.
Do đó, việc quản lý động các đối tượng sẽ tối ưu hơn trong lập trình game đa màn hình. Bài viết sau giới thiệu cách hiện thực đơn giản giải quyết vấn đề trên trong Cocos2d-x.
Lớp Dictionary
Cocos2d-x đã hiện thực sẵn lớp Dictionary, hỗ trợ lập trình viên đọc file theo cấu trúc của file XML. Các key/value
sẽ được lưu trữ trong file dưới dạng tag.
File lưu trữ position phải tuân theo 1 cấu trúc định sẵn với phần ở rộng mặc định của file là .plist.
Hiện thực đơn giản file plist để minh họa với các key/value
như sau:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>title</key> <string>540,1250</string> <key>button_play </key> <string>540,800</string> <key>button_sound</key> <string>200,1400</string> </dict> </plist>
Các phương thức cần lưu ý khi sử dụng Dictionary
:
createWithContentsOfFile
Đối số truyền vào là đường dẫn đến file plist. Nếu đường dẫn không tồn tại sẽ trả về nullptr
. Thông qua hàm này, toàn bộ dữ liệu có trong file plist sẽ được xử lý thành các bộ key/value
. Cần tạo sẵn 1 đối tượng Dictionary
để lưu trữ lại các bộ key/value
này.
valueForKey
Hàm có tác dụng trả về value có dạng const __String*
với key
tương ứng. Nếu key
không tồn tại sẽ trả về 1 chuỗi rỗng.
Các kiểu dữ liệu phức tạp cấp cao như array
hay dict
sẽ không được trình bày trong bài viết này. Dữ liệu ở dạng chuỗi sẽ hiệu quả nhất, có thể thao tác để chuyển từ chuỗi sang các kiểu dữ liệu mong muốn.
Hiện thực lớp PositionManager
Lớp PositionManager có các phương thức chính là loadObjectsPosition
và getObjectPosition
.
Hiện thực 2 phương thức này bên dưới. Khai báo lớp PositionManager
như sau:
class PositionManager { private: static PositionManager* m_instance; private: PositionManager(); ~PositionManager(); public: static PositionManager* getInstance(); void loadObjectsPosition(const char* pListPath); Vec2 getObjectPosition(const String* objectPosition); // Your variable to store object position (Vec2) Vec2 m_title; Vec2 m_buttonPlay; Vec2 m_buttonSound; }
Do chỉ có duy nhất 1 PositionManager
tồn tại trong game nên áp dụng kỹ thuật Singleton để quản lý thuận tiện.
loadObjectsPosition
Hàm loadObjectsPosition
có tác dụng lưu trữ vị trí của các đối tượng được load vào file plist.
void PositionManager::loadObjectsPosition(const char* pListPath) { Dictionary* objectsListPosition = Dictionary::createWithContentsOfFile(pListPath); // get title position const __String* strTitlePosition = objectsListPosition->valueForKey("title"); PositionManager::getInstance()->m_title = getObjectPosition(strTitlePosition); // get play button position const __String* strButtonPlayPosition = objectsListPosition->valueForKey("button_play"); PositionManager::getInstance()->m_buttonPlay= getObjectPosition(strButtonPlayPosition); // get sound button position const __String* strButtonSoundPosition = objectsListPosition->valueForKey("button_sound"); PositionManager::getInstance()->m_buttonSound= getObjectPosition(strButtonSoundPosition); }
Value dạng chuỗi sẽ được lưu trữ lại trong các biến const __String*
và được phân tích (parse) để lưu trữ lại vào PositionManager
dưới dạng Vec2
. Các kiểu dữ liệu int
, float
, bool
, … được lưu trữ trực tiếp qua hàm valueForKey
.
getObjectPosition
Hàm getObjectPosition
hỗ trợ parse dữ liệu từ dạng const __String*
sang Vec2
.
Việc phân tích dữ liệu chuỗi sang các kiểu dữ liệu khác khá đơn giản và có nhiều cách hiện thực khác nhau. Dưới đây là cách sử dụng trong Project Zero:
Vec2 PositionManager::getObjectPosition(const __String* strObjectPosition) { Vec2 objectPosition; int value = 0; for(size_t i = 0; i < strObjectPosition->_string.length(); i++) { if(strObjectPosition->_string[i] >= '0' && strObjectPosition->_string[i] <= '9') { value *= 10; value += (strObjectPosition->_string[i] - '0'); } else { objectPosition.x = value; value = 0; } } objectPosition.y = value; return objectPosition; }