0

Game design pattern on cocos2dx : Observer

OBSERVER : MẪU NGƯỜI QUAN SÁT

Hôm nay mình sẽ giới thiệu cho các bạn 1 mẫu design pattern hay được sử dụng trong game deverlopment đó chính là Observer. Observer là mẫu design pattern phổ biến không chỉ trong phát triển game mà còn trong hầu hết các lĩnh  vực phát triển phần mềm. Để tìm hiểu về Observer là gì cà trong phát triển game nó được dùng như thế nào thì trước tiên ta phải hiểu Design pattern là gì? và nó có vai trò như thế nào trong phát triển phần mềm? Design patterns là các giải pháp đã được tối ưu hóa, được tái sử dụng cho các vấn đề lập trình mà chúng ta gặp phải hàng ngày. Nó là một khuôn mẫu đã được suy nghĩ, giải quyết trong tình huống cụ thể rồi. Các vấn đề mà bạn gặp phải có thể bạn sẽ tự nghĩ ra cách giải quyết nhưng có thể nó chưa phải là tối ưu. Design Pattern giúp bạn giải quyết vấn đề một cách tối ưu nhất, cung cấp cho bạn các giải pháp trong lập trình OOP. Nó không phải là ngôn ngữ cụ thể nào cả. Design patterns có thể thực hiện được ở phần lớn các ngôn ngữ lập trình. Ta thường gặp nó nhất trong lập trình OOP. Vậy mẫu Observer là gì ? Trong game design pattern mẫu Observer sẽ làm nhiệm vụ thông báo cho controller biết khi có bất kỳ thay đổi từ data trong mô hình Modem - view - controller. Điều này nghĩa là gì? Đơn giản bạn hình dung khi bạn đang chơi game nhập vai online. Khi nhân vật của bạn tăng level server sẽ báo về cho data của nhân vật thay đổi. Khi đó hiển thị level trên màn hình sẽ thay đổi. Việc hiển thị lên màn hình sẽ được view trong mô hình MVC phụ trách. Vậy làm cách nào để view biết data thay đổi để hiển thị? Khi đó nhiệm vụ sẽ phụ thuộc vào mẫu Observer. Controller sẽ đóng vai trò người quan sát data. Data thay đổi sẽ bắn ra 1 notification nói rằng data đã cập nhật dữ liệu mới qua đó controller lắng nghe được và yêu cầu view cập nhật hiển thị. Đó là 1 ví dụ đơn giản để các bạn hiểu được observer là gì và nó hoạt động như thế nào. Cocos2dx đã xây dựng sẵn 1 class theo Observer Design pattern đó là CCNotificationCenter. Nhiệm vụ của class này là tạo và xoá các Observer hoặc bắn ra các notification tới observer khi có thay đổi. Các phương thức chính trong class CCNotification :

  • void addObserver (CCObject *target, SEL_CallFuncO selector, const char *name, CCObject *obj) để thêm observer cho 1 đối tượng cụ thể. Trong đó target là đối tượng muốn theo dõi sự kiện thông báo, selector là phương thức sẽ được gọi khi đối tượng theo dõi thông báo có sự thay đổi, name là tên của thông báo, obj là tham số truyền vào cùng với selector.
  • void removeObserver (CCObject *target, const char *name) xoá 1 observer bởi 1 đối tượng và tên cụ thể.
  • int removeAllObservers (CCObject *target) xoá tất cả các thông báo được đăng ký bởi target.
  • void postNotification (const char *name) bắn ra 1 thông báo được có tên name. Tất cả những observer nào có tên name sẽ nhận được thông báo này và tiến hành cập nhật data, hoặc hiển thị tuỳ thuộc theo phương thức callback đã đăng ký trước đó.
  • void postNotification (const char *name, CCObject *object) bắn ra 1 thông báo có tên name kèm theo tham số truyền vào object.

Bên trên là các phương thức chính hay được sử dụng. Để hiểu rõ hơn tác dụng cũng như cách thức hoạt động của CCNotificationCenter chúng ta cùng tìm hiểu thông qua 1 ví dụ đơn giản sau : trong màn hình HelloWorld khi chạm vào màn hình sẽ tạo ra 1 label đếm tăng dần theo thời gian tại vị trí chạm vào màn hình đó. Đầu tiên ta phải tạo 1 lớp Cout để hiển thị label coutup : Count.h

class Count : public cocos2d::Label
{
public :
virtual ~Count();
virtual bool init();
CREATE_FUNC(Count);
private:
int _count;
void countUp(Ref* data);
};

Count.cpp

Count::~Count()
{
CCNotificationCenter::getInstance()->removeAllObservers(this);
}

bool Count::init()
{
if(!cocos2d::Label::init())
{
return false;
}

_count = 0;
this->setString(StringUtils::toString(_count));

CCNotificationCenter::getInstance()->addObserver(this, SEL_CallFuncO(&Count::countUp), "count up", nulltr); //  đăng ký observer với tên "cout up"
return true;
}

void Count::countUp(Ref *data)
{
_cout++;
this->setString(StringUtils::toString(_count));
}

Bây giờ chúng ta sẽ sửa class HelloWorld:

bool HelloWorld::init()
{
if(!Layer::init())
{
return false;
}

auto listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
this->getEventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
this->schedule(schedule_selector(HelloWorld::countUp), 1.0f);

return true;
}

bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
{
    auto countLabel = Count::create();
    this->addChild(countLabel);
    countLabel->setPosition(touch->getLocation());
    
    return true;
}

void HelloWorld::countUp(float dt)
{
CCNotification::getInstance()->postNotification("count up"); // thông báo tới observer có tên "cout up"
}

Và kết quả là mỗi khi ta touch vào màn hình thì sẽ có 1 label được tạo ra và sau 1s thì label sẽ tăng lên 1 đơn vị. Vừa rồi mình đã giới thiệu cho các bạn mẫu Observer pattern và cách sử dụng class CCNotification để xây dựng lên các Observer. Hy vọng bài viết có ích cho các bạn. Cảm ơn các bạn đã theo dõi!!!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí