- objective-c - iOS 5 : Can you override UIAppearance customisations in specific classes?
- iphone - 如何将 CGFontRef 转换为 UIFont?
- ios - 以编程方式关闭标记的信息窗口 google maps iOS
- ios - Xcode 5 - 尝试验证存档时出现 "No application records were found"
好吧,这涉及到来自 this part of a multiplayer tutorial 的大量网络编码.
基本上,我正在尝试按照上面链接的教程使用 GameKit 实现多人游戏。我输入了所有必要的网络编码并且或多或少地理解了它,但是我在方法调用的某个地方遇到了障碍。基本上,我的设置是一台设备充当主机,其余设备充当客户端。我有两个单独的 UIViewcontroller
,分别用于建立连接的主机和客户端。
现在的问题是,连接已建立,但只有主机可以识别连接,客户端无法识别。问题出在这里:
- (void)sendPacketToAllClients:(Packet *)packet
{
[_players enumerateKeysAndObjectsUsingBlock:^(id key, Player *obj, BOOL *stop)
{
obj.receivedResponse = [_session.peerID isEqualToString:obj.peerID];
}];
GKSendDataMode dataMode = GKSendDataReliable;
NSData *data = [packet data];
NSError *error;
if (![_session sendDataToAllPeers:data withDataMode:dataMode error:&error])
{
NSLog(@"Error sending data to clients: %@", error);
}
}
这在 GameMultiplayer
中实现,实际游戏将在其中实现。这个方法应该做的是向每个客户端发送数据包,表明主机收到了连接请求并且能够与它们连接。 [_session sendDataToAllPeers:data withDataMode:dataMode error:&error]
被调用后(if
语句中的方法),应该会触发这个方法:
- (void)receiveData:(NSData *)data fromPeer:(NSString *)peerID inSession:(GKSession *)session context:(void *)context
{
#ifdef DEBUG
NSLog(@"Game: receive data from peer: %@, data: %@, length: %d", peerID, data, [data length]);
#endif
Packet *packet = [Packet packetWithData:data];
if (packet == nil)
{
NSLog(@"Invalid packet: %@", data);
return;
}
Player *player = [self playerWithPeerID:peerID];
if (player != nil)
{
player.receivedResponse = YES; // this is the new bit
}
if (self.isServer)
[self serverReceivedPacket:packet fromPlayer:player];
else
[self clientReceivedPacket:packet];
}
此方法在我上面链接的教程的下一部分(即 here)中,应该接收主机发送给所有客户端的数据包并在此网络链中实现下一个方法。但是,该方法永远不会被调用。没有触发调试断点,我在控制台中什么也得不到。
我知道我是否需要提供更多源 Material ,但是已经实现了很多网络编码,所以我想把它缩小到人们需要看到的程度。此外,[_session setDataReceiveHandler:self withContext:nil]
和 _session.delegate = self
是在 GameMultiplayer
中调用的另一个方法中编写的,因此那不是问题。有谁知道我需要修复什么?
编辑:根据要求,这里是初始化 GKSession 的地方:
@property (nonatomic, strong, readonly) GKSession *session; //This is done in the header file
@synthesize session = _session; //This is done in the main file
- (void)startAcceptingConnectionsForSessionID:(NSString *)sessionID
{
if (_serverState == ServerStateIdle)
{
_serverState = ServerStateAcceptingConnections;
_connectedClients = [NSMutableArray arrayWithCapacity:self.maxClients];
_session = [[GKSession alloc] initWithSessionID:sessionID displayName:nil sessionMode:GKSessionModeServer];
_session.delegate = self;
_session.available = YES;
}
}
session 在 MatchmakingServer
中初始化,它在主机 View Controller 中使用。然后 session 被传递到应用程序的主视图 Controller ,然后初始化 GameMultiplayer
并将 GKSession 发送给它。这是主机 View Controller 将它发送到主视图 Controller 的地方:
- (IBAction)startAction:(id)sender
{
if (_matchmakingServer != nil && [_matchmakingServer connectedClientCount] > 0)
{
NSString *name = [self.nameTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([name length] == 0)
name = _matchmakingServer.session.displayName;
[_matchmakingServer stopAcceptingConnections];
[self.delegate hostViewController:self startGameWithSession:_matchmakingServer.session playerName:name clients:_matchmakingServer.connectedClients];
}
}
然后主视图 Controller 在这里处理该方法调用:
- (void)hostViewController:(MatchmakerHost *)controller startGameWithSession:(GKSession *)session playerName:(NSString *)name clients:(NSArray *)clients
{
[self dismissViewControllerAnimated:NO completion:^
{
[self startGameWithBlock:^(GameMultiplayer *aGame)
{
[aGame startServerGameWithSession:session playerName:name clients:clients];
}];
}];
}
最后,这是在 GameMultiplayer
中实现该方法调用的地方:
- (void)startServerGameWithSession:(GKSession *)session playerName:(NSString *)name clients:(NSArray *)clients
{
_clients = clients;
const char* className = class_getName([[_clients objectAtIndex:0] class]);
NSLog(@"yourObject is a: %s", className);
self.isServer = YES;
_session = session;
_session.available = NO;
_session.delegate = self;
[_session setDataReceiveHandler:self withContext:nil];
_state = GameStateWaitingForSignIn;
[self.delegate gameWaitingForClientsReady:self];
// Create the Player object for the server.
Player *player = [[Player alloc] init];
player.name = name;
player.peerID = _session.peerID;
player.position = PlayerPositionBottom;
[_players setObject:player forKey:player.peerID];
// Add a Player object for each client.
int index = 0;
for (NSString *peerID in clients)
{
Player *player = [[Player alloc] init];
player.peerID = peerID;
[_players setObject:player forKey:player.peerID];
if (index == 0)
player.position = ([clients count] == 1) ? PlayerPositionTop : PlayerPositionLeft;
else if (index == 1)
player.position = PlayerPositionTop;
else
player.position = PlayerPositionRight;
index++;
}
NSLog(@"Players:");
Packet *packet = [Packet packetWithType:PacketTypeSignInRequest];
[self sendPacketToAllClients:packet];
// for (int i = 0; i < [_players count]; i++) {
// NSLog([NSString stringWithFormat:@"%@", [clients objectAtIndex:i]]);
// }
}
最佳答案
我认为您是在调用 send to fast。当服务器意识到连接时,它会向客户端发送确认以真正建立连接 - 这样客户端就知道连接成功了。
如果您在此之前发送数据包 - 它将会丢失。
只需这样做:
[self performSelector:@selector(sendPacketToAllClients) withObject:nil afterDelay:1.0];
代替:
[self sendPacketToAllClients];
我遇到了同样的问题,即连接是在不同的时刻建立的,客户端的延迟很小。最好的办法是从客户端发送他准备好从服务器接收数据包的第一个数据包 - 而不是从那里正常进行。
也尝试调试:
- (void)session:(GKSession *)session peer:(NSString *)peerID didChangeState:(GKPeerConnectionState)state
在两个设备(服务器和客户端)上。
关于ios - GKSession 和 sendDataToAllPeers 的问题 :withDataMode:error:,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17623414/
我有许多使用 GameKit 通过 wifi 连接的设备。当对等方(客户端)接收数据时,我会弹出一个简单的 UIAlertView 。除了发送者(服务器)之外的所有其他人在发送数据时都会显示此警报 V
我当前的sessionMode是GKSessionModeServer。如果我在客户端,我会执行以下操作: [mySession sendDataToAllPeers:packet withDat
好吧,这涉及到来自 this part of a multiplayer tutorial 的大量网络编码. 基本上,我正在尝试按照上面链接的教程使用 GameKit 实现多人游戏。我输入了所有必要的
我是一名优秀的程序员,十分优秀!