Show Opponent's Score (Multiplayer/GameKit) - Cocos2d - iphone

I have it set up so it sends the player's score to the opponents's screen so they can see what their score is, but it never updates the value. Any ideas?
typedef enum
{
kMessageTypeRandomNumber = 0,
kMessageTypeScore,
} MessageType;
typedef struct
{
Message message;
int score;
} MessageScore;
#interface GSMultiplayer : CCLayer <GCHelperDelegate>
{
CCLabelTTF *oppScoreLabel;
uint32_t ourRandom;
BOOL receivedRandom;
}
--------------------------------------------
- (void)sendScore
{
CCLOG(#"Sent Score");
int oppScore = score;
MessageScore message;
message.message.messageType = kMessageTypeScore;
message.score = oppScore;
NSData *data = [NSData dataWithBytes:&message length:sizeof(MessageScore)];
[self sendData:data];
}
- (void)tryStartGame
{
if (isPlayer1 && gameState == kGameStateWaitingForStart)
{
[self setGameState:kGameStateActive];
[self sendGameBegin];
}
[self sendScore];
}
- (void)matchStarted
{
CCLOG(#"Match started");
if (receivedRandom)
{
[self setGameState:kGameStateWaitingForStart];
} else {
[self setGameState:kGameStateWaitingForRandomNumber];
}
[self sendRandomNumber];
[self tryStartGame];
}
- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID
{
Message *message = (Message *) [data bytes];
if (message->messageType == kMessageTypeScore)
{
CCLOG(#"Score Received");
[scoreLabel setString:[NSString stringWithFormat:#"Score: %d", score]];
}
}
}
Also, score is globally delcared from the main "GameScene". I am very new to multiplayer so help is greatly appreciated
Thanks

Keep track of the score yourself and add a layer to display the score.. after player changes scene, send the score to gamecenter?
Is your game using gamekit? If yes, you might wan to look at an example in a game called Infinight.. there is a lite version in the App store.. It has gamecenter multiplayer in it.. Just play it with friends and see how it works.. It also sends score to gamecenter after playing..
in your send data function:
msg.oppScore = score;
NSData *packet = [NSData dataWithBytes:&msg length:sizeof(charInfo)];
[sharedData.myMatch sendDataToAllPlayers: packet withDataMode: GKMatchSendDataUnreliable error:&error];
sharedData.myMatch is suppose to be the GKMatch that you are suppose to reference to when the game starts..

Related

GKScore doesn't reporting scores

Does anybody know, why this code isn't sending score to GameCenter? Authentication to GC is ok. My leaderboard is 1.
- (void) reportScore: (int64_t) score forLeaderboardID: (NSString*) identifier
{
GKScore *scoreReporter = [[GKScore alloc] initWithLeaderboardIdentifier: identifier];
scoreReporter.value = score;
scoreReporter.context = 0;
NSArray *scores = #[scoreReporter];
[GKScore reportScores:scores withCompletionHandler:^(NSError *error) {
//Do something interesting here.
NSLog(#"sent");
}];
}
I want to touch button and send some value to Game Center.
- (IBAction)sendScoreButton:(id)sender {
[self reportScore:77 forLeaderboardID:#"1"];
}

Issues regarding gamecenter+ios

I am not knowing anything about gamecentre.I am working on the COCO application
I had gone through gamecenter guide and get able to integrate the game center in my application.
1)
Now the i am able enter the score in the gamecentre through my application.
By doing this:-
- (void) reportScore: (int64_t) score forCategory: (NSString*) category
{
GKScore *scoreReporter = [[[GKScore alloc] initWithCategory:category] autorelease];
scoreReporter.value = score;
[scoreReporter reportScoreWithCompletionHandler: ^(NSError *error)
{
[self callDelegateOnMainThread: #selector(scoreReported:) withArg: NULL error: error];
}];
}
I is working properly uptil yesterday.But now if i tried to update the score it is not updating.Please any one know the reason y the score is not updating in the game center
I had tried to search out but not get anything.
2)I want to send the current latitude & longitude of one player to another.
I came to know that it is possible by GKMATCH
GKMatchRequest *request = [[[GKMatchRequest alloc] init] autorelease];
request.minPlayers = 1;
request.maxPlayers = 1;
[[GKMatchmaker sharedMatchmaker] findMatchForRequest:request
withCompletionHandler:^(GKMatch *match, NSError *error) {
if (error || !match) {
// handle the error
}
else if (match != nil){
// match found
}}];
/*GKMatchRequest *request = [[[GKMatchRequest alloc] init] autorelease];
request.minPlayers = 1;
request.maxPlayers = 1;
GKMatchmakerViewController *mmvc = [[GKMatchmakerViewController alloc] initWithMatchRequest:request];
mmvc.matchmakerDelegate = self;
currentMatch.delegate=self;
[self presentModalViewController:mmvc animated:YES];*/
//[mmvc release];
}
- (void)match:(GKMatch *)match player:(NSString *)playerID didChangeState:(GKPlayerConnectionState)state {
switch (state){
case GKPlayerStateConnected:
if (match.expectedPlayerCount == 0) {
// start the match
}
break;
case GKPlayerStateDisconnected:
// remove the player from the match, notify other players, etc
break;
}
}
- (void)matchmakerViewControllerWasCancelled:(GKMatchmakerViewController *)viewController{}
// Matchmaking has failed with an error
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFailWithError:(NSError *)error{
}
// A peer-to-peer match has been found, the game should start
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindMatch:(GKMatch *)match{
}
// Players have been found for a server-hosted game, the game should start
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindPlayers:(NSArray *)playerIDs{
}
// An invited player has accepted a hosted invite. Apps should connect through the hosting server and then update the player's connected state (using setConnected:forHostedPlayer:)
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didReceiveAcceptFromHostedPlayer:(NSString *)playerID {
}
- (void) sendPosition
{
NSError *error;
NSString* str = #"teststring";
NSData* data = [str dataUsingEncoding:NSUTF8StringEncoding];
// NSData *packet = [NSData dataWithBytes:&msg length:sizeof(PositionPacket)];
[currentMatch sendDataToAllPlayers: data withDataMode: GKMatchSendDataUnreliable error:&error];
if (error != nil)
{
// Handle the erro.r
}
}
But i dont know why but delegate method of GKMatchmakerViewController is not called i had set the delegate but still and even i ama not able to get GKMATCH (here currentMatch).
So due to this
[currentMatch sendDataToAllPlayers: data withDataMode: GKMatchSendDataUnreliable error:&error];
this method is not working.
as CurrentMatch refrence is 0X0.
Please help me out.How do i send and recive data.
M i doing anything wrong?OR is there any thing else to be done.
Please help me.
Thanks

How Can i Know if GKAchievement is Completed?

I have built objectives for my game and everything works just fine accept the part of making the objectives not be called any more after any of them is completed.
I know there is a Property of the GKAchievement Class "completed" which is a boolean that returns yes when the Achievement is 100 percent done.
here is the method that called when a Achievement is 100 percent done it passes id which is the Achievement identifier and report the acheeee :
- (void)AchivmentDidAchive:(id)Achivment{
NSString *identifier = Achivment;
NSLog(#"%#",identifier);
self.achivment = [[GKAchievement alloc]initWithIdentifier:identifier];
self.achivment.showsCompletionBanner = YES;
if (!self.achivment.completed) {
self.achivment.percentComplete = 100;
NSLog(#"Reproting!");
[self.achivment reportAchievementWithCompletionHandler: ^(NSError *error)
{
}];
}
else {
NSLog(#"Achivment Completed!");
} }
what I am trying to do here is to set the percent completed to 100 and report it so in the next time ie want get called again.
but it always works... any better idea for how to handle this?
in interface add variable & property:
NSMutableDictionary *earnedAchievementCache;
#property (nonatomic, retain)NSMutableDictionary *earnedAchievementCache;
in .m:
#synthesize earnedAchievementCache;
- (void) submitAchievement: (NSString*) identifier percentComplete: (double) percentComplete
{
if(self.earnedAchievementCache == NULL)
{
[GKAchievement loadAchievementsWithCompletionHandler: ^(NSArray *scores, NSError *error)
{
if(error == NULL)
{
NSMutableDictionary* tempCache= [NSMutableDictionary dictionaryWithCapacity: [scores count]];
for (GKAchievement* score in scores)
{
[tempCache setObject: score forKey: score.identifier];
}
self.earnedAchievementCache= tempCache;
[self submitAchievement: identifier percentComplete: percentComplete];
}
}];
}
else
{
GKAchievement* achievement= [self.earnedAchievementCache objectForKey: identifier];
if(achievement != NULL)
{
if((achievement.percentComplete >= 100.0) || (achievement.percentComplete >= percentComplete))
{
achievement= NULL;
}
achievement.percentComplete= percentComplete;
}
else
{
achievement= [[[GKAchievement alloc] initWithIdentifier: identifier] autorelease];
achievement.percentComplete= percentComplete;
[self.earnedAchievementCache setObject: achievement forKey: achievement.identifier];
}
if(achievement!= NULL)
{
//Submit the Achievement...
if (achievement.percentComplete>=100) {
//show banner
achievement.showsCompletionBanner = YES; //only in IOS 5+
}
[achievement reportAchievementWithCompletionHandler: ^(NSError *error)
{
if (error!=NULL){
NSLog(#"Error!!");
} else NSLog(#"all is well");
}];
}
}
}
in dealloc :
[self.earnedAchievementCache release];
i'm using the cache to not submit scores already submitted / completed
PS: the code is perfect just copy and paste it into your class and it will work
this is what I use in my helper Game Center class:
-(void) reportAchievementWithID:(NSString*) AchievementID {
[GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error) {
if(error) NSLog(#"error");
for (GKAchievement *ach in achievements) {
if([ach.identifier isEqualToString:AchievementID]) { //already submitted
NSLog(#"Already submitted");
return ;
}
}
GKAchievement *achievementToSend = [[GKAchievement alloc] initWithIdentifier:AchievementID];
achievementToSend.percentComplete = 100;
achievementToSend.showsCompletionBanner = YES;
[achievementToSend reportAchievementWithCompletionHandler:NULL];
}];
}
note: I don't use percentages in my achievements, so you'd need to modify things a little bit if you do.

Game Center multiplayer code

As per the docs, I'm using:
- (void) match:(GKMatch*) match
player:(NSString*) playerID
didChangeState:(GKPlayerConnectionState) state;
to carry out the initial game negotiation. I do this in the scope of:
if (matchStarted_ == NO && [match expectedPlayerCount] == 0) { ... }
I need to decide which device is responsible for setting up the game. I do this by sorting the match.playerIDs NSArray instance and comparing the [GKLocalPlayer localPlayer].playerID NSString to the playerID NSString at index 0 of the sorted array. This player creates the game, sending out the data to all players.
However, and even with an expectedPlayerCount of 0, the playerIDs array has zero entries at this point, giving me an array overrun. Why is that? And what should I do instead to make a well-defined choice of player to generate the game?
For the decision code, take a look at the GKTank example provided by Apple - they take a hash of the device id, send it to the other client, and whichever has the lower number is the "host". That seems like a pretty solid way to decide.
here is sample code to do that thing
NSString *uid = [[UIDevice currentDevice] uniqueIdentifier];
CoinTossID = [uid hash];
now in delegate Function
- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID
{
NSMutableArray *ReceivedArray = [[NSMutableArray alloc] init];
ReceivedArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];
int flag = [[ReceivedArray objectAtIndex:0] intValue];
[ReceivedArray removeObjectAtIndex:0];
int CoinValue = [ReceivedCoinTossID intValue];
if(CoinValue > CoinTossID)
{
isPlayer1 = YES;
}
else
{
isPlayer1 = NO;
}
}

iPhone read image from socket

I am working in a little app for iphone base on ideas used to make an Android app.
To test, obviously i use the simulator, but the simulator don't have support for built-in camera. The Android idea to test this consist in use a WebCamBroadcaster Java app in the desktop to capture frames from built-in webcam and pass it through socket. Then in the app you just read the bytes and convert to image.
Well i was trying to do the same thing with iPhone Simulator. Searching in the web a found a class to work with asynchronous sockets (cocoaasyncsocket). But i can't make it work.
The Java App send the frames like this:
socket = ss.accept();
BufferedImage image = videoCapture.getNextImage();
if (image != null) {
OutputStream out = socket.getOutputStream();
if (RAW) {
image.getWritableTile(0, 0).getDataElements(0, 0, w$
image.releaseWritableTile(0, 0);
DataOutputStream dout = new DataOutputStream(new Bu$
out));
for (int i = 0; i < data.length; i++) {
dout.writeInt(data[i]);
}
dout.close();
} else {
ImageIO.write(image, "JPEG", out);
}
}
The Android version of this use C code to implement de socket reading proccess like this:
long read_count, total_read = 0;
while (total_read < readBufSize)
{
read_count = read(sockd, &readBuf[total_read], readBufSize);
if (read_count <= 0 || errno != 0)
{
char buffer[100];
sprintf(buffer, "socket read errorno = %d", errno);
LOGV(buffer);
break;
}
total_read += read_count;
}
// If we read all of the data we expected, we will load the frame from the p$
if (total_read == readBufSize){
frame = loadPixels(readBuf, width, height);}
Where readBufsize = width*height*sizeof(int);
readBuf = (char*)malloc(readBufSize);
So i try to implement the same for iPhone but i have an error in the connection (errno = 2).. Then i find cocoaasyncsocket and i try to use but i have an unknown error and nothing is read:
#import <Foundation/Foundation.h>
#import "AsyncSocket.h"
#interface Captura : NSObject {
NSString *ipserver;
UInt16 port;
NSError *errPtr;
AsyncSocket *socket;
NSMutableData *socketData;
}
#property (nonatomic,retain) NSString *ipserver;
#property (retain) AsyncSocket *socket;
#property (retain) NSError *errPtr;
//will contain de data read from socket
#property (retain) NSMutableData *socketData;
-(id)initWithIp:(NSString*)ip puerto:(UInt16)p;
-(BOOL)open;
-(void)close;
-(void)beginRead;
- (UIImage*)getImage;
#end
and the implementation
#import "Captura.h"
#implementation Captura
#synthesize ipserver;
#synthesize socket;
#synthesize errPtr;
#synthesize socketData;
-(id)initWithIp:(NSString*)ip puerto:(UInt16)p{
if (self = [super init]) {
ipserver = ip;
port = p;
socket = [[AsyncSocket alloc] initWithDelegate:self];
socketData = [[NSMutableData alloc] init];
}
return self;
}
//Connect
-(BOOL)open{
return [socket connectToHost:ipserver onPort:port error:&errPtr];
}
-(void)beginRead{
NSLog(#"Begin Read");
NSUInteger offset = [socketData length];
[socket readDataWithTimeout:1
tag:0];
}
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port{
NSLog(#"Conectado al servidor");
}
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
NSLog(#"Data leida %u",[data length]);
[socketData appendData:data];
[self beginRead];
}
- (void)onSocketDidDisconnect:(AsyncSocket *)sock{
[socketData release];
[ipserver release];
[socket release];
NSLog(#"MutableData length %u", [socketData length]);
NSLog(#"Socket Desconectado");
}
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err{
NSLog(#"OcurriĆ³ un error desconectando.... %#",err);
}
- (UIImage*)getImage{
NSData *data;
[socketData getBytes:data length:320*480*sizeof(int)];
NSLog(#"Data obtenida %#",[data length]);
if ([socketData length]>320*480*sizeof(int)) {
[socketData replaceBytesInRange:NSMakeRange(0,320*480*sizeof(int)) withBytes:NULL length:0];
}
if (data!=nil && [data length]) {
UIImage *img = [[UIImage alloc] initWithData:data];
[data release];
return img;
}
[data release];
return nil;
}
#end
Well this code connect to the server and initialize the reading process and then close up.. socket is disconnect and the app is close.
i can't test de getImage method yet...
Some idea?
Thanks in advance...
I think you need a call to -beginRead in -onSocket:didConnectToHost:port: