iphone4字体大小 邮件 字太小

翻译这篇文章的第一部分时,真的差点要了我的命,字太小,文章又太长,看得我眼睛都花了。早知道找一篇简单短小的来练练手了。苦于我翻译水平有点差,很多东西只知道意思,但是不知道怎么表达出来,这些乱写一通的你们就凑合着看吧,代码应该没有什么错误,意思也大概能明白,原理应该准确,总之就是如果你的基础知识还行的话,只看我翻译的应该是没有问题的。好了,现在献上该教程的第二部分,同样还是那么的长,就像裹脚布一样,不过要是你真的有这方面的需要,应该不是又臭又长的。啰啰嗦嗦的说了这么多,就先来个免责声明吧,虽然不会被熊猫跨省,但有可能会被奥巴马跨国就不好了。
免责申明(必读!):本博客提供的所有教程的翻译原稿均来自于互联网,仅供学习交流之用,切勿进行商业传播。同时,转载时不要移除本申明。如产生任何纠纷,均与本博客所有人、发表该翻译稿之人无任何关系。谢谢合作!
原文在这,不想看我狗屁不通的译文,可以去看看原文吧
这是介绍如何使用服务器来创建系列教程的第二部分,使用来配对游戏。在第一部分中,我们介绍了如何通过GameCenter认证,使用Python和Twisted建立一个简单的服务器,通过NSInputStream和NSOutputStream接收和发送数据,编组和解组数据。在这一部分中,我们将完善这个游戏的,获得完整的功能!我们将创建一场比赛,最终能让你移动角色来让他们赛跑。这篇教程需要有上一部分的基础,如果你还没有看上一部分,你应该去学习一下。
开始一场比赛
为了实现这一点,GameCenter已经存储所有玩家的列表。我们要做的就是把它发送到我们的服务器,创建一个游戏实例让玩家参加。为了能简单明了的说明,我们就称游戏实例为比赛吧。好了,我们只需从客户端发送一个”match started”的消息,告诉服务器玩家的ID,服务器将设置比赛实例,将”match started”的消息发送给各客户端,告诉他们,去吧。。。
我们就让客户端能发送MessageStartMatch消息吧,在NetworkController.m做如下变动
// Add to end of MessageType enum
MessageStartMatch,
MessageMatchStarted,
// After sendPlayerConnected
- (void)sendStartMatch:(NSArray *)players {
[self setState:NetworkStatePendingMatchStart];
MessageWriter * writer = [[[MessageWriter alloc] init] autorelease];
[writer writeByte:MessageStartMatch];
[writer writeByte:players.count];
for(NSString *playerId in players) {
[writer writeString:playerId];
[self sendData:writer.data];
// In matchmakerViewController:didFindPlayers, after the TODO
[self sendStartMatch:playerIDs];
这是一个很简单的东西,当matchmaker找到一个比赛,我们就调用- (void)sendStartMatch方法,它将发送玩家数以及玩家的ID。现在到编辑服务端的CatRaceServer.py,做如下的更改
// After MESSAGE_NOT_IN_MATCH constant
MESSAGE_START_MATCH = 2
MESSAGE_MATCH_STARTED = 3
MATCH_STATE_ACTIVE = 0
MATCH_STATE_GAME_OVER = 1
// Add before CatRacePlayer
class CatRaceMatch:
def __init__(self, players):
self.players = players
self.state = MATCH_STATE_ACTIVE
def __repr__(self):
return "%d %s" % (self.state, str(self.players))
def write(self, message):
message.writeByte(self.state)
message.writeByte(len(self.players))
for matchPlayer in self.players:
matchPlayer.write(message)
// Add new method to CatRaceFactory
def startMatch(self, playerIds):
matchPlayers = []
for existingPlayer in self.players:
if existingPlayer.playerId in playerIds:
if existingPlayer.match != None:
matchPlayers.append(existingPlayer)
match = CatRaceMatch(matchPlayers)
for matchPlayer in matchPlayers:
matchPlayer.match = match
matchPlayer.protocol.sendMatchStarted(match)
// Add new methods to CatRaceProtocol
def sendMatchStarted(self, match):
message = MessageWriter()
message.writeByte(MESSAGE_MATCH_STARTED)
match.write(message)
self.log("Sent MATCH_STARTED %s" % (str(match)))
self.sendMessage(message)
def startMatch(self, message):
numPlayers = message.readByte()
playerIds = []
for i in range(0, numPlayers):
playerId = message.readString()
playerIds.append(playerId)
self.log("Recv MESSAGE_START_MATCH %s" % (str(playerIds)))
self.factory.startMatch(playerIds)
// Add inside processMessage after return self.playerConnected(message)
if messageId == MESSAGE_START_MATCH:
return self.startMatch(message)
在这里最重要的就是startMatch方法——它会根据每个玩家的ID寻找他们的信息,并为玩家创建比赛对象,然后对每个玩家发送一条”match started”的消息。至于其他的方法,就是编组、解组消息,和存储比赛状态。现在回到Xcode,我们将创建一些类来处理玩家和游戏状态。新建一个NSObject子类,命名为Player.m,打开Player.h,替换为以下内容
#import &Foundation/Foundation.h&
@interface Player : NSObject {
NSString * _playerId;
NSString * _
int _posX;
@property (retain) NSString *playerId;
@property (retain) NSString *
- (id)initWithPlayerId:(NSString*)playerId alias:(NSString*)alias posX:(int)posX;
这些都似曾相识吧,没什么特别的,我就不让你们费心看我的解释了。然后,打开Player.m,改为以下内容
#import "Player.h"
@implementation Player
@synthesize playerId = _playerId;
@synthesize alias = _
@synthesize posX = _posX;
- (id)initWithPlayerId:(NSString*)playerId alias:(NSString*)alias posX:(int)posX
if ((self = [super init])) {
_playerId = [playerId retain];
_alias = [alias retain];
_posX = posX;
- (void)dealloc
[_playerId release];
_playerId =
[_alias release];
[super dealloc];
现在,让我们重复以上的再新建一个match类,命名为Match.m,把Match.h替换为以下内容
#import &Foundation/Foundation.h&
typedef enum {
MatchStateActive = 0,
MatchStateGameOver
@interface Match : NSObject {
MatchState _
NSArray * _
@property (retain) NSArray *
- (id)initWithState:(MatchState)state players:(NSArray*)
同样的,把Match.m改成下面这个样子
#import "Match.h"
@implementation Match
@synthesize state = _
@synthesize players = _
- (id)initWithState:(MatchState)state players:(NSArray*)players
if ((self = [super init])) {
_players = [players retain];
- (void)dealloc
[_players release];
_players =
[super dealloc];
现在我们有了这些辅助类后,切换到NetworkController.h,添加以下的东西
// Add before @protocol
// Add inside @protocol
- (void)matchStarted:(Match *)
在这里我们添加了一个新的方法,当比赛开始时,委托就会通知调这个方法。现在,切换到NetworkController.m,我们来处理”match started”消息
// Add to top of file
#import "Match.h"
#import "Player.h"
// Add to end of processMessage
else if (msgType == MessageMatchStarted) {
[self setState:NetworkStateMatchActive];
[self dismissMatchmaker];
unsigned char matchState = [reader readByte];
NSMutableArray * players = [NSMutableArray array];
unsigned char numPlayers = [reader readByte];
for(unsigned char i = 0; i & numP ++i) {
NSString *playerId = [reader readString];
NSString *alias = [reader readString];
int posX = [reader readInt];
Player *player = [[[Player alloc] initWithPlayerId:playerId alias:alias posX:posX] autorelease];
[players addObject:player];
Match * match = [[[Match alloc] initWithState:matchState players:players] autorelease];
[_delegate matchStarted:match];
这只是简单的解析一下玩家和比赛的数据,然后转发给委托。最后,打开HelloWorldLayer.h,并进行以下更改
// Add before @interface
// Add inside @interface
CCLabelBMFont *player1L
CCLabelBMFont *player2L
// Add after interface
@property (retain) Match *
还有,最后再对HelloWorldLayer.m添加这些东西
// Add to top of file
#import "Match.h"
#import "Player.h"
// Add after @implementation
// Replace update with the following
- (void)update:(ccTime)dt {
player1Label.position = player1.
player2Label.position = player2.
// Add before dealloc
- (void)matchStarted:(Match *)theMatch {
self.match = theM
Player *p1 = [match.players objectAtIndex:0];
Player *p2 = [match.players objectAtIndex:1];
if ([p1.playerId compare:[GKLocalPlayer localPlayer].playerID] == NSOrderedSame) {
isPlayer1 = YES;
isPlayer1 = NO;
player1.position = ccp(p1.posX, player1.position.y);
player2.position = ccp(p2.posX, player2.position.y);
player1.moveTarget = player1.
player2.moveTarget = player2.
if (player1Label) {
[player1Label removeFromParentAndCleanup:YES];
player1Label =
player1Label = [CCLabelBMFont labelWithString:p1.alias fntFile:@"Arial.fnt"];
[self addChild:player1Label];
if (player2Label) {
[player2Label removeFromParentAndCleanup:YES];
player2Label =
player2Label = [CCLabelBMFont labelWithString:p2.alias fntFile:@"Arial.fnt"];
[self addChild:player2Label];
现在你终于看到了最重要的东西,- (void)matchstarted方法。它会选出哪个玩家是player1,他还更新玩家的位置和名字的标签。编译并运行,还要重启你的服务器和客户端,好了,现在你的比赛已经激活了。
呼~~~现在我们终于可以看到有乐趣的一部分了——在网络中移动玩家!像上次一样,让我们从客户端向服务端发送消息开始。在NetworkController.h添加一个新的方法
- (void)sendMovedSelf:(int)posX;
然后,在NetworkController.m中实现它
// Add to MessageType enum
MessageMovedSelf,
MessagePlayerMoved,
MessageGameOver,
// Add after sendStartMatch
- (void)sendMovedSelf:(int)posX {
MessageWriter * writer = [[[MessageWriter alloc] init] autorelease];
[writer writeByte:MessageMovedSelf];
[writer writeInt:posX];
[self sendData:writer.data];
切换到HelloWorldLayer.m,在- (void)ccTouchesBegan中调用上面的方法
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (match == nil || match.state != MatchStateActive)
// Move the appropriate player forward a bit
if (isPlayer1) {
[player1 moveForward];
posX = player1.moveTarget.x;
[player2 moveForward];
posX = player2.moveTarget.x;
[[NetworkController sharedInstance] sendMovedSelf:posX];
现在,让我们在服务端处理这些消息并做出回应。在CatRaceServer.py中做以下的更改
// Add in MESSAGE constants section
MESSAGE_MOVED_SELF = 4
MESSAGE_PLAYER_MOVED = 5
MESSAGE_GAME_OVER = 6
PLAYER_WIN_X = 445
// Add new method in CatRaceMatch
def movedSelf(self, posX, player):
if (self.state == MATCH_STATE_GAME_OVER):
player.posX = posX
if (player.posX &= PLAYER_WIN_X):
self.state = MATCH_STATE_GAME_OVER
for matchPlayer in self.players:
if (matchPlayer.protocol):
matchPlayer.protocol.sendGameOver(player.match.players.index(player))
for i in range(0, len(self.players)):
matchPlayer = self.players[i]
if matchPlayer != player:
if (matchPlayer.protocol):
matchPlayer.protocol.sendPlayerMoved(i, posX)
// Add new methods to CatRaceProtocol
def sendPlayerMoved(self, playerIndex, posX):
message = MessageWriter()
message.writeByte(MESSAGE_PLAYER_MOVED)
message.writeByte(playerIndex)
message.writeInt(posX)
self.log("Sent PLAYER_MOVED %d %d" % (playerIndex, posX))
self.sendMessage(message)
def sendGameOver(self, winnerIndex):
message = MessageWriter()
message.writeByte(MESSAGE_GAME_OVER)
message.writeByte(winnerIndex)
self.log("Sent MESSAGE_GAME_OVER %d" % (winnerIndex))
self.sendMessage(message)
def movedSelf(self, message):
posX = message.readInt()
self.log("Recv MESSAGE_MOVED_SELF %d" % (posX))
self.player.match.movedSelf(posX, self.player)
// Add to processMessage, right before self.log(...)
# Match specific messages
if (self.player == None):
self.log("Bailing - no player set")
if (self.player.match == None):
self.log("Bailing - no match set")
if messageId == MESSAGE_MOVED_SELF:
return self.movedSelf(message)
这里重要的是movedSelf方法。它会更新每个玩家的位置,并判断是否游戏结束。如果已经决出胜负,它会给每个玩家发送一条Over的消息,否则,它会告诉玩家们尽管移动并发送新的玩家位置。好的,让我们在客户端中添加处理服务端回应的代码吧。在NetworkController.h添加以下代码
// Add new methods to @protocol
- (void)player:(unsigned char)playerIndex movedToPosX:(int)posX;
- (void)gameOver:(unsigned char)winnerI
还有,对NetworkController.m做出下边的变动
else if (msgType == MessagePlayerMoved && _state == NetworkStateMatchActive) {
unsigned char playerIndex = [reader readByte];
int posX = [reader readInt];
[_delegate player:playerIndex movedToPosX:posX];
} else if (msgType == MessageGameOver && _state == NetworkStateMatchActive) {
unsigned char winnerIndex = [reader readByte];
[_delegate gameOver:winnerIndex];
在这它会解析每个回应并转发给委托。到PlayerSprite.h中添加一点东西
- (void)moveTo:(CGPoint)moveTo;
然后切换到PlayerSprite.h中,删掉原来的- (void)moveTo方法,并添加以下的内容
- (void)moveTo:(CGPoint)moveTo {
// Animate player if he isn't already
if (!isMoving) {
isMoving = YES;
[self runAction:animateAction];
// Stop old move sequence
[self stopAction:moveAction];
// Figure new position to move to and create new move sequence
moveTarget = moveTo; //ccpAdd(moveTarget, ccp(10, 0));
CCMoveTo *moveToAction = [CCMoveTo actionWithDuration:0.5 position:moveTarget];
CCCallFunc *callFuncAction = [CCCallFunc actionWithTarget:self selector:@selector(moveDone)];
moveAction = [CCSequence actions:moveToAction, callFuncAction, nil];
// Run new move sequence
[self runAction:moveAction];
- (void)moveForward {
CGPoint moveTo = ccpAdd(moveTarget, ccp(10, 0));
[self moveTo:moveTo];
最后,切换到HelloWorldLayer.m,做以下的更改
// Add to bottom of file
- (void)player:(unsigned char)playerIndex movedToPosX:(int)posX {
// We know if we receive this it's the other guy, so here's a shortcut
if (isPlayer1) {
[player2 moveTo:CGPointMake(posX, player2.position.y)];
[player1 moveTo:CGPointMake(posX, player1.position.y)];
- (void)gameOver:(unsigned char)winnerIndex {
match.state = MatchStateGameO
if ((winnerIndex == 0 && isPlayer1) ||
(winnerIndex != 0 && !isPlayer1)) {
[self endScene:kEndReasonWin];
[self endScene:kEndReasonLose];
它些改动你应该明白,就是它了,编译并运行你的代码,你终于有一个真正的网络游戏,而且是托管在自己的服务器上!
接近结束:处理重新开始和继续游戏
现在,当你赢了某场比赛后,你点击restart,并没有任何的反应,这是因为我们根本没有写入通知服务端重新开始比赛的任何代码。还有,如果你退出了程序后再进入,服务端仍然会认为你还在比赛中,并不会更新你正确的比赛状态。所以,让我们先来解决这两个问题。像平常一样,我们先从客户端开刀,把下边这个新的方法加入到NetworkController.h中
- (void)sendRestartM
然后在NetworkController.h中实现他
// Add new MessageType
MessageRestartMatch,
// Add right after sendMovedSelf
- (void)sendRestartMatch {
MessageWriter * writer = [[[MessageWriter alloc] init] autorelease];
[writer writeByte:MessageRestartMatch];
[self sendData:writer.data];
然后在HelloWorldLayer.h做一些调整
// Add inside @interface
CCLabelBMFont *gameOverL
CCMenu *gameOverM
在HelloWorldLayer.m中调用重新比赛的方法
// Add at top of matchStarted
[gameOverMenu removeFromParentAndCleanup:YES];
gameOverMenu =
[gameOverLabel removeFromParentAndCleanup:YES];
gameOverLabel =
// Replace restartTapped and endScene with the following
- (void)restartTapped:(id)sender {
[gameOverMenu removeFromParentAndCleanup:YES];
gameOverMenu =
[gameOverLabel removeFromParentAndCleanup:YES];
gameOverLabel =
[[NetworkController sharedInstance] sendRestartMatch];
- (void)endScene:(EndReason)endReason {
CGSize winSize = [CCDirector sharedDirector].winS
NSString *
if (endReason == kEndReasonWin) {
message = @"You win!";
} else if (endReason == kEndReasonLose) {
message = @"You lose!";
gameOverLabel = [CCLabelBMFont labelWithString:message fntFile:@"Arial.fnt"];
gameOverLabel.scale = 0.1;
gameOverLabel.position = ccp(winSize.width/2, 180);
[self addChild:gameOverLabel];
CCLabelBMFont *restartLabel = [CCLabelBMFont labelWithString:@"Restart" fntFile:@"Arial.fnt"];
CCMenuItemLabel *restartItem = [CCMenuItemLabel itemWithLabel:restartLabel target:self selector:@selector(restartTapped:)];
restartItem.scale = 0.1;
restartItem.position = ccp(winSize.width/2, 140);
gameOverMenu = [CCMenu menuWithItems:restartItem, nil];
gameOverMenu.position = CGPointZ
[self addChild:gameOverMenu];
[restartItem runAction:[CCScaleTo actionWithDuration:0.5 scale:1.0]];
[gameOverLabel runAction:[CCScaleTo actionWithDuration:0.5 scale:1.0]];
现在轮到服务端了,修改CatRaceServer.py
// Add to end of MESSAGE constants
MESSAGE_RESTART_MATCH = 7
// Add new method to CatRaceMatch
def restartMatch(self, player):
if (self.state == MATCH_STATE_ACTIVE):
self.state = MATCH_STATE_ACTIVE
for matchPlayer in self.players:
matchPlayer.posX = 25
for matchPlayer in self.players:
if (matchPlayer.protocol):
matchPlayer.protocol.sendMatchStarted(self)
// In CatRaceFactory's playerConnected, after TODO
if (continueMatch):
existingPlayer.protocol.sendMatchStarted(existingPlayer.match)
print "TODO: Quit match"
// Add new method to CatRaceProtocol
def restartMatch(self, message):
self.log("Recv MESSAGE_RESTART_MATCH")
self.player.match.restartMatch(self.player)
// Add to CatRaceProtocol's processMessage, right before self.log
if messageId == MESSAGE_RESTART_MATCH:
return self.restartMatch(message)
编译你的代码,重新运行,并重启你的服务器,你将会看到现在你赢了之后可以重新开始比赛了
更酷的是,如果你断开了设备(通过关闭应用程序并重新启动),你会重新回到比赛中。
接近结束:处理比赛结束
重新连接到比赛中是很酷的,但并不是最好的,如果你的对手离开了比赛,那么你就只能一个人玩了。但是我们会让它更好,如果有玩家离开了,但他没有回来,我们可以取消这场比赛。要做到这一点,对CatRaceServer.py做些改动
// Add to top of file
from twisted.internet.task import LoopingCall
from time import time
// Add in constants section
SECS_FOR_SHUTDOWN = 30
// Add to bottom of __init__ in CatRaceMatch
self.pendingShutdown = False
self.shutdownTime = 0
self.timer = LoopingCall(self.update)
self.timer.start(5)
// Add new methods to CatRaceMatch
def update(self):
print "Match update: %s" % (str(self))
if (self.pendingShutdown):
cancelShutdown = True
for player in self.players:
if player.protocol == None:
cancelShutdown
if (time() & self.shutdownTime):
print "Time elapsed, shutting down match"
self.quit()
for player in self.players:
if player.protocol == None:
print "Player %s disconnected, scheduling shutdown" % (player.alias)
self.pendingShutdown = True
self.shutdownTime = time() + SECS_FOR_SHUTDOWN
def quit(self):
self.timer.stop()
for matchPlayer in self.players:
matchPlayer.match = None
if matchPlayer.protocol:
matchPlayer.protocol.sendNotInMatch()
在Twisted中,你可以使用LoopingCall来按排每隔一段时间来调用方法。在这里,我们设置每5秒钟调用update方法。在这个方法中,看看是否正在处理等待取消比赛的,如果是,如果所有玩家都在连接,我们就取消这个等待,如果有玩家断开连接,当过了5秒后,就会取消比赛,调用quit方法。如果不是在处理等待取消比赛,我们就会检查是否有玩家断开连接,就会处理正在等待取消比赛,重新完成上述的过程。quit方法会把”not in match”消息发给发有的客户端。重启你的服务器,开始一场比赛,当有一个客户端断开连接后,但是还会保持一会,直到服务器取消这场比赛。
接近结束:处理GameCenter的邀请
现在我们的程序能够很好的运行了,但是现在还不支持GameCenter的邀请功能。这是一个我们必须要有的重要特性,而且还很容易实现,因此,让我们来看看怎么在托管服务器的多人游戏中实现这项功能。其实工作原理和普通的方式非常相似,除了一个重要的变化——如果你接受了一个邀请,你必须连接服务器,并发送一条消息给邀请你的玩家,然后在他的Matckmaker的视图中显示你已连接。如果你没有完成这一步,对方会将一直看着一个菊花在发呆。让我们看看这是怎么工作的,对NetworkController.h做出以下的更改
// Add inside @interface
GKInvite *_pendingI
NSArray *_pendingPlayersToI
// Add after @interface
@property (retain) GKInvite *pendingI
@property (retain) NSArray *pendingPlayersToI
在这我们定义了一此变量来保存GameCenter传来过来的邀请信息,下一步切换到NetworkController.m并做这些变动
// Add new MessageType
MessageNotifyReady
// Add to @synthesize section
@synthesize pendingInvite = _pendingI
@synthesize pendingPlayersToInvite = _pendingPlayersToI
// Add before processMessage
- (void)sendNotifyReady:(NSString *)inviter {
MessageWriter * writer = [[[MessageWriter alloc] init] autorelease];
[writer writeByte:MessageNotifyReady];
[writer writeString:inviter];
[self sendData:writer.data];
// Add at end of processMessage
else if (msgType == MessageNotifyReady) {
NSString *playerId = [reader readString];
NSLog(@"Player %@ ready", playerId);
if (_mmvc != nil) {
[_mmvc setHostedPlayerReady:playerId];
// Inside inputStreamHandleEvent, replace [self sendPlayerConnected:...] with this:
BOOL continueMatch = _pendingInvite ==
[self sendPlayerConnected:continueMatch];
// Inside outputStreamHandleEvent, replace [self sendPlayerConnected:...] with this:
BOOL continueMatch = _pendingInvite ==
[self sendPlayerConnected:continueMatch];
// Inside authenticationChanged, after _userAuthenticated = TRUE
[GKMatchmaker sharedMatchmaker].inviteHandler = ^(GKInvite *acceptedInvite, NSArray *playersToInvite) {
NSLog(@"Received invite");
self.pendingInvite = acceptedI
self.pendingPlayersToInvite = playersToI
if (_state &= NetworkStateConnected) {
[self setState:NetworkStateReceivedMatchStatus];
[_delegate setNotInMatch];
// Inside findMatchWithMinPlayers:maxPlayers:viewController, replace if (FALSE) { } with the following
if (_pendingInvite != nil) {
[self sendNotifyReady:_pendingInvite.inviter];
self.mmvc = [[[GKMatchmakerViewController alloc] initWithInvite:_pendingInvite] autorelease];
_mmvc.hosted = YES;
_mmvc.matchmakerDelegate =
[_presentingViewController presentModalViewController:_mmvc animated:YES];
self.pendingInvite =
self.pendingPlayersToInvite =
这些非常简单,我解释一下它是怎么工作的:
当玩家通过验证后,我们注册了一个邀请处理,它能在任何时候被调用。当然被调用的时候,我们就存储这些邀请的信息,并把游戏状态设为“not in the mach”,然后调用- (void)findMatchWithMinPlayers方法开始游戏。
在- (void)findMatchWithMinPlayers中,如何有邀请信息,我们就会通过- (void)sendNotifyReady方法来告诉邀请者我们已经安全的连接上服务器了。
在接收到MessageNotifyReady后,我们就在GKMatchmakerViewController中调用- (void)setHostedPlayerReady方法,记住,不然你就会陷入死亡漩涡(译者:死循环。。。)
以上是客户端我们需要做的所有工作,现在轮到服务端了,编辑CatRaceServer.py
// Add new message constant
MESSAGE_NOTIFY_READY = 8
// Add new method to CatRaceFactory
def notifyReady(self, player, inviter):
for existingPlayer in self.players:
if existingPlayer.playerId == inviter:
existingPlayer.protocol.sendNotifyReady(player.playerId)
// In CatRaceFactory, replace print "TODO: Quit match" with the following
print "Quitting match!"
existingPlayer.match.quit()
// Add new methods to CatRaceProtocol
def sendNotifyReady(self, playerId):
message = MessageWriter()
message.writeByte(MESSAGE_NOTIFY_READY)
message.writeString(playerId)
self.log("Sent PLAYER_NOTIFY_READY %s" % (playerId))
self.sendMessage(message)
def notifyReady(self, message):
inviter = message.readString()
self.log("Recv MESSAGE_NOTIFY_READY %s" % (inviter))
self.factory.notifyReady(self.player, inviter)
// Add new case to processMessage, right before Match specific messages
if messageId == MESSAGE_NOTIFY_READY:
return self.notifyReady(message)
这太简单不过了——当服务器接收到一条”notify ready”消息,就会转发给适当的对象。现在,你可以在两台设备上运行你的程序了(注意:你必须使用两台设备,模拟器不支持邀请的!),你应该能够邀请你的另一个帐号到你的比赛中了。
GameCenter是否值得做多人游戏
在我们以前的教程中,我们说Game Center是一个很好的东西,因为你不必建立你自己的帐号系统,用户也不必创建新的号,而且他们还可以使用现在的朋友列表,等等。但是,当你有了自己的服务器,Game Center并不是最好的选择。这里有几条你不愿使用它,而宁愿自己建立一个帐号系统的原因 :
你可以管理用户的帐号,你可以从你的用户那得到更多的信息,当用户注册时你还能得到你的邮箱列表,等等,这些总好过你只能得到Game Center中随机的用户ID;
如果你使用Game Center,这就意味着你只能和有Game Center帐号的玩家一起游戏,使用自己的服务器的好处之一,就是你可以做一个跨平台的游戏;
Game Center好像不支持在一场已经开始的比赛中邀请其他玩家,因为根本没有关于这些的GUI元素。
其实我想说的是,你已经通过各种努力建立了你自己的游戏服务器,也不差这么点功夫来创建你自己的帐号系统,这东西对你的游戏长期发展会有帮助的。
何去何从?
这里是这篇教程完整的。
谢谢所有投票表决发表这篇教程的人,希望你们都喜欢!但是在本教程中,我有点怀疑,我可能已经犯了些细微的错误,在网络状态中,可能会错过一些没发现的事件,或者会有些小小的逻辑错误。但这东西很难做到完全正确的!
如果你正在寻找本教程中的任何问题,或者有能让事情做得更好的任何建议,请你告诉我,我想这能让我学习得更好。
如果你有任何疑问,意见或建议,请加入论坛讨论!
翻译手记:终于翻译完毕了,虽然后边说了用Game Center做多人游戏的诸多不利,但是这还是一篇很好的文章,可以学习多人游戏中的工作原理,还有利用Python建立自己的服务器的基础知识。相信当你掌握了这些知识,你就可以加入你自己想要的东西,能够做出更复杂的游戏。
喜欢我们的文章请您与朋友分享:
相关文章:
当睡觉也成为一种奢侈,你就达到了程序猿的境界了——苦逼码农

我要回帖

更多关于 iphone字体怎么改大小 的文章

 

随机推荐