gpt4 book ai didi

c++ - 游戏对象互相交谈

转载 作者:行者123 更新时间:2023-12-02 07:12:20 25 4
gpt4 key购买 nike

关闭。这个问题是opinion-based .它目前不接受答案。












想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题.

2年前关闭。




Improve this question




处理对象并使它们相互交谈的好方法是什么?

到目前为止,我所有的游戏爱好/学生都很小,所以这个问题通常以一种相当丑陋的方式解决,这导致紧密集成和循环依赖。这对于我正在做的项目规模来说很好。

然而,我的项目在规模和复杂性上变得越来越大,现在我想开始重用代码,让我的头脑变得更简单。

我遇到的主要问题通常是Player需要了解的Map Enemy 也是如此,这通常会导致设置大量指针并具有大量依赖项,这很快就会变得一团糟。

我已经按照消息样式系统的思路进行了思考。但我真的看不出这是如何减少依赖性的,因为我仍然会到处发送指针。

PS:我想这之前已经讨论过,但我不知道它叫什么,只是我的需要。

最佳答案

编辑:下面我描述了一个我反复使用的基本事件消息系统。我突然想到,这两个学校项目都是开源的,并且在网络上。您可以在 http://sourceforge.net/projects/bpfat/ 找到此消息传递系统的第二个版本(以及更多版本)。 .. 享受,并阅读下面的系统更详尽的描述!

我编写了一个通用的消息传递系统,并将其引入到一些已在 PSP 上发布的游戏以及一些企业级应用软件中。消息传递系统的重点是仅传递处理消息或事件所需的数据,具体取决于您要使用的术语,以便对象不必相互了解。

用于完成此操作的对象列表的快速纲要大致如下:

struct TEventMessage
{
int _iMessageID;
}

class IEventMessagingSystem
{
Post(int iMessageId);
Post(int iMessageId, float fData);
Post(int iMessageId, int iData);
// ...
Post(TMessageEvent * pMessage);
Post(int iMessageId, void * pData);
}

typedef float(*IEventMessagingSystem::Callback)(TEventMessage * pMessage);

class CEventMessagingSystem
{
Init ();
DNit ();
Exec (float fElapsedTime);

Post (TEventMessage * oMessage);

Register (int iMessageId, IEventMessagingSystem* pObject, FObjectCallback* fpMethod);
Unregister (int iMessageId, IEventMessagingSystem* pObject, FObjectCallback * fpMethod);
}

#define MSG_Startup (1)
#define MSG_Shutdown (2)
#define MSG_PlaySound (3)
#define MSG_HandlePlayerInput (4)
#define MSG_NetworkMessage (5)
#define MSG_PlayerDied (6)
#define MSG_BeginCombat (7)
#define MSG_EndCombat (8)

现在稍微解释一下。第一个对象 TEventMessage 是表示消息传递系统发送的数据的基础对象。默认情况下,它将始终具有正在发送的消息的 ID,因此如果您想确保收到了您期望的消息(通常我只在调试中这样做)。

接下来是 Interface 类,它为消息传递系统提供了一个通用对象,用于在执行回调时进行转换。此外,这还提供了一个“易于使用”的接口(interface),用于将不同的数据类型发布到消息系统。

之后,我们有了回调 typedef,简单地说,它需要一个接口(interface)类类型的对象,并将传递一个 TEventMessage 指针……您可以选择将参数设为 const,但我之前使用过涓流处理,例如消息系统的堆栈调试等。

最后也是核心的是 CEventMessagingSystem 对象。该对象包含一组回调对象堆栈(或链接列表或队列,或者您想要存储数据的任何方式)。上面未显示的回调对象需要维护(并由其唯一定义)指向对象的指针以及调用该对象的方法。当您 Register() 时,您在消息 id 的数组位置下的对象堆栈上添加一个条目。当您 Unregister() 时,您将删除该条目。

基本上就是这样。现在这确实规定了一切都需要了解 IEventMessagingSystem 和 TEventMessage 对象......但是这个对象不应该经常改变,并且只传递对被调用的事件所指示的逻辑至关重要的信息部分。通过这种方式,玩家无需直接了解 map 或敌人即可向其发送事件。托管对象也可以向更大的系统调用 API,而无需了解任何相关信息。

例如:当敌人死亡时,您希望它播放声音效果。假设您有一个继承 IEventMessagingSystem 接口(interface)的声音管理器,您将为消息传递系统设置一个回调,该回调将接受 TEventMessagePlaySoundEffect 或类似的东西。然后,声音管理器会在启用音效时注册此回调(或者当您想将所有音效静音以方便开/关功能时取消注册回调)。接下来,您将让敌人对象也继承自 IEventMessagingSystem,将一个 TEventMessagePlaySoundEffect 对象放在一起(需要 MSG_PlaySound 作为其消息 ID,然后是要播放的音效 ID,无论是 int ID 还是声音名称effect) 并简单地调用 Post(&oEventMessagePlaySoundEffect)。

现在这只是一个非常简单的设计,没有实现。如果您可以立即执行,那么您就不需要缓冲 TEventMessage 对象(我主要在控制台游戏中使用的对象)。如果您处于多线程环境中,那么对于在不同线程中运行的对象和系统而言,这是一种定义非常明确的方式,但您需要保留 TEventMessage 对象,以便在处理时可以使用数据。

另一个改变是对于只需要 Post() 数据的对象,您可以在 IEventMessagingSystem 中创建一组静态方法,这样它们就不必从它们继承(这是为了便于访问和回调能力,而不是直接- Post() 调用需要)。

对于所有提到 MVC 的人来说,这是一个非常好的模式,但是您可以以多种不同的方式在不同的层次上实现它。我目前从事的专业项目是 MVC 设置大约 3 倍,有整个应用程序的全局 MVC,然后明智地设计每个 MV 和 C 也是一个自包含的 MVC 模式。所以我在这里试图做的是解释如何制作一个足够通用的 C 来处理几乎任何类型的 M 而不需要进入 View ......

例如,一个对象在它“死亡”时可能想要播放声音效果。您可以为声音系统创建一个结构,例如 TEventMessageSoundEffect 继承自 TEventMessage 并添加声音效果 ID(无论是预加载的 Int,还是sfx 文件的名称,但是它们在您的系统中被跟踪)。然后所有的对象只需要将一个 TEventMessageSoundEffect 对象与适当的死亡噪音放在一起并调用 Post(&oEventMessageSoundEffect);对象.. 假设声音没有静音(您想要取消注册声音管理器。

编辑:为了澄清这一点关于下面的评论:
任何发送或接收消息的对象只需要知道 IEventMessagingSystem 接口(interface),这是 EventMessagingSystem 需要知道所有其他对象的唯一对象。这就是给你超脱的原因。任何想要接收消息的对象只需为其注册(MSG,对象,回调)。然后当一个对象调用 Post(MSG,Data) 时,它通过它知道的接口(interface)将它发送到 EventMessagingSystem,然后 EMS 将通知每个注册的对象该事件。您可以执行其他系统处理的 MSG_PlayerDied,或者玩家可以调用 MSG_PlaySound、MSG_Respawn 等,让监听这些消息的事物对它们采取行动。将 Post(MSG,Data) 视为游戏引擎中不同系统的抽象 API。

哦!向我指出的另一件事。我上面描述的系统符合给出的另一个答案中的观察者模式。所以如果你想要一个更一般的描述让我的描述更有意义,那是一篇很好的描述的简短文章。

希望这有助于和享受!

关于c++ - 游戏对象互相交谈,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4574016/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com