1. Code
  2. Mobile Development
  3. iOS Development

Build a Multiplayer Minesweeper Game: Client-Side Creation

Scroll to top

This is the second installment of the Minesweeper game mini-series. In this tutorial, you will learn how to fully implement the client side of the application. We will use a native iOS application that connects to the web servers, parses the data, and displays the user interface interaction.


Project Overview

Minesweeper Flag is a multi-player board game that is played between two opponents. Commonly, blue or red is assigned to each player. The board is composed by 256 equal squares, and each board has 51 mines placed in entirely random positions.

Figure 5: Blue playerFigure 5: Blue playerFigure 5: Blue player
Preview of the Final Effect

Review of Part 1

Before you start the second part of the series make sure you have the first part fully tested and implemented.


Step 1: Installing Cocos 2D

The first step is to download and install the Cocos 2D game engine. For this tutorial, we used Cocos 2D version 2.

Once downloaded, you need to install it and integrate it with Xcode. Unpack the file downloaded before and you will notice a file called install-templates.sh. Open a terminal window and run that file using the following command

1
2
./install-templates -f.

Step 2: Create a New Project

Using Xcode, create a new project: File -> New -> Project.

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

Choose the Cocos2d v2.x on the left side menu and Cocos2d iOS on the right one.


Step 3: Configure Project Settings

Give your project a name and a company identifier. For this tutorial, we use the iPad device family option.

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

Step 4: Verify the Setup

If everything is correct you should see a window similar to the following one:

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

Step 5: Add New Classes

Now you should add two new Objective-c classes. To do this, access the menu option File -> New -> File.

Add the following classes:

  • LoadingScene: This class will serve as a loading screen for the user while he / she is waiting for another player to join the game.
  • GameScene: This is the core class of the game; is where the main logic is programmed.

Step 6: Add Resource Files

In order to correctly run the game you should add the resource files to your project. Here you can download the resource files used. Next, copy them to the resources folder.


Step 7: Create the HelloWorldLayer Class

Change your HelloWorldLayer header file to the following:

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

Change the HelloWorldLayer implementation file to the following:

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

Step 8: Create the LoadingScene Class

Change your LoadingScene header file to the following:

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

Change your LoadingScene implementation file to the following:

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

Step 9: Create the GameScene Class

Change your GameScene header file to the following:

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

Change your GameScene implementation file to the following:

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

Step 10: Build & Run the Game

After you include the abovementioned code, the next step is to build and test the application. Use the cmd + b shortcut. If everything is fine you should see the iPad simulator up and running the game.

Figure 4: iPadFigure 4: iPadFigure 4: iPad

Step 11: Enjoy the Game

In this final step the objective is to enjoy the game. Since the game is a two-player game the best way to play it is with a friend!

In the following screens we can see the final game board though the vision of the two-players (blue and red). The arrow above the player avatar indicates the current player turn; the player that is currently playing.

Blue player game board:

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

Red player game board:

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

Step 12: Conclusions

This concludes the Part II of how to create a Minesweeper Flag game using both server-side and client-side code. By now, you should have enough knowledge to create a simple Cocos2D game using the same game engine. If you have any questions or comments, please feel free to leave them in the comments section here.