SDL2 游戏开发日记(七) 自定义消息

SDL2 游戏开发日记(七) 自定义消息

在游戏中,有各种各样的消息,除了鼠标键盘等控制消息之外。游戏物体也会产生各种各样的消息,有些消息是需要立即处理的。有些消息需要过了一段时间后才会被处理。

例如在单机麻将游戏中,玩家出牌的消息要通知其他ai玩家,出了什么牌,其他玩家收到消息后,则需要判断这个牌有需不需要,是否碰/杠/胡等。

玩家出牌后,其他ai玩家不能立即摸牌,需要等待2秒后才能摸牌。

消息接收处理类

#pragma once
#include <cassert>

struct GameMessage;

class MessageListener{
protected:
	int mID;
	static int mNextVaildID;
public:
	MessageListener(){
		SetID(MessageListener::NextVaildID());
	}
	MessageListener(int id){
		SetID(id);
	}
	virtual ~MessageListener(){

	}
	int ID(){
		return mID;
	}
	void SetID(int id){
		assert(id >= mNextVaildID && "MessageListener invaild id");
		mID = id;
		mNextVaildID = id + 1;
	}

	static int NextVaildID(){
		return mNextVaildID;
	}
	//消息处理
	virtual bool OnMessage(const GameMessage &msg){ return false; }
};

消息结构#

#pragma once
#include "MessageListener.h"
#include <math.h>
const float smallestDelay = 0.1f;
struct GameMessage{
	//消息的发送端
	void *Sender;
	//消息的接收端
	MessageListener *Receiver;
	//消息类型
	int message;
	//消息发送时间,延时消息用
	float DispatchTime;
	//扩展数据
	void *ExtraInfo;
	
	GameMessage(){
		Sender = 0;
		Receiver = 0;
		message = -1;
		DispatchTime = 0;
		ExtraInfo = 0;
	}
	GameMessage(float time, void *sender, MessageListener *receiver, int msg, void *extraInfo = 0){
		DispatchTime = time;
		Sender = sender;
		Receiver = receiver;
		message = msg;
		ExtraInfo = extraInfo;
	}
};

//重载运算符,放到set容器中时自动排序。
inline bool operator ==(const GameMessage &m1,const GameMessage &m2){
	return fabs(m1.DispatchTime - m2.DispatchTime) <= smallestDelay &&
		(m1.Sender == m2.Sender) &&
		(m1.Receiver == m2.Receiver) &&
		(m1.message == m2.message) && (m1.ExtraInfo == m2.ExtraInfo);
}

inline bool operator <(const GameMessage &m1,const GameMessage &m2){
	if (m1 == m2){
		return false;
	}
	else{
		return m1.DispatchTime < m2.DispatchTime;
	}
}

消息管理和分发

单例模式

#pragma once
#include <set>

#include "GameMessage.h"

#define Dispatcher MessageDispatcher::Instance()

class MessageDispatcher{
private:
	//游戏运行时间
	float mTimeElapse;
	//游戏运行帧数
	long mFrameCount;
	//延时消息队列
	std::set<GameMessage> mMessageQueue;
	
	MessageDispatcher():mTimeElapse(0.0f),mFrameCount(0){};
	MessageDispatcher(const MessageDispatcher&);
	MessageDispatcher& operator=(const MessageDispatcher&);
public:
	static MessageDispatcher &Instance(){
		static MessageDispatcher instance;
		return instance;
	}
	//发送消息
	void DispatchMsg(float delay, void *sender, MessageListener *receiver, int message, void* extraInfo = NULL);
	
	//处理延时消息
	void DispatchDelayedMessages(float time_step);
};


#include "MessageDispatcher.h"
#include "MessageListener.h"
#include "GameMessage.h"
//发送消息
void MessageDispatcher::DispatchMsg(float delay, void *sender, MessageListener *receiver, int message, void* extraInfo){
	if (receiver == NULL)
		return;
	
	GameMessage msg(0, sender, receiver, message, extraInfo);
	//如果不是延时消息,receiver立即处理。
	if (delay <= 0.0f){
		receiver->OnMessage(msg);
	}
	else{
		//延时消息,发送时间为当前时间加上延时时间。
		msg.DispatchTime = mTimeElapse + delay;
		mMessageQueue.insert(msg);
	}
}

//处理延时消息,游戏主循环中每帧调用一次。
void MessageDispatcher::DispatchDelayedMessages(float time_step){
	float currentTimeElapse = mTimeElapse;
	while (!mMessageQueue.empty() &&
		(mMessageQueue.begin()->DispatchTime <= currentTimeElapse)){

		const GameMessage &message = *(mMessageQueue.begin());
		message.Receiver->OnMessage(message);

		mMessageQueue.erase(mMessageQueue.begin());
	}
	mTimeElapse += time_step;
	mFrameCount++;
}
发布了9 篇原创文章 · 获赞 0 · 访问量 1026

猜你喜欢

转载自blog.csdn.net/drizzlemao/article/details/104430125