游戏中心沙盒问题
Game Center Sandbox issue
我遇到了一个很老的问题,这里已经讨论过很多次了。尽管讨论了很多次这个问题,但我没有找到可接受的解决方案,所以我决定再次提出这个问题。
那么,问题来了。我正在尝试测试回合制比赛。我为此使用了两个真实的设备。我打开第一台设备,匹配数据更新没有错误(我肯定知道),但有时第二台设备没有收到任何通知,而且第一台设备似乎仍在转动。有时它会按预期工作。
换句话说,有时 player(_:receivedTurnEventFor:didBecomeActive)
方法不会被调用。但是,如果我关闭第二台设备上的应用程序,重新打开它并加入现有的比赛,一切正常。
据我了解,这是众所周知的 Game Center 沙盒问题,但在我尝试测试该应用程序时,它让我抓狂。
有人知道解决方法吗?或者也许有一个最佳实践如何使用这种奇怪的沙盒行为来运行和测试应用程序?
更新。
Thunk提出的方法就是一个解决方案。我在 Swift 重写了它并修改以符合我的游戏逻辑。
首先,我定义了全局变量
var gcBugTimer: Timer
在 endTurn(withNextParticipants:turnTimeOut:match:completionHandler:)
完成处理程序中:
let interval = 3.0
self.gcBugTimer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(self.isMatchActive), userInfo: nil, repeats: true)
self.gcBugTimer.tolerance = 1.0
上面的代码也应该被调用,以防一个玩家正在为新的比赛而高兴,而另一个玩家在一个回合中。
然后定时器方法:
func isMatchActive() {
// currentMatch - global variable contains information about current match
GKTurnBasedMatch.load(withID: currentMatch.matchID!) { (match, error) in
if match != nil {
let participant = match?.currentParticipant
let localPlayer = GKLocalPlayer.localPlayer()
if localPlayer.playerID == participant?.player?.playerID {
self.player(localPlayer, receivedTurnEventFor: match!, didBecomeActive: false)
}
} else {
print(error?.localizedDescription ?? "")
}
}
}
然后我在 player(_:receivedTurnEventFor:didBecomeActive)
的开头添加了以下代码:
if gcBugTimer != nil && gcBugTimer.isValid {
gcBugTimer.invalidate()
}
我发现唯一可靠的解决方案是在等待轮到我时手动重新检查我的状态。在 endTurnWithNextParticipants
的完成处理程序中,我设置了一个计时器来不断重新加载匹配数据。我检查了 localPlayer
是否已成为活跃玩家。如果是,那么我自己调用 receivedTurnForEvent
,否则,我重复计时器。像这样:
在 endTurnWithNextParticipants
完成处理程序中:
float dTime = 60.0; //messages sometimes fail in IOS8.4
if (SYSTEM_VERSION_EQUAL_TO(@"8.3") )
{
dTime = 5.0; //messages always fail in IOS8.3
}
IOS8BugTimer = [NSTimer scheduledTimerWithTimeInterval:dTime
target:gameKitHelper
selector:@selector(isMatchActive:)
userInfo:theMatch.matchID
repeats:NO];
并在 gameKitHelper:isMatchActive 中:
-(void)isMatchActive:(NSTimer *)timer
{
NSString *matchID = (NSString *)timer.userInfo;
[GKTurnBasedMatch loadMatchWithID:matchID withCompletionHandler:^(GKTurnBasedMatch *match, NSError *error)
{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
GKTurnBasedParticipant *currentParticipant = match.currentParticipant;
if ([localPlayer.playerID isEqualToString:currentParticipant.player.playerID])
{
//we have become active. Call the event handler like it's supposed to be called
[self player:localPlayer receivedTurnEventForMatch:match didBecomeActive:false];
}
else
{
//we are still waiting to become active. Check back soon
float dTime = 60.0;
if (SYSTEM_VERSION_EQUAL_TO(@"8.3") )
{
dTime = 5.0;
}
gameController.IOS8BugTimer = [NSTimer scheduledTimerWithTimeInterval:dTime
target:self
selector:@selector(isMatchActive:)
userInfo:matchID
repeats:NO];
}
}];
}
我遇到了一个很老的问题,这里已经讨论过很多次了。尽管讨论了很多次这个问题,但我没有找到可接受的解决方案,所以我决定再次提出这个问题。
那么,问题来了。我正在尝试测试回合制比赛。我为此使用了两个真实的设备。我打开第一台设备,匹配数据更新没有错误(我肯定知道),但有时第二台设备没有收到任何通知,而且第一台设备似乎仍在转动。有时它会按预期工作。
换句话说,有时 player(_:receivedTurnEventFor:didBecomeActive)
方法不会被调用。但是,如果我关闭第二台设备上的应用程序,重新打开它并加入现有的比赛,一切正常。
据我了解,这是众所周知的 Game Center 沙盒问题,但在我尝试测试该应用程序时,它让我抓狂。
有人知道解决方法吗?或者也许有一个最佳实践如何使用这种奇怪的沙盒行为来运行和测试应用程序?
更新。
Thunk提出的方法就是一个解决方案。我在 Swift 重写了它并修改以符合我的游戏逻辑。
首先,我定义了全局变量
var gcBugTimer: Timer
在 endTurn(withNextParticipants:turnTimeOut:match:completionHandler:)
完成处理程序中:
let interval = 3.0
self.gcBugTimer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(self.isMatchActive), userInfo: nil, repeats: true)
self.gcBugTimer.tolerance = 1.0
上面的代码也应该被调用,以防一个玩家正在为新的比赛而高兴,而另一个玩家在一个回合中。
然后定时器方法:
func isMatchActive() {
// currentMatch - global variable contains information about current match
GKTurnBasedMatch.load(withID: currentMatch.matchID!) { (match, error) in
if match != nil {
let participant = match?.currentParticipant
let localPlayer = GKLocalPlayer.localPlayer()
if localPlayer.playerID == participant?.player?.playerID {
self.player(localPlayer, receivedTurnEventFor: match!, didBecomeActive: false)
}
} else {
print(error?.localizedDescription ?? "")
}
}
}
然后我在 player(_:receivedTurnEventFor:didBecomeActive)
的开头添加了以下代码:
if gcBugTimer != nil && gcBugTimer.isValid {
gcBugTimer.invalidate()
}
我发现唯一可靠的解决方案是在等待轮到我时手动重新检查我的状态。在 endTurnWithNextParticipants
的完成处理程序中,我设置了一个计时器来不断重新加载匹配数据。我检查了 localPlayer
是否已成为活跃玩家。如果是,那么我自己调用 receivedTurnForEvent
,否则,我重复计时器。像这样:
在 endTurnWithNextParticipants
完成处理程序中:
float dTime = 60.0; //messages sometimes fail in IOS8.4
if (SYSTEM_VERSION_EQUAL_TO(@"8.3") )
{
dTime = 5.0; //messages always fail in IOS8.3
}
IOS8BugTimer = [NSTimer scheduledTimerWithTimeInterval:dTime
target:gameKitHelper
selector:@selector(isMatchActive:)
userInfo:theMatch.matchID
repeats:NO];
并在 gameKitHelper:isMatchActive 中:
-(void)isMatchActive:(NSTimer *)timer
{
NSString *matchID = (NSString *)timer.userInfo;
[GKTurnBasedMatch loadMatchWithID:matchID withCompletionHandler:^(GKTurnBasedMatch *match, NSError *error)
{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
GKTurnBasedParticipant *currentParticipant = match.currentParticipant;
if ([localPlayer.playerID isEqualToString:currentParticipant.player.playerID])
{
//we have become active. Call the event handler like it's supposed to be called
[self player:localPlayer receivedTurnEventForMatch:match didBecomeActive:false];
}
else
{
//we are still waiting to become active. Check back soon
float dTime = 60.0;
if (SYSTEM_VERSION_EQUAL_TO(@"8.3") )
{
dTime = 5.0;
}
gameController.IOS8BugTimer = [NSTimer scheduledTimerWithTimeInterval:dTime
target:self
selector:@selector(isMatchActive:)
userInfo:matchID
repeats:NO];
}
}];
}