这是我第一次在游戏中实现匹配。我正在使用 cocos2d-x v3.x 框架。游戏是用C++编写的,我也在利用苹果的GameKit框架(Objective-C)。
我从一开始就遵循Ray Wenderlich的教程:http://tinyurl.com/j8uoftg
我想知道是否有人遇到过我遇到的同样问题。我将在下面显示主要问题。任何帮助或建议将不胜感激...
首先,我在 cocos2d-x (MultiPlayer.mm) 中在 init 上设置匹配:
bool MultiPlayer::init() {
// super init first
if (!Layer::init()) {return false;}
//...
[[MultiPlayerLayer sharedManager] setUpGame];
}
里面 MultiPlayerLayer.mm...
-(id) init {
if( (self=[super init])) {}
return self;
}
- (void)setUpGame {
isPlayer1 = YES;
AppController *delegate = (AppController *) [UIApplication sharedApplication].delegate;
[[GCHelper sharedInstance] findMatchWithMinPlayers:2 maxPlayers:2 viewController:delegate.viewController delegate:self];
ourRandom = arc4random();
[self setGameState:kGameStateWaitingForMatch];
}
游戏中心方面一切顺利。我现在被提示玩游戏,游戏中心会查找玩家。找到玩家后,将通知代表比赛可以开始 (GCHelper.m):
- (void)lookupPlayers {
// a few lines later...
matchStarted = YES;
[delegate matchStarted];
}
现在我们又回到了 MultiPlayerLayer.mm...
- (void)matchStarted {
printf("Match startednn");
if (receivedRandom) {
[self setGameState:kGameStateWaitingForStart];
} else {
[self setGameState:kGameStateWaitingForRandomNumber];
}
[self sendRandomNumber];
[self tryStartGame];
}
当发送 sendRandomNumber 消息时,我们通过生成一个随机数(顺便说一句,它正在工作)来确定谁是玩家 1 和玩家 2:
- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID {
// Store away other player ID for later
if (otherPlayerID == nil) {
otherPlayerID = [playerID retain];
}
Message *message = (Message *) [data bytes];
if (message->messageType == kMessageTypeRandomNumber) {
MessageRandomNumber * messageInit = (MessageRandomNumber *) [data bytes];
printf("Received random number: %ud, ours %udnn", messageInit->randomNumber, ourRandom);
bool tie = false;
if (messageInit->randomNumber == ourRandom) {
printf("TIE!nn");
tie = true;
ourRandom = arc4random();
[self sendRandomNumber];
} else if (ourRandom > messageInit->randomNumber) {
printf("We are player 1nn");
isPlayer1 = YES;
} else {
printf("We are player 2nn");
isPlayer1 = NO;
}
if (!tie) {
receivedRandom = YES;
if (gameState == kGameStateWaitingForRandomNumber) {
[self setGameState:kGameStateWaitingForStart];
}
[self tryStartGame];
}
}
// ...
}
然后我们尝试开始游戏。因此,如果我是玩家 1 并等待,我们将游戏状态设置为活动,设置字符串(获取另一个玩家 ID)并向另一方发送消息以开始游戏:
- (void)tryStartGame {
if (isPlayer1 && gameState == kGameStateWaitingForStart) {
[self setGameState:kGameStateActive];
[self sendGameBegin];
[self setupStringsWithOtherPlayerId:otherPlayerID];
}
}
当发送 sendGameBegin 消息时,我们将另一端的状态设置为活动并设置玩家 ID 字符串:
- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID {
// Store away other player ID for later
if (otherPlayerID == nil) {
otherPlayerID = [playerID retain];
}
Message *message = (Message *) [data bytes];
if (message->messageType == kMessageTypeRandomNumber) {
// ...
} else if (message->messageType == kMessageTypeGameBegin) {
[self setGameState:kGameStateActive];
[self setupStringsWithOtherPlayerId:playerID];
}
// ...
}
好的,现在我们回到了cocos2d-x类(MultiPlayer.mm)。在这个类中,我在设置多人游戏之前调用了this->scheduleUpdate();
。update 方法每帧调用一次,并检查游戏状态是否处于活动状态:
// game loop
void MultiPlayer::update(float fDelta) {
if ([[MultiPlayerLayer sharedManager] gameStateIsActive] && (!namesSet)) {
// set names
player1ID->setString([[[MultiPlayerLayer sharedManager] getPlayer1ID] UTF8String]);
player1ID->setPosition(Vec2((player1ID->getContentSize().width / 2) + origin.x, heartPosY - 50));
player1ID->setColor(Color3B::BLACK);
player2ID->setString([[[MultiPlayerLayer sharedManager] getPlayer2ID] UTF8String]);
player2ID->setPosition(Vec2((visibleSize.width + origin.x) - (player2ID->getContentSize().width / 2), heartPosY - 50));
player2ID->setColor(Color3B::BLACK);
namesSet = true;
}
// ...
}
我的其余代码似乎工作正常。当我在两台设备上测试我的游戏时,第一个匹配游戏工作正常。选择玩家 1 和玩家 2,字符串(玩家 ID)作为我创建的标签显示在屏幕上。我可以分辨出玩家 1 和玩家 2 之间的区别,并且消息发送工作正常。当游戏结束时,我显示获胜者的玩家ID,然后等待输入。收到输入(点击屏幕)后,玩家设备上的比赛将断开连接。例如,如果玩家 1 先点击屏幕,则玩家 1 断开连接并返回到主菜单。玩家 2 仍将在游戏中,直到他们选择断开与比赛的连接。这是我在控制台中收到的输出(对于我玩的第一个游戏):
Setting up game...
Waiting for match
Received random number: 2119557985d, ours 1863796654d
We are player 2
Match started
Waiting for start
Active
plugin com.apple.GameCenterUI.GameCenterMatchmakerExtension invalidated
Suspended
Waiting for game over
Match ended
Done
这是 MultiPlayer.mm 中等待结束匹配的方法:
void MultiPlayer::waitForGameOver(float dt) {
// wait for user interaction
if (userDefault->getBoolForKey("gameOverResults-MultiPlayer")) {
// unschedule
this->unschedule(schedule_selector(MultiPlayer::waitForGameOver));
// end game, return to play menu
[[MultiPlayerLayer sharedManager] matchEnded];
}
}
在 MultiPlayerLayer.mm...
- (void)matchEnded {
[self setGameState:kGameStateDone];
[[GCHelper sharedInstance].match disconnect];
[GCHelper sharedInstance].match = nil;
// this function replaces the scene in cocos2d-x
// and returns the player to the main menu
goBack();
}
更多信息:我正在使用 extern"C"作为我在 MultiPlayerLayer.mm 内部调用的C++函数。现在,当比赛断开连接时,玩家返回主菜单,一切都很好。我再次测试我的游戏,并在"第二次"时间再次开始匹配。这是一切都出错的时候。这是我在控制台中收到的输出(对于我玩的"SECOND"游戏):
Setting up game...
Waiting for match
Received random number: 1726927477d, ours 1604807545d
We are player 2
Active
Match started
Waiting for start
plugin com.apple.GameCenterUI.GameCenterMatchmakerExtension invalidated
Game is not active yet. // <- I am unable to play because the game is not active
这是我玩的另一个"第二"游戏,我玩了一个不同的问题。它将游戏状态设置为活动两次。此外,在我的设备上,我以玩家 1 的身份玩游戏,在我的第二个测试设备上,我以玩家 1 的身份玩游戏:
Setting up game...
Waiting for match
Received random number: 588896416d, ours 3091892431d
We are player 1
Active
Match started
Waiting for start
Active
plugin com.apple.GameCenterUI.GameCenterMatchmakerExtension invalidated
我对为什么会发生这种情况感到非常困惑。它总是在第一场比赛中起作用,然后在那之后就不起作用了。有谁知道这是否是游戏中心端的问题,或者比赛结束后设备中存储了一些东西需要在第二场比赛开始之前发布,或者只是在游戏状态处于活动状态之前设置玩家人数的问题?谢谢。
终于解决了:
- (void)matchEnded {
[self setGameState:kGameStateDone];
[[GCHelper sharedInstance].match disconnect];
[GCHelper sharedInstance].match = nil;
// release
[otherPlayerID release];
otherPlayerID = nil;
isPlayer1 = NO;
receivedRandom = NO;
// this function replaces the scene in cocos2d-x
// and returns the player to the main menu
goBack();
}