ÉÏһƪ¡¶iOS
APP ¼Ü¹¹Âþ̸(Ò»)¡·¼òµ¥½éÉÜÁËinformation flowµÄ¸ÅÄî¡£ÕâÆªÎÄÕ¼òµ¥½éÉÜÁíÒ»¸öÔÚ±à³ÌÖзdz£ÖØÒªµÄ˼Ïë»ò¹¤¾ß¡ª¡ª×´Ì¬»ú£¨State
machine£©¡£ ¶Ô´ó¶àÊý¼ÆËã»úרҵµÄ¼Ò»ïÃÇÀ´Ëµ£¬ÕâÓ¦¸ÃÊÇÒ»ÃűȽÏÄÑѧµÄ¿Î³Ì£¬ÀïÃæ°üº¬Ò»´ó¶Ñ¾¾ÐĵÄÃû×Ö±ÈÈçDFA£¬NFA£¬»¹ÓÐÒ»´ó¶Ñ¸÷ÖÖ¸÷ÑùµÄÊýѧ·ûºÅ,ÓÖÊDZàÒëÔÀíµÄ»ù´¡¡£²»¹ýºÜÒź¶£¬ËƺõÔÚ×öÍê±àÒëÔÀí¿Î³Ì×÷ÒµÖ®ºó£¬ºÜ¶àÈËÔÙҲûÓÐʵÏÖ¹ý»òÊÇÓùý״̬»úÁË¡£±¾ÎÄͨ¹ýÒ»¸öÓÎÏ·demoÀ´¼òµ¥ÃèÊöÒ»ÏÂ״̬»úÔÚʵ¼ùÖеÄÓ¦Óá£
±³¾°
Ê×ÏÈ¿´ÏÂÎÒÃǵÄʹÓó¡¾°£¬¼ÙÈçÎÒÃÇÐèÒªÉè¼ÆÒ»Ì×ÁªÍø¶ÔÕ½µÄСÓÎÏ·¡£µÚÒ»¸öÄÑÌâ¿ÉÄÜÊÇÈçºÎ½¨Á¢Ò»¸öͨµÀ£¬ÈÃ2¸öÊÖ»úÏ໥·¢ËÍÏûÏ¢¡£ÕâÀïÎÒ²¢²»´òËãÒýÈëserver¶Ë¿ª·¢£¬Ï£ÍûÖ»ÊÇͨ¹ý¿Í»§¶ËÀ´ÊµÏÖÕâ¸öÂß¼£¬ÕâÀïʹÓÃLeanCloud
APIÀ´¼ò»¯Õâ¸ö¹ý³Ì¡£ÕâÑùÎÒÃÇ¿ÉÒÔÔÝʱ²»¿¼ÂǼ¼Êõϸ½Ú£¬Ö±½ÓÕ¾ÔÚÒµÎñ½Ç¶Èȥ˼¿¼ÈçºÎ½¨Á¢Õâ¸öÓÎÏ·¡£
ÒµÎñ³¡¾°¨CÑûÇë
Õýʽ¿ªÊ¼ÓÎϷ֮ǰ£¬×Ü»áÓÐÒ»¸öÑûÇëµÄ»·½Ú¡£¼ÙÈçÎÒÃÇÓÐ2¸öÓû§£¬·Ö±ðÊÇHost£¬Guest¡£Host´´½¨ÓÎÏ·£¬Guest¼ÓÈëÓÎÏ·¡£ÓÎÏ·µÄÕû¸öÁ÷³ÌºÍÎÒÃÇÆ½Ê±ÍæµÄ¶ÔÕ½ÓÎÏ·Á÷³Ì²¢Ã»Óжà´ó²»Í¬¡£

1. Host´´½¨ÓÎÏ·£¬Ëû¾ÍÏ൱ÓÚ½øÈëÒ»¸öµÈ´ý¶ÓÁÐÀïÃæ¡£
2. Guest¼ÓÈëÓÎÏ·£¬Ëû´ÓµÈ´ý¶ÓÁÐÖÐÕÒµ½Ò»¸öÆ¥Å䣬±ÈÈçHost¡£È»ºó¶ÔHost·¢ËÍjoin message
3. Host»áÊÕµ½ºÜ¶àjoin message¡£ÓÉÓÚÎÒÃÇÖ»ÊÇÑ¡Ôñ1vs1¡£ÕâÀï¼Ù¶¨HostͬÒâGuest¼ÓÈëÓÎÏ·¡£HostÏòGuest·¢ËÍjoin
confirm message
4. GuestÊÕµ½join confirm message, ÏòHost·¢ËÍGoÏûÏ¢£¬±íʾGuestÒѾ½øÈëÓÎÏ·
5. HostÊÕµ½GoÏûÏ¢¡£Ò²½øÈëÓÎÏ·¡£
¾ßÌåʵÏÖÒµÎñÂß¼
ÏÖÔڵĹ¹ÏëµÄÂß¼Ö»ÓÐ5²½£¬µ«Æäʵ»¹»á°üº¬ºÜ¶àÂß¼£¬±ÈÈ糬ʱ»úÖÆ£¬ÖØ·¢»úÖÆ¡£ÓÉÓÚÖмä״̬ºÜ¶à£¬»¹¿ÉÄÜÓÐÎÒÃÇûÓÐÏëµ½¹ýµÄÎÊÌâ¡£ÔÚÃæ¶ÔÕâÖÖ¸´ÔÓÂ߼ʱ£¬»áͨ¹ý״̬»úÀ´°ïÖúÎÒÃÇÀí˳Âß¼¡£Õâʱ£¬ÎÒÃÇÄÔÖÐ˼¿¼µÄÒµÎñÆäʵÊÇÒ»¸ö״̬µ½Ò»¸ö״̬µÄͼ¡£
ÈçÏÂ

Éϰ벿·ÖÊÇÓÎÏ·µÄ´´½¨Õߣ¬Ï°벿·ÖÊÇÓÎÏ·µÄ¼ÓÈëÕß¡£
Ò»¿ªÊ¼£¬¾¡Á¿¼ò»¯Ä£ÐÍ£¬ÕâÀïºìÉ«¼ôÍ·±íʾÎÒÃǵÄÕýÈ·Ö÷Á÷·Ïߣ¬ºÚÉ«±íÏÖ³ö´í·Ïß¡£Ò²¾ÍÊÇ˵£¬Ò»µ©´íÎ󣬾ͻص½ÔʼIdle״̬¡£
¿ªÊ¼Ð´´úÂë
ÔÚÏëÇå³þËùÓÐÂß¼£¬²¢¿¼ÂÇÇå³þÕý³£Â·ÏߺʹíÎó·ÏßÖ®ºó£¬¾Í¿ÉÒÔ¿ªÊ¼Ð´´úÂëÁË¡£ÎªÁË·½±ã£¬ÕâÀïÖ±½ÓʹÓõÚÈý·½µÄ״̬»ú¿ò¼ÜTransitionKit¡£
¶¨ÒåState£¨HOST£©
TKState *idleState = [TKState stateWithName:@"idle"]; TKState *waitingJoinState = [TKState stateWithName:@"waitingJoin"]; TKState *waitingConfirmState = [TKState stateWithName:@"waitingConfirm"]; TKState *goState = [TKState stateWithName:@"go"]; [waitingConfirmState setDidEnterStateBlock:^(TKState *state, TKTransition *transition) { [selfWeak sendJoinConfirm]; }]; [goState setDidEnterStateBlock:^(TKState *state, TKTransition *transition) { NSLog(@"happy ending"); [SVProgressHUD showSuccessWithStatus:@"ok"]; }]; |
¶¨ÒåEvent£¨HOST£©
Event Êǽ¨Á¢Stateµ½StateµÄ·¾¶
TKEvent *waitingJoinEvent = [TKEvent eventWithName:CUHostGameManagerWaitingJoinEvent transitioningFromStates:@[idleState] toState:waitingJoinState]; TKEvent *receiveInviteEvent = [TKEvent eventWithName:CUHostGameManagerReceiveInviteEvent transitioningFromStates:@[waitingJoinState] toState:waitingConfirmState]; TKEvent *receiveConfirmEvent = [TKEvent eventWithName:CUHostGameManagerReceiveConfirmEvent transitioningFromStates:@[waitingConfirmState] toState:goState]; TKEvent *disconnectedEvent = [TKEvent eventWithName:CUHostGameManagerDisconnectedEvent transitioningFromStates:nil toState:idleState]; |
¶¨Òå¹ý³Ì£¨HOST£©
- (void)startGame { NSAssert(self.session.peerId != nil, @""); //ÕâÀÈç¹û²»ÊÇidle£¬ÎÒÃÇÇл»×´Ì¬»úµ½idle if (![self.stateMachine.currentState.name isEqual:@"idle"]) { [self fireEvent:CUHostGameManagerDisconnectedEvent userInfo:nil]; } //ÕâÀïµ÷ÓÃLeanCloud Èë¶Ó AVObject *waitingId = [AVObject objectWithClassName:@"waiting_join_Ids"]; [waitingId setObject:self.session.peerId forKey:@"peerId"]; [waitingId saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) { //enqueue Ö®ºó£¬½øÈëwaitingJoin״̬ [self fireEvent:CUHostGameManagerWaitingJoinEvent userInfo:nil]; }]; } - (void)sendJoinConfirm { //·¢ËͼÓÈëÈ·ÈÏÏûÏ¢¸øGuest AVMessage *message = [AVMessage messageForPeerWithSession:self.session toPeerId:self.peerId payload:@"join_confirm"]; [self.session sendMessage:message transient:YES]; } - (void)session:(AVSession *)session didReceiveMessage:(AVMessage *)message { if ([message.payload isEqualToString:@"join"]) { //ÊÕµ½Join£¨ÑûÇ룩֮ºó£¬·¢ËÍÈ·ÈÏÏûÏ¢ self.peerId = message.fromPeerId; //ÒòΪLeanCloudµÄAPI±È½Ï´ì£¬watch Ö®ºó²ÅÄÜ·¢ËÍÏûÏ¢£¬µ«ÊÇÎÒÃDz»ÖªµÀʲôʱºò²Åwatch³É¹¦¡£¡£¡£¡£ //ºÃÔÚÖ»ÊÇdemo£¬ÎÒÃÇÖ»ºÃÓÃÕâÖÖ·½Ê½work around£¬ÑÓ³Ù2s·¢ËÍÏûÏ¢ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(sendInviteConfirmRequest:) object:nil]; [self performSelector:@selector(sendInviteConfirmRequest:) withObject:@[message.fromPeerId] afterDelay:2.0f]; } else if ([message.payload isEqualToString:@"go"]) { //ÊÕµ½goÏûÏ¢£¬Á÷³Ì½áÊø [self fireEvent:CUHostGameManagerReceiveConfirmEvent userInfo:nil]; } } - (void)sendInviteConfirmRequest:(NSArray *)watchPeerIds { [self.session watchPeerIds:watchPeerIds]; [self fireEvent:CUHostGameManagerReceiveInviteEvent userInfo:nil]; } |
¶¨ÒåState£¨Guest£©
TKState *idleState = [TKState stateWithName:@"idle"]; TKState *waitingReplyState = [TKState stateWithName:@"waitingReply"]; TKState *goState = [TKState stateWithName:@"go"]; [waitingReplyState setWillEnterStateBlock:^(TKState *state, TKTransition *transition) { [selfWeak searchingGames]; }]; [goState setDidEnterStateBlock:^(TKState *state, TKTransition *transition) { [selfWeak sendGo]; NSLog(@"happy ending"); [SVProgressHUD showSuccessWithStatus:@"ok"]; }]; |
¶¨ÒåEvent£¨Guest£©
TKEvent *searchingEvent = [TKEvent eventWithName:CUGestGameManagerSearchingEvent transitioningFromStates:@[idleState] toState:waitingReplyState]; TKEvent *receiveConfirmEvent = [TKEvent eventWithName:CUGestGameManagerReceiveConfirmEvent transitioningFromStates:@[waitingReplyState] toState:goState]; TKEvent *disconnectedEvent = [TKEvent eventWithName:CUGestGameManagerDisconnectedEvent transitioningFromStates:nil toState:idleState]; |
¶¨Òå¹ý³Ì£¨Guest£©
- (void)joinGame { if (![self.stateMachine.currentState.name isEqual:@"idle"]) { [self fireEvent:CUGestGameManagerDisconnectedEvent userInfo:nil]; } [self fireEvent:CUGestGameManagerSearchingEvent userInfo:nil]; } - (void)searchingGames { AVQuery *query = [AVQuery queryWithClassName:@"waiting_join_Ids"]; [query orderByDescending:@"updatedAt"]; [query setLimit:1]; [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) { NSMutableArray *installationIds = [[NSMutableArray alloc] init]; for (AVObject *object in objects) { if ([object objectForKey:@"peerId"]) { [installationIds addObject:[object objectForKey:@"peerId"]]; } } [self.session watchPeerIds:installationIds]; [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(sendJoinRequest) object:nil]; [self performSelector:@selector(sendJoinRequest) withObject:nil afterDelay:2.0f]; }]; } - (void)sendJoinRequest { for (NSString *item in self.session.watchedPeerIds) { AVMessage *message = [AVMessage messageForPeerWithSession:self.session toPeerId:item payload:@"join"]; [self.session sendMessage:message transient:YES]; } } - (void)sendGo{ AVMessage *message = [AVMessage messageForPeerWithSession:self.session toPeerId:self.otherPeerId payload:@"go"]; [self.session sendMessage:message transient:YES]; } |
×îºó
state machine ÊÇÒ»¸öÂùÀ÷º¦µÄ´¸×Ó£¬Ö»ÒªÊÇÒ»¸ö¹¤¾ß£¬¾Í¿Ï¶¨»á±»ÀÄÓᣡ£¡£state machine×î´óµÄºÃ´¦ÊÇÔÚÓÚ£¬·½±ãÎÒÃÇ˼¿¼Çå³þËùÓÐϸ½Ú£¬Ö÷Ïߣ¬ºÍ´íÎóÁ÷³Ì¡£±ÜÃâÒòΪ¿¼ÂDz»ÖÜÈ«¶ø²úÉúµÄbug¡£½áºÏ֮ǰµÄinformation
flowµÄ˼·£¬»áÈÃÎÒÃǵÄÈí¼þÉè¼Æ¸ü¼ÓÇå³þ¡£
|