游戏设计模式-观察者模式

成就系统,基本上是每个游戏里都会涉及到的系统,但如果直接使用其它系统的函数接口,你将会发现整个项目中,每个系统都要和成就系统耦合在一起。

这是一件极其糟糕的事情。

观察者模式可以解决这件事情。


首先,我们先定义两个类,分别是观察者和被观察者。

 观察者:

class Observer
{
	friend class Subject;

public:
	Observer()
		:next(nullptr), previous(nullptr) {}

	void OnNotify(const Unit unit, Event event) {}

private:
	std::shared_ptr<Observer> next;
	std::shared_ptr<Observer> previous;
};

 被观察者:

class Subject
{
public:
	Subject()
		:head(nullptr) {}

	void AddObserver(std::shared_ptr<Observer> observer)
	{
		observer->next = head;
		head = observer;
	}

	void RemoveObserver(std::shared_ptr<Observer> observer)
	{
		if (observer->previous == nullptr)
			head = observer->next;
		else
			observer->previous = observer->next;
	}

	void Notify(const Unit unit,Event event)
	{
		//相应事件
		//...

		auto observer = head;
		while (observer != nullptr)
		{
			observer->OnNotify(unit, event);
			observer = observer->next;
		}
	}

private:
	std::shared_ptr<Observer> head;
};

如何去使用它:

假如游戏中存在着一个邮件系统,当玩家发送第一封邮件时,解锁一个成就:

发信人:成功发送一封邮件给其他玩家

那我们只需要在邮件系统中定义:

class MailMgr
{
public:
	void OnRoleSendMail(Unit& unit)
	{
		subject.Notify(unit, Event::EVENT_SENDMAIL);

		//...
	}

private:
	Subject subject;
};

观察者模式本身只是发送了一个通知,它的逻辑是遍历一个观察者列表,然后调用函数,相对于一开始的直接函数调用,它并没有速度上的劣势,反而让两个游戏系统解耦,邮件系统开发者并不需要关注成就系统开发者做了什么事情。

如果非要说它的缺点:那就是多了一些内存的开销


 进阶:

链表节点池:

我们可以对被观察者进行改造,在上面的代码中,被观察者存储的是一个观察者列表,现在改为存储一个指针列表,列表中的指针指向真正的观察者。

这样,多个指针可以指向同一个观察者,节省空间。

(当然,上面的代码使用的是智能指针,变向地支持了这个功能)

对象池:

由于所有的结点都是一样的大小和类型,可以预分配一个内存对象池子,根据需要去重用而不是不断地进行内存分配

 注册函数,而不是注册类:

在上面的代码中,我们是使用类来实现观察者(列表中存储的是对象指针),其实也可以改造成函数指针。 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值