游戏编程模式——观察者模式

游戏编程模式——观察者模式

概述

​ 观察者模式是我们在游戏中常用到的一种设计模式,比方说在UI系统中,我们消耗了金币,要更新当前UI界面上所有和金币相关的元素,如果UI上只有一个修改项还好,但当修改的元素过多时,一个个修改就会很麻烦,也容易遗漏,而且代码耦合性也很高,通常我们可以用观察者模式来解决类似的问题。cocos2dx中的事件分发器就采用了观察者模式的思想。

​ 下面是根据《 游戏编程模式》写的一个简单的观察者模式实例,采用定长数组来保存观察者,可以优化成链式观察者。

​ 应用场景:游戏中需要一个成就系统,当我们触发玩家角色坠落时,触发成就系统的一个成就事件,而玩家坠落是由物理系统处理的,要避免两个系统之间代码耦合。

本文只是展现观察者模式的一个应用实例,不对观察者模式进行详细介绍,具体的介绍可以参考《游戏编程模式》或其他设计模式经典书籍。

类图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eTkAnkXs-1612423438216)(https://s3.ax1x.com/2021/01/30/yknqN8.png)]

​ 如图,避免了成就系统和物理系统的耦合。

代码实现

被观察对象——Subject

Subject.h

#pragma once
#include "Observer.h"
#include "Event.h"

class Subject {
public:
	void addObserver(Observer* observer);
	void removeObserver(Observer* observer);

private:
	Observer* observers_[MAX_OBSERVERS];
	int numObservers_ = 0;

protected:
	void notify(const Entity& entity, Event event);
};

Subject.cpp

#include "Subject.h"

void Subject::addObserver(Observer* observer) {
	observers_[numObservers_] = observer;
	++numObservers_;
}

void Subject::removeObserver(Observer* observer) {

}

void Subject::notify(const Entity& entity, Event event) {
	for (int i = 0; i < numObservers_; ++i) {
		observers_[i]->onNotify(entity, event);
	}
}

物理系统类 Physics

Physics.h

#pragma once
#ifndef PHYSICS
#include "Subject.h"
class Physics :public Subject
{
public:
	void updateEntity(Entity& entity,Event event);
};

#endif // !PHYSICS

Physics.cpp

#include "Physics.h"
void Physics::updateEntity(Entity& entity,Event event) {
	Subject::notify(entity, event);
}

观察者抽象类 Observer

Observer.h

#pragma once
#ifndef OBSERVER
#include "Entity.h"
#include "Event.h"

#define MAX_OBSERVERS 100

class Observer {
public:
	virtual ~Observer() {};
	virtual void onNotify(const Entity& enity, Event event) = 0;
};

#endif // !OBSERVER

可以看到Observer类中有一个纯虚函数 —— onNotify() ,所以Observer类是一个抽象基类,不能被实例化

成就Achievements

​ 成就Achievements类继承于Observer类,是一个具体的观察者,通过重写了父类Observer的纯虚函数onNotify()来实现不同观察者对同一监听事件的不同处理方法。

Achievements.h

#pragma once
#ifndef ACHIEVEMENTS
#include "Observer.h"
#include "Entity.h"
#include "Event.h"

class Achievements :public Observer {
public:
	virtual void onNotify(const Entity& enity, Event event);
};
#endif 

Achievements.cpp

#include "Achievements.h"

void Achievements::onNotify(const Entity& enity, Event event) {
	switch (event)
	{
	case EVENT_ENTITY_FALL:
		if (enity.isHero()) {
			printf("Get achievement - falling hero");
		}
		break;

		//处理其他事件
	default:
		break;
	}
}

实体类(Entity)

Entity.h

#pragma once
#ifndef ENTITY

#include<string>

class Entity {
public:
	Entity() {};
	virtual ~Entity() {};
	bool isHero() const;
    
private:
	std::string type;
}; 

#endif // ENTITY

Entity.cpp

#pragma once
#ifndef ENTITY

#include<string>

class Entity {
public:
	Entity() {};
	Entity(std::string s) {
		type = s;
	};
	virtual ~Entity() {};

	bool isHero() const;

private:
	std::string type;
}; 

#endif // ENTITY

监听事件 (Event)

Event.h

#pragma once
#ifndef EVENT

typedef int Event;
#define EVENT_ENTITY_FALL 10001		//物体下落事件

#endif // !EVENT
  • Event并不是定义的新类,只是对int 类型的一个别名,在Event.h下申明对应的事件ID,不同的Event对应不同的触发事件。

  • 同时当事件很多的时候,我们可以在Event.h中直接看到当前观察的事件类型,而不用去一行行翻具体的执行代码。

  • 此外,我们还可以增加相关的方法,就像cocos引擎的事件分发器那样可以在代码中手动注册监听事件

main方法

main.cpp

#include "Entity.h"
#include "Achievements.h"
#include "Physics.h"

int main() {
	Entity myHero = Entity("hero");		// 定义了一个hero实体
	Physics phySystem = Physics();		// 定义了一个物理系统
	Achievements achSystem = Achievements();	// 定义了一个成就系统
	phySystem.addObserver(&achSystem);		// 让成就系统观察物理系统
	phySystem.updateEntity(myHero, EVENT_ENTITY_FALL);	//hero实体触发了物理系统中的实体下坠事件
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值