RakNet--NetworkIDObject
![]() |
NetworkIDObject 和NetworkIDManager类允许使用普通的ID查询指针
NetworkIDOjbect类是一个可选类,可以将自己的类从这个类派生,那么你的类就自动赋值标识数字(NetworkID)。这种方法对于多玩家游戏特别有用,否则你必须有自己的方法动态的访问远端系统上分配的对象。 在RakNet 4中,NetworkID是8字节长的全局唯一数字,随机选择。旧版本的RakNet要求中心授权者(服务器)赋值NetworkIDs。这种方法已经废弃了,因为如果游戏是端到到(p2p)的形式,或者有多个分布式的服务器存在,那么编程人员创建这个ID号就非常困难。如果客户端要创建一个对象,也要增加额外的很多工作。因为客户端必须先赋值一个临时的ID,然后从服务器请求真实的NetworkID,然后才可以将它赋值给这个客户端创建的对象。
NetworkIDObject类提供了如下的函数:
SetNetworkIDManager( NetworkIDManager * manager)
NetworkIDManager保存了一个NetworkID的列表用于查询。因此,这就要求你在调用GetNetworkID()或SetNetworkID() 之前调用SetNetworkIDManager()。List不能简单设置为静态的,原因是你或许想要多个NetworkIDManager,例如如果你想要启动多个游戏,它们之间没有任何的交互,如果设置为静态,就会出现错误。
NetworkID GetNetworkID(void)
如果 SetNetworkID() 在前面调用了,这个函数就会返回NetworkID值。否则它为对象生成一个新的,推测是唯一的NetworkID。本质上说,对象只有在调用了GetNetworkID()时才会真正为这个对象赋值一个NetworkID。在客户端/服务器应用下,如果所有的对象依旧是由服务器创建的,那么就不需要客户端生成NetworkID。
SetNetworkID( NetworkID id)
给对象赋值一个NetworkID。用到这个方法的例子就是服务器创建新的游戏对象,广播对象的数据到客户端。客户端会创建一个相同时间的类,读取在用户消息中编码的NetworkID,在同一个对象上调用SetNetworkID()方法。 NetworkIDManager类仅仅有一个用户函数: template < class returnType> returnType GET_OBJECT_FROM_ID(NetworkID x);
这是一个模板函数,因此你可以如下一样写代码:
Solider * solider = networkIDManager.GET_OBJECT_FROM_ID<Solider *>(networkId);
如下是一个将指针存储到类的一个例子,重新检索出来,使用Assert确保有效工作(不出现错误): class Solider : public NetworkIDObject{} int main(void) { NetworkIDManager networkIDManager; Solider * solider = new Solider; solider->SetNetworkIDManager(&networkIDManager); NetworkID soliderNetworkID = solider->GetNetworkID(); Assert(networkIDManager.GET_OBJECT_FROM_ID<Solider ->(soliderNetworkID)== solider); }
如下是一个例子,使用系统创建一个远端系统上的对象,将同一个ID值赋给两者: Server:
void CreateSoldier(void) { Soldier *soldier = new Soldier; soldier->SetNetworkIDManager(&networkIDManager); RakNet::BitStream bsOut; bsOut.Write((MessageID)ID_CREATE_SOLDIER); bsOut.Write(soldier->GetNetworkID()); rakPeerInterface->Send(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,UNASSIGNED_SYSTEM_ADDRESS,true); }
Client:
Packet *packet = rakPeerInterface->Receive(); if (packet->data[0]==ID_CREATE_SOLDIER) { RakNet::BitStream bsIn(packet->data, packet->length, false); bsIn.IgnoreBytes(sizeof(MessageID)); NetworkID soldierNetworkID; bsIn.Read(soldierNetworkID); Soldier *soldier = new Soldier; soldier->SetNetworkIDManager(&networkIDManager); soldier->SetNetworkID(soldierNetworkID); }
静态对象: 有时候对象并不是动态创建的,而是在所有的系统上都已经存在了,所有的系统提前都知道了。例如,如果你在标记地图上有一个获取物,带有三个标记,这三个标记或许是硬编码进关卡设计中的,因此当游戏加载关卡信息的时候,这些数据就直接加载进了游戏。这些是静态对象,NetworkIDManager也是可以访问的。使得这些对象从NetworkIDObject对象派生出来,如同创建动态对象一样,调用SetNetworkIDManager。然后只需要给你的对象赋值一个唯一的ID即可。ID是什么并不重要,只要它是唯一的就好,那么你可以给flag1赋值ID 0,flag2 赋值 ID 1 以及给flag 3 赋值ID 2。这都没有问题。
// 所有的NetworkID在这里增加 enum StaticNetworkIDs { CTF_FLAG_1, CTF_FLAG_2, CTF_FLAG_3, }; class Flag : public NetworkIDObject { // 关卡设计者给标记命名flag1, flag2, 或flag3都可以, // 地图在其他系统也是以相似方式加载 Flag(std::string flagName, NetworkIDManager *networkIDManager) { SetNetworkIDManager(networkIDManager); if (flagName=="flag1") SetNetworkID(CTF_FLAG_1); else if (flagName=="flag2") SetNetworkID(CTF_FLAG_2); else if (flagName=="flag3") SetNetworkID(CTF_FLAG_3); };
|
![]() |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步