1. Code
  2. Mobile Development
  3. iOS Development

Crea un juego multijugador de Buscaminas: creación del lado del cliente

Esta es la segunda entrega de la miniserie del juego Minesweeper. En este tutorial, aprenderá a implementar completamente el lado del cliente de la aplicación. Utilizaremos una aplicación nativa de iOS que se conecta a los servidores web, analiza los datos y muestra la interacción de la interfaz de usuario.
Scroll to top

Spanish (Español) translation by Claudia Márquez (you can also view the original English article)

Esta es la segunda entrega de la miniserie del juego Minesweeper.  En este tutorial, aprenderá a implementar completamente el lado del cliente de la aplicación.  Utilizaremos una aplicación nativa de iOS que se conecta a los servidores web, analiza los datos y muestra la interacción de la interfaz de usuario. 


Visión general del proyecto

Minesweeper Flag es un juego de mesa multijugador que se juega entre dos oponentes.  Comúnmente, se asigna azul o rojo a cada jugador.  El tablero está compuesto por 256 cuadrados iguales, y cada tablero tiene 51 minas colocadas en posiciones completamente aleatorias. 

Figure 5: Blue playerFigure 5: Blue playerFigure 5: Blue player
Vista previa del efecto Final

Revisión de la Parte 1

Antes de comenzar la segunda parte de la serie, asegúrese de tener la primera parte totalmente probada e implementada.


Paso 1: Instalación Cocos 2D

El primer paso es descargar e instalar el motor de juego 2D Cocos.  Para este tutorial, usamos Cocos2d versión 2.

Una vez descargado, debe instalarlo e integrarlo con Xcode.  Desempaque el archivo descargado anteriormente y verá un archivo llamado install-templates.sh.  Abra una ventana de terminal y ejecute ese archivo usando el siguiente comando 

1
2
./install-templates -f.

Paso 2: Crea un nuevo proyecto

Usando Xcode, crea un nuevo proyecto: Archivo -> Nuevo -> Proyecto.

Figure 1: New cocos2d projectFigure 1: New cocos2d projectFigure 1: New cocos2d project

Elija Cocos2d v2.x en el menú de la izquierda y Cocos2d iOS en la de la derecha.


Paso 3: Configurar los ajustes del proyecto

Dale a tu proyecto un nombre y un identificador de empresa.  Para este tutorial, utilizamos la opción de familia de dispositivos iPad. 

Figure 2: New cocos2d projectFigure 2: New cocos2d projectFigure 2: New cocos2d project

Paso 4: Verificar la configuración

Si todo es correcto, debería ver una ventana similar a la siguiente:

Figure 3: Project filesFigure 3: Project filesFigure 3: Project files

Paso 5: Agregar nuevas clases

Ahora debería agregar dos nuevas clases de Objective-c. Para hacer esto, acceda a la opción de menú Archivo -> Nuevo -> Archivo.

Agregue las siguientes clases:

  • LoadingScene: Esta clase servirá como una pantalla de carga para el usuario mientras espera que otro jugador se una al juego.
  • GameScene: Esta es la clase principal del juego; es donde está programada la lógica principal.

Paso 6: Agregar archivos de recursos

Para ejecutar correctamente el juego, debe agregar los archivos de recursos a su proyecto.  Aquí puede descargar los archivos de recursos utilizados. Luego, cópielos a la carpeta de recursos.


Paso 7: Crea la clase HelloWorldLayer

Cambie su archivo de encabezado HelloWorldLayer a lo siguiente:

1
2
#import <GameKit/GameKit.h>

3
#import "cocos2d.h"

4
5
@interface HelloWorldLayer : CCLayer {}
6
7
@property (nonatomic, retain) NSURLConnection* connectionConnectGame;
8
@property (nonatomic,retain) NSMutableData* responseData;
9
@property (nonatomic,retain) NSString* URL;
10
@property (nonatomic) int playerID;
11
@property (nonatomic,retain) NSString* playerIDString;
12
@property (nonatomic) BOOL launchFlag;
13
@property (nonatomic,retain) NSString* gameID;
14
@property (nonatomic,retain) NSString* turnID;
15
16
+(CCScene *) scene;
17
-(void) connectTheWebService:(NSString*)id;
18
19
@end

Cambie el archivo de implementación de HelloWorldLayer a lo siguiente: 

1
2
#import "HelloWorldLayer.h"

3
#import "GameScene.h"

4
#import "LoadingScene.h"

5
#import "cocos2d.h"

6
#import "AppDelegate.h"

7
8
#pragma mark - HelloWorldLayer

9
10
@implementation HelloWorldLayer
11
12
@synthesize connectionConnectGame = _connectionConnectGame;
13
@synthesize URL = _URL;
14
@synthesize responseData = _responseData;
15
@synthesize launchFlag = _launchFlag;
16
@synthesize gameID = _gameID;
17
@synthesize playerID = _playerID;
18
@synthesize playerIDString = _playerIDString;
19
@synthesize turnID = _turnID;
20
21
+(CCScene *) scene{
22
  CCScene *scene = [CCScene node];
23
24
  HelloWorldLayer *layer = [HelloWorldLayer node];
25
26
  [scene addChild: layer];
27
  
28
  return scene;
29
}
30
31
-(id) init {
32
  if( (self=[super init]) ) {
33
34
        [self setLaunchFlag:FALSE];
35
        
36
        // CHANGE THE LINK accordingly

37
        [self setURL:@"http://10.0.6.178:8080/Minesweeper_Flag/resources/generic/connectGame/"];
38
        
39
        CGSize size = [[CCDirector sharedDirector] winSize];
40
        
41
        // Background

42
        CCSprite * background = [CCSprite spriteWithFile:@"background.jpg"];
43
        background.position = ccp(size.width/2,size.height/2);
44
        [self addChild:background];
45
        
46
        CCSprite* flags = [CCSprite spriteWithFile:@"bandeiras.png"];
47
        flags.scale = .30;
48
        flags.position = ccp(size.width - size.width/1.15,size.height - size.height/1.25);
49
        [self addChild:flags];
50
        
51
        // Title Label

52
        CCLabelTTF *label = [CCLabelTTF labelWithString:@"Minesweeper Flags" fontName:@"Marker Felt" fontSize:64];
53
        label.position =  ccp( size.width /2 , size.height - size.height/4 );
54
        [self addChild: label];
55
56
        // Player ID generation

57
        NSDateFormatter *date = [[NSDateFormatter alloc] init];
58
        [date setDateFormat:@"mm"];
59
        int minute = [[date stringFromDate:[NSDate date] ]intValue];
60
        [date setDateFormat:@"ss"];
61
        int seconds = [[date stringFromDate:[NSDate date]] intValue];
62
        int pID = minute + seconds + (rand() % 1000000);
63
        [self setPlayerID:pID];
64
        
65
        NSString* playerIDInStringFormat = [NSString stringWithFormat:@"%d", _playerID];
66
        [self setPlayerIDString:playerIDInStringFormat];
67
        NSLog(@"ID DO PLAYER %@",_playerIDString);
68
        [self setResponseData:[NSMutableData data]];
69
        
70
    // Menus

71
    [CCMenuItemFont setFontSize:38];
72
    CCMenuItem *itemNewGame = [CCMenuItemFont itemWithString:@"New Game" block:^(id sender) {
73
            
74
            [self connectTheWebService:playerIDInStringFormat];
75
    }];
76
77
        CCMenu *menu = [CCMenu menuWithItems:itemNewGame ,nil];
78
    
79
    [menu alignItemsVerticallyWithPadding:20];
80
    [menu setPosition:ccp( size.width/2, size.height/2 - 50)];
81
    
82
    [self addChild:menu];
83
  }
84
  return self;
85
}
86
87
//connect the Web server method

88
-(void) connectTheWebService:(NSString*)id{
89
    
90
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[[_URL autorelease] stringByAppendingString:id]                                                             ]];
91
    _connectionConnectGame = [[NSURLConnection alloc] initWithRequest:request delegate:self];
92
}
93
94
//Web server responses.

95
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
96
    [_responseData setLength:0];
97
}
98
99
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
100
    [_responseData appendData:data];
101
}
102
103
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
104
    NSLog(@"Connection failed: %@", [error description]);
105
}
106
107
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
108
    
109
    NSString* responseString = [[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
110
    NSLog(@"HelloWorld responseString %@",responseString);
111
    
112
    NSArray* resultArray = [[NSArray alloc] init];
113
    resultArray = [responseString componentsSeparatedByString:@","];
114
115
    if ([[resultArray objectAtIndex:1] isEqualToString:@"no"]) {
116
        [self setGameID:[resultArray objectAtIndex:0]];
117
        [self setLaunchFlag:TRUE];
118
    } else {
119
        [self setGameID:[resultArray objectAtIndex:0]];
120
        _playerID = [[resultArray objectAtIndex:1] integerValue];
121
        [self setPlayerID:[[resultArray objectAtIndex:1] integerValue]];
122
        [self setLaunchFlag:FALSE];
123
    }
124
    
125
    if (_launchFlag){
126
        GameScene* scene = [[GameScene alloc] initializeInternalDataWithPlayerID:_playerIDString andWithGameID:_gameID andWithTurnID:@"no"];
127
        [[CCDirector sharedDirector] replaceScene:scene];
128
    } else {
129
        LoadingScene* scene = [LoadingScene initializeWithPlayerID:_playerIDString andWithGameID:_gameID];
130
        [[CCDirector sharedDirector] replaceScene:scene];
131
    }
132
133
}
134
135
- (void) dealloc {
136
  [super dealloc];
137
}
138
139
@end

Paso 8: Crea la clase LoadingScene

Cambie su archivo de encabezado LoadingScene a lo siguiente: 

1
2
#import "cocos2d.h"

3
4
@interface LoadingScene : CCLayer <UIGestureRecognizerDelegate>{ }
5
6
@property (nonatomic, retain) NSURLConnection *connectionConnectGame;
7
@property (nonatomic,retain) NSMutableData* responseData;
8
@property (nonatomic,retain) NSString* gameID;
9
@property (nonatomic,retain) NSString* playerID;
10
@property (nonatomic) BOOL launchFlag;
11
@property (nonatomic,retain) NSString* URL;
12
13
+(CCScene *) scene;
14
+(id) initializeWithPlayerID:(NSString*) playerid andWithGameID:(NSString*) gameid;
15
-(id) initializeInternalDataWithPlayerID:(NSString*) playerid andWithGameID:(NSString*) gameid;
16
-(void) connectTheWebService:(NSString*)id;
17
18
@end

Cambie su archivo de implementación de LoadingScene a lo siguiente: 

1
2
#import "LoadingScene.h"

3
#import "GameScene.h"

4
5
@implementation LoadingScene
6
7
@synthesize responseData = _responseData;
8
@synthesize connectionConnectGame = _connectionConnectGame;
9
@synthesize gameID = _gameID;
10
@synthesize playerID = _playerID;
11
@synthesize launchFlag = _launchFlag;
12
@synthesize URL = _URL;
13
14
+(CCScene *) scene{
15
    CCScene *scene = [CCScene node];
16
    
17
    LoadingScene *layer = [LoadingScene node];
18
    
19
    [scene addChild: layer];
20
    
21
    return scene;
22
}
23
24
-(id) init{
25
    if( (self=[super init] )) {}
26
    
27
    return self;
28
}
29
30
// Custom initializer

31
+(id) initializeWithPlayerID:(NSString*) playerid andWithGameID:(NSString*) gameid {
32
    return [[[self alloc] initializeInternalDataWithPlayerID:playerid andWithGameID:gameid] autorelease];
33
}
34
35
-(id) initializeInternalDataWithPlayerID:(NSString*) playerid andWithGameID:(NSString*) gameid {
36
    self = [super init];
37
    
38
    if (self) {
39
        CGSize _size = [[CCDirector sharedDirector] winSize];
40
        _gameID = [[NSString alloc] init];
41
        [self setLaunchFlag:FALSE];
42
        [self setPlayerID:playerid];
43
        [self setGameID:gameid];
44
        
45
        CCSprite* background = [CCSprite spriteWithFile:@"background.jpg"];
46
        background.position = ccp(_size.width/2,_size.height/2);
47
        [self addChild:background];
48
        
49
        CCLabelTTF* label = [CCLabelTTF labelWithString:@"Loading..." fontName:@"Marker Felt" fontSize:40];
50
        label.position = ccp(_size.width/2, _size.height/2);
51
        [self addChild:label];
52
        CCLabelTTF* label2 = [CCLabelTTF labelWithString:@"Waiting for another player" fontName:@"Marker Felt" fontSize:25];
53
        label2.position = ccp(_size.width/2, _size.height - _size.height/1.80);
54
        [self addChild:label2];
55
        
56
        [self setResponseData:[NSMutableData data]];
57
        
58
        // CHANGE IT ACCORDINGLY

59
        [self setURL:@"http://10.0.6.178:8080/Minesweeper_Flag/resources/generic/player2Available/"];
60
        
61
        [self schedule:@selector(update:) interval:2];
62
    }
63
    return self;
64
}
65
66
-(void) update:(ccTime) dt{
67
    [self connectTheWebService:_gameID];
68
}
69
70
-(void) connectTheWebService:(NSString*)id{
71
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[[_URL autorelease] stringByAppendingString:id]                                                             ]];
72
    _connectionConnectGame = [[NSURLConnection alloc] initWithRequest:request delegate:self];
73
}
74
75
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
76
    [_responseData setLength:0];
77
}
78
79
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
80
    [_responseData appendData:data];
81
}
82
83
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
84
    NSLog(@"Connection failed: %@", [error description]);
85
}
86
87
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
88
    
89
    NSString* responseString = [[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
90
91
    if ([responseString isEqualToString:@"nulo"]) {
92
        [self setLaunchFlag:FALSE];
93
    }else {
94
        [self setLaunchFlag:TRUE];
95
    }
96
    
97
    if (_launchFlag){
98
        GameScene* scene = [[GameScene alloc] initializeInternalDataWithPlayerID:_playerID andWithGameID:_gameID andWithTurnID:_playerID] ;
99
        [[CCDirector sharedDirector] replaceScene:scene];
100
    } else { [self schedule:@selector(update:) interval:2];  }
101
    
102
}
103
104
-(void)dealloc {
105
    [super dealloc];
106
}
107
108
@end

Paso 9: Crea la clase GameScene

Cambie su archivo de encabezado GameScene a lo siguiente: 

1
2
#import "cocos2d.h"

3
4
@interface GameScene : CCLayer <UIGestureRecognizerDelegate> {
5
    NSString* turn;
6
}
7
8
@property (nonatomic) int gameGridSize, initialSpriteXXPosition, initialSpriteYYPosition, deslocamentoNoEixoXX, deslocamentoNoEixoYY, tamanhoSprite, playerBlueScore, playerRedScore, lastSpriteTouch;
9
10
@property (nonatomic, retain) NSMutableArray *spritesMutableArray;
11
@property (nonatomic,retain) NSMutableArray* touchedLocations;
12
@property (nonatomic) CGSize size;
13
@property (nonatomic) CGPoint initialSpritePositon;
14
@property (nonatomic, retain) CCSprite* sprites;
15
@property (nonatomic) int spritePositionInGrid;
16
@property (nonatomic) int webServerResult;
17
@property (nonatomic, strong) NSMutableData *responseData;
18
@property (nonatomic, strong) NSString *resourceImage;
19
@property (nonatomic, retain) CCSprite* playerBlueSprite;
20
@property (nonatomic, retain) CCSprite* playerRedSprite;
21
@property (nonatomic, retain) CCSprite* playerTurnSprite;
22
@property (nonatomic, retain) CCSprite* youArrow;
23
@property (nonatomic,retain) CCLabelTTF* playerBlueLabel;
24
@property (nonatomic,retain) CCLabelTTF* playerRedLabel;
25
@property (nonatomic,retain) NSString* gameID;
26
@property (nonatomic,retain) NSString* userID;
27
@property (nonatomic,retain) NSString* colorPlayer;
28
@property (nonatomic,retain) CCSprite* positionTouchedSprite;
29
@property (nonatomic,retain) NSString* turn;
30
@property (nonatomic, retain) NSMutableString* gameBoardInfoS;
31
32
+(CCScene *) scene;
33
-(void)getMinesAtPosition:(int)pos;
34
-(void)drawGameBoard;
35
-(void)setInitialAppValues;
36
-(void)setArrowonTheRightPlayer;
37
38
+(id) initializeWithPlayerID:(NSString*) playerid andWithGameID:(NSString*) gameid andWithTurnID:(NSString*) turnid;
39
-(id) initializeInternalDataWithPlayerID:(NSString*) playerid andWithGameID:(NSString*) gameid andWithTurnID:(NSString*) turnid;
40
41
@end

Cambie su archivo de implementación de GameScene a lo siguiente: 

1
2
#import "GameScene.h"

3
#import "cocos2d.h"

4
#import "LoadingScene.h"

5
6
@implementation GameScene
7
8
@synthesize spritesMutableArray = _spritesMutableArray;
9
@synthesize touchedLocations = _touchedLocations;
10
@synthesize size = _size;
11
@synthesize initialSpritePositon = _initialSpritePositon;
12
@synthesize sprites = _sprites;
13
@synthesize spritePositionInGrid = _spritePositionInGrid;
14
@synthesize webServerResult = _webServerResult;
15
@synthesize gameGridSize = _gameGridSize;
16
@synthesize initialSpriteXXPosition = _initialSpriteXXPosition;
17
@synthesize initialSpriteYYPosition = _initialSpriteYYPosition;
18
@synthesize deslocamentoNoEixoXX = _deslocamentoNoEixoXX;
19
@synthesize deslocamentoNoEixoYY = _deslocamentoNoEixoYY;
20
@synthesize tamanhoSprite = _tamanhoSprite;
21
@synthesize responseData = _responseData;
22
@synthesize resourceImage = _resourceImage;
23
@synthesize playerTurnSprite = _playerTurnSprite;
24
@synthesize youArrow = _youArrow;
25
@synthesize playerBlueSprite = _playerBlueSprite;
26
@synthesize playerRedSprite = _playerRedSprite;
27
@synthesize playerBlueLabel = _playerBlueLabel;
28
@synthesize playerRedLabel = _playerRedLabel;
29
@synthesize playerBlueScore = _playerBlueScore;
30
@synthesize playerRedScore = _playerRedScore;
31
@synthesize gameID = _gameID;
32
@synthesize userID = _userID;
33
@synthesize colorPlayer = _colorPlayer;
34
@synthesize turn = _turn;
35
@synthesize gameBoardInfoS;
36
@synthesize lastSpriteTouch;
37
38
@synthesize positionTouchedSprite = _positionTouchedSprite;
39
40
+(CCScene *) scene{
41
    //+(id)scene{

42
    CCScene *scene = [CCScene node];
43
    
44
    GameScene *layer = [GameScene node];
45
    
46
    [scene addChild: layer];
47
    
48
    return scene;
49
}
50
51
-(id) init{
52
    if( (self=[super init] )) {
53
    }
54
    return self;
55
}
56
57
//new initialize method to recive parameters such as playerID, turnID, and gameID

58
+(id) initializeWithPlayerID:(NSString*) playerid andWithGameID:(NSString*) gameid andWithTurnID:(NSString*) turnid{
59
    return [[[self alloc] initializeInternalDataWithPlayerID:playerid andWithGameID:gameid andWithTurnID:turnid] autorelease];
60
}
61
62
//initialize several values and call methods to generate and draw all scene

63
-(id) initializeInternalDataWithPlayerID:(NSString*) playerid andWithGameID:(NSString*) gameid andWithTurnID:(NSString*) turnid{
64
    self = [super init];
65
    
66
    if (self) {
67
        // Activate touch events

68
        [super setIsTouchEnabled:YES];
69
        //set the parameters

70
        [self setGameID:gameid];
71
        [self setUserID:playerid];
72
        [self setTurn:turnid];
73
        [self setInitialAppValues];
74
        
75
        //generate and draw gameBoard

76
        [self drawGameBoard];
77
        
78
        //call the updater one time for second

79
        [self schedule:@selector(update:) interval:1];
80
    }
81
    return self;
82
}
83
84
85
// detect touchs and which sprite was touched

86
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
87
    
88
    //verify if the user have the turn

89
    if(![_turn isEqualToString:_userID]){
90
        //in case of the user not have the turn

91
        return;
92
    }
93
    
94
    UITouch* touch = [touches anyObject];
95
    CGPoint location = [touch locationInView: [touch view]];
96
    CGPoint converted = [[CCDirector sharedDirector] convertToGL:location];
97
    
98
    _spritePositionInGrid=0;
99
    for (CCSprite* spr in _spritesMutableArray){
100
        CCSprite* currentSprite = [_spritesMutableArray objectAtIndex:_spritePositionInGrid];
101
        
102
        if (CGRectContainsPoint([currentSprite boundingBox], converted)){
103
            
104
            // Verificar se a posição já foi touched

105
            BOOL jaExiste =FALSE;
106
            for (int i = 0 ; i < [_touchedLocations count]; i++){
107
                if (_spritePositionInGrid == [[_touchedLocations objectAtIndex:i] integerValue])
108
                    jaExiste=TRUE;
109
            }
110
            
111
            //was touched?

112
            if([gameBoardInfoS characterAtIndex:_spritePositionInGrid] != '9'){
113
                return;
114
            }
115
116
            if (!jaExiste){
117
                [_touchedLocations addObject:[NSNumber numberWithInt:_spritePositionInGrid]];
118
                lastSpriteTouch = _spritePositionInGrid;
119
                
120
                self.responseData = [NSMutableData data];
121
                
122
                _positionTouchedSprite = [_spritesMutableArray objectAtIndex:_spritePositionInGrid];
123
                
124
                NSMutableString* enderecoReturnValue = [NSMutableString stringWithFormat:@"http://10.0.6.178:8080/Minesweeper_Flag/resources/generic/returnValue/%@/%@/%d",_userID,_gameID,_spritePositionInGrid];
125
                NSLog(@"%@",enderecoReturnValue);
126
                
127
                NSURLRequest *request = [NSURLRequest requestWithURL: [NSURL URLWithString:enderecoReturnValue]];
128
                [[NSURLConnection alloc] initWithRequest:request delegate:self];   
129
            }
130
        }
131
        _spritePositionInGrid++;
132
    }
133
}
134
135
-(void) update: (ccTime) dt
136
{
137
    if(![_turn isEqualToString:_userID]){
138
        
139
        NSMutableString* returnUpdateURL = [NSMutableString stringWithFormat:@"http://10.0.6.178:8080/Minesweeper_Flag/resources/generic/returnUpdates/%@",_gameID];
140
        
141
        NSURL *url = [NSURL URLWithString:returnUpdateURL];
142
        NSData *jsonData = [NSData dataWithContentsOfURL:url];
143
        
144
        NSString *value = [[NSString alloc] init];
145
        NSRange a;
146
        
147
        if(jsonData != nil) {
148
            NSError *error = nil;
149
            id result = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
150
            if(error == nil) {
151
                NSString* resultString = [result objectForKey:@"Uncover_Matrix"];
152
                int positionAt, positionDiff=-1;
153
                
154
                for(positionAt= 0; positionAt< resultString.length; positionAt++){
155
                    a = NSMakeRange(positionAt, 1);
156
                    if(![[gameBoardInfoS substringWithRange:a] isEqualToString:[resultString substringWithRange:a]]){
157
                        positionDiff = positionAt;
158
                        value = [[NSString alloc] initWithString:[resultString substringWithRange:a]];
159
                        break;
160
                    }
161
                }
162
                if(positionDiff != -1){
163
                    [self setTurn:[result objectForKey:@"Turn"]];
164
                
165
                    [gameBoardInfoS replaceCharactersInRange:a withString:value];
166
                    
167
                    if([value isEqualToString:@"*"]){
168
                        _playerBlueScore++;
169
                        NSString *stringBlueScore = [NSString stringWithFormat:@"%d",_playerBlueScore];
170
                        [_playerBlueLabel setString:stringBlueScore];
171
                        value = @"9";
172
                    }
173
                    
174
                    if([value isEqualToString:@"#"]){
175
                        _playerRedScore++;
176
                        NSString *stringRedScore = [NSString stringWithFormat:@"%d",_playerRedScore];
177
                        [_playerRedLabel setString:stringRedScore];
178
                        value = @"10";
179
                    }
180
                    
181
                    [self setArrowonTheRightPlayer];
182
                    
183
                    CGPoint coordenates = [self getReversePositionGameBoard:positionDiff];
184
                    [self getMinesAtPosition:[value integerValue] withXCoord:coordenates.x andYYpos:coordenates.y];
185
                }
186
                
187
            }
188
            else
189
                NSLog(@"error");
190
        }
191
    }
192
    
193
}
194
195
//recive the position and the value returned from Web Services and replace in the board

196
-(void)getMinesAtPosition:(int)pos withXCoord:(int)xxpos andYYpos:(int)yypos{
197
    _webServerResult = pos;
198
        
199
    switch (_webServerResult) {
200
        case 0:
201
            [self setResourceImage:@"0.png"];
202
            break;
203
        case 1:
204
            [self setResourceImage:@"1.png"];
205
            break;
206
        case 2:
207
            [self setResourceImage:@"2.png"];
208
            break;
209
        case 3:
210
            [self setResourceImage:@"3.png"];
211
            break;
212
        case 4:
213
            [self setResourceImage:@"4.png"];
214
            break;
215
        case 5:
216
            [self setResourceImage:@"5.png"];
217
            break;
218
        case 6:
219
            [self setResourceImage:@"6.png"];
220
            break;
221
        case 7:
222
            [self setResourceImage:@"7.png"];
223
            break;
224
        case 8:
225
            [self setResourceImage:@"8.png"];
226
            break;
227
        case 9:
228
            [self setResourceImage:@"flag_b.png"];
229
            break;
230
        case 10:
231
            [self setResourceImage:@"flag_r.png"];
232
            break;            
233
        default:
234
            _resourceImage = @"flag_r.png";
235
            break;
236
    }
237
    
238
    // New sprite substitution after the WS invocation

239
    CCSprite* newSprite = [CCSprite spriteWithFile:_resourceImage];
240
    newSprite.scale = .25;
241
    newSprite.position = ccp(xxpos,yypos);
242
    
243
    [self addChild:newSprite];
244
}
245
246
// communication

247
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
248
    [[self responseData] setLength:0];
249
}
250
251
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
252
    [[self responseData] appendData:data];
253
}
254
255
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
256
    NSLog(@"Connection failed: %@", [error description]);
257
}
258
259
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
260
    
261
    NSString* responseString = [[NSString alloc] initWithData:[self responseData] encoding:NSUTF8StringEncoding];
262
    
263
    NSRange range = NSMakeRange(lastSpriteTouch, 1);
264
    [gameBoardInfoS replaceCharactersInRange:range withString:responseString];
265
    
266
    //assign the turn after the request

267
    if([responseString isEqualToString:@"*"]){
268
        _playerBlueScore++;
269
        NSString *stringBlueScore = [NSString stringWithFormat:@"%d",_playerBlueScore];
270
        [_playerBlueLabel setString:stringBlueScore];
271
        _turn = _userID;
272
        responseString = @"9";
273
    }
274
    else if([responseString isEqualToString:@"#"]){
275
        _playerRedScore++;
276
        NSString *stringRedScore = [NSString stringWithFormat:@"%d",_playerRedScore];
277
        [_playerRedLabel setString:stringRedScore];
278
        _turn = _userID;
279
        responseString = @"10";
280
    }
281
    else{
282
        _turn = @"is not you";
283
    }
284
    
285
    [self setArrowonTheRightPlayer];
286
    
287
    [self getMinesAtPosition:[responseString integerValue] withXCoord:_positionTouchedSprite.position.x andYYpos:_positionTouchedSprite.position.y];
288
}
289
290
//put the arrow on the player that holds the turn

291
-(void)setArrowonTheRightPlayer{
292
    
293
    if([_turn isEqualToString:_userID]) {
294
        if ([_colorPlayer isEqualToString:@"blue"])
295
            _playerTurnSprite.position = ccp(_size.width/1.30, _size.height/1.10);
296
        else
297
            _playerTurnSprite.position = ccp(_size.width/1.30, _size.height/1.48);
298
    }
299
    
300
    if(![_turn isEqualToString:_userID]) {
301
        if ([_colorPlayer isEqualToString:@"blue"])
302
            _playerTurnSprite.position = ccp(_size.width/1.30, _size.height/1.48);
303
        else
304
            _playerTurnSprite.position = ccp(_size.width/1.30, _size.height/1.10);
305
    }
306
}
307
308
//calculate the reverse position to change the sprite on gameBoard

309
-(CGPoint)getReversePositionGameBoard:(int)positionTouched{
310
    NSInteger linha = (int) positionTouched / 16.0;
311
    NSInteger y = 688 - _tamanhoSprite * linha;
312
    NSInteger x = ( (int) positionTouched % 16) * 38 + _initialSpriteXXPosition;
313
    CGPoint position = CGPointMake(x, y);
314
315
    return position;
316
}
317
318
//draw the gameBoard (background, sprites blue (water), and the playerss avatar

319
-(void)drawGameBoard{
320
    
321
    for (int i = 0 ; i < _gameGridSize; i++) {
322
        _sprites = [CCSprite spriteWithFile:@"water.png"];
323
        _sprites.scale = .25;
324
        _initialSpritePositon = CGPointMake(_initialSpriteXXPosition+_deslocamentoNoEixoXX, _size.height-_initialSpriteYYPosition-(_deslocamentoNoEixoYY*_tamanhoSprite));
325
        _sprites.position = ccp(_initialSpritePositon.x,_initialSpritePositon.y);
326
        _deslocamentoNoEixoXX+=_tamanhoSprite;
327
        
328
        if (((i+1) % 16) == 0){
329
            _deslocamentoNoEixoXX=0;
330
            _deslocamentoNoEixoYY++;
331
        }
332
        
333
        [_spritesMutableArray addObject:_sprites];
334
        [self addChild:_sprites];
335
    }
336
    
337
    
338
    [self addChild:_playerTurnSprite z:4];
339
    
340
    [self addChild:_playerBlueSprite];
341
    [self addChild:_playerRedSprite];
342
    [self addChild:_youArrow];
343
    
344
    [self addChild:_playerBlueLabel];
345
    [self addChild:_playerRedLabel];
346
}
347
348
//set initial values

349
-(void)setInitialAppValues{
350
    _size = [[CCDirector sharedDirector] winSize];
351
    _gameGridSize = 256, _tamanhoSprite = 38;
352
    _initialSpriteXXPosition = 80, _initialSpriteYYPosition = 80;
353
    _deslocamentoNoEixoXX=0, _deslocamentoNoEixoYY=0;
354
    _spritesMutableArray = [[NSMutableArray alloc] initWithCapacity:256];
355
    _touchedLocations = [[NSMutableArray alloc] initWithCapacity:256];
356
    [self setResourceImage:@""];
357
    
358
    CCSprite * background = [CCSprite spriteWithFile:@"background.jpg"];
359
    background.position = ccp(_size.width/2,_size.height/2);
360
    [self addChild:background];
361
    
362
    //init the gameBoard array

363
    gameBoardInfoS = [[NSMutableString alloc] init];
364
    for(int i=0;i<256;i++){
365
        [gameBoardInfoS appendString:@"9"];
366
    }
367
    
368
    _playerBlueSprite = [CCSprite spriteWithFile:@"player_bue.png"];
369
    _playerBlueSprite.scale = .5;
370
    _playerBlueSprite.position = ccp(_size.width/1.30, _size.height/1.25);
371
    _playerRedSprite = [CCSprite spriteWithFile:@"player_red.png"];
372
    _playerRedSprite.scale = .5;
373
    _playerRedSprite.position = ccp(_size.width/1.30, _size.height/1.75);
374
    
375
    //identify the players on field

376
    if([_turn isEqualToString:_userID]){
377
        _youArrow = [CCSprite spriteWithFile:@"you.png"];
378
        _youArrow.scale = .3;
379
        _youArrow.position = ccp(_size.width/1.30, _size.height/1.30);
380
        [self setColorPlayer:@"blue"];
381
    }
382
    else{
383
        _youArrow = [CCSprite spriteWithFile:@"you.png"];
384
        _youArrow.scale = .3;
385
        _youArrow.position = ccp(_size.width/1.30, _size.height/1.85);
386
        [self setColorPlayer:@"red"];
387
    }
388
    
389
    _playerTurnSprite = [CCSprite spriteWithFile:@"arrowTurn.png"];
390
    _playerTurnSprite.scale = 1;
391
    _playerTurnSprite.position = ccp(_size.width/1.30, _size.height/1.10);
392
    
393
    
394
    _playerBlueLabel = [CCLabelTTF labelWithString:@"0" fontName:@"Marker Felt" fontSize:50.0];
395
    _playerBlueLabel.position = ccp(_size.width/1.15, _size.height/1.25);
396
    _playerRedLabel = [CCLabelTTF labelWithString:@"0" fontName:@"Marker Felt" fontSize:50.0];
397
    _playerRedLabel.position = ccp(_size.width/1.15, _size.height/1.75);
398
    
399
    [self setPlayerBlueScore:0];
400
    [self setPlayerRedScore:0];
401
}
402
403
-(void) registerWithTouchDispatcher
404
{
405
    NSLog(@"registerWithTouchDispatcher");
406
    [[[CCDirector sharedDirector] touchDispatcher] addStandardDelegate:self priority:0];
407
}
408
409
- (void) dealloc
410
{
411
    [turn release];
412
    [super dealloc];
413
}
414
415
@end

Paso 10: Construye y ejecuta el juego

Después de incluir el código mencionado anteriormente, el siguiente paso es construir y probar la aplicación.  Use el atajo cmd + b. Si todo está bien, deberías ver el simulador de iPad funcionando. 

Figure 4: iPadFigure 4: iPadFigure 4: iPad

Paso 11: Disfruta del juego

En este paso final, el objetivo es disfrutar del juego.  ¡Dado que el juego es para dos jugadores, la mejor manera de jugarlo es con un amigo! 

En las siguientes pantallas podemos ver el tablero de juego final a través de la visión de los dos jugadores (azul y rojo).  La flecha arriba del avatar del jugador indica el turno actual del jugador; el jugador que está jugando actualmente.

Tablero de juego del jugador azul:

Figure 5: Blue playerFigure 5: Blue playerFigure 5: Blue player

Tablero de juego del jugador rojo:

Figure 6: Red playerFigure 6: Red playerFigure 6: Red player

Paso 12: Conclusiones

Esto concluye la Parte II de cómo crear un juego de Flag Minesweeper utilizando tanto el código del lado del servidor como el del lado del cliente.  Por ahora, debes tener suficiente conocimiento para crear un juego Cocos2D simple usando el mismo motor de juego.  Si tiene alguna pregunta o comentario, no dude en dejarlos en la sección de comentarios aquí.