Game Center multiplayer code - iphone

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;
}
}

Related

Int decimal count in iPhone

I need to know whatever an int64_t has decimals, and how many. This should be placed in if-else-statement. I tried this code, but it causes the app to crash.
NSNumber *numValue = [NSNumber numberWithInt:testAnswer];
NSString *string = [numValue stringValue];
NSArray *stringComps = [string componentsSeparatedByString:#"."];
int64_t numberOfDecimalPlaces = [[stringComps objectAtIndex:1] length];
if (numberOfDecimalPlaces == 0) {
[self doSomething];
} else {
[self doSomethingElse];
}
Your question doesn't make a lot of sense; you are creating the NSNumber object from an int so it will never have decimal places, as an int cannot store them. The reason your code is crashing is that it assumes that the array of components is always at least 2 elements long (as you use objectAtIndex:1).
This is better, though still not that good:
NSString *answer = ...; // From somewhere
NSArray *stringComps = [answer componentsSeparatedByString:#"."];
if ([stringComps count] == 0) {
[self doSomething];
} else if [stringComps count] == 1) {
[self doSomethingElse];
} else {
// Error! More than one period entered
}
This still isn't a very good test as it only tests if a period (.) has been entered, not a valid number.

nsarray switching image texture randomly everyone one second

I have an array that has 2 balloon textures,one green and one red.I have 12 green balloon object at the start of the app.Basically I want one random green balloon to turn red every one second.If anyone can help it would be appreciated.
init method
balloonTextures = [NSMutableArray array];
[balloonTextures addObject:[SPTexture textureWithContentsOfFile:#"greenballoon.png"]];
[balloonTextures addObject:[SPTexture textureWithContentsOfFile:#"redballoon.png"]];
[balloonTextures retain];
playFieldSprite = [SPSprite sprite];
[self addChild:playFieldSprite];
[self addBalloon];
add ballon method
-(void)addBalloon
{
for(int i = 0; i < 12; i++)
{
SPImage *image = [SPImage imageWithTexture:[balloonTextures objectAtIndex:0]];
image.x = 40*i;
image.y = 10 ;
[playFieldSprite addChild:image];
}
}
For getting random number:
#include <stdlib.h>
int r = arc4random() % 12;
Use a NSTimer to be called every second: How do I use NSTimer?
You could use CADisplayLink instead of NSTimer. The reason is that CADisplayLink is synchronized its drawing to the refresh rate of the display.
How to setup CADisplayLink:
id displayLink = [NSClassFromString(#"CADisplayLink") displayLinkWithTarget:self selector:#selector(changeBalloonTexture)];
[displayLink setFrameInterval:60]; // refresh rate is 60fps, 1=60fps, 60=1fps
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
How to check whether CADisplayLink is supported or not on the particular device:
// code from cocos2d
displayLinkSupported = FALSE;
NSString *reqSysVer = #"3.1";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending)
displayLinkSupported = TRUE;
For this you'll need to keep track of Green Balloons & change one of them to red randomly.
Put all your balloon sprites in one NSArray say balloonArray & schedule a timer to run a method every second. In that method, iterate the balloonArray, & collect all green balloons into another array say greenBalloonsArray.
Then use arch4random() method to generate a random number (index) from 0 to the length of greenBalloonsArray. Use random number as an index of newly created greenBalloonsArray to fetch the balloonSprite and change it's texture to red.
// Sudo Code
// Add all objects to one array
NSMutableArray *balloonsArray = [[NSMutableArray alloc] initWithObjects: ..... ];
- (void) timerMethod
{
__block NSMutableArray *greenBalloonsArray = [[NSMutableArray alloc] init];
[balloonsArray enumerateObjectsUsingBlock:^(BalloonSprite *object, NSUInteger idx, BOOL *stop) {
if (object.isGreen)
[greenBalloonsArray addObject:object];
}];
int index = arc4random() % greenBalloonsArray.count;
GreenBallonArray * greenBalloon = [greenBalloonsArray objectAtIndex:index];
[greenBallon turnToRed];
}

How do I get the index of an object in an NSArray using string value?

I want to get the index of an object within the NSMutableArray of categories.
The category object has an attribute "category_title" and I want to be able to get the index by passing the value of category_title.
I have looked through the docs and can't find a simple way to go about this.
NSArray does not guarantee that you can only store one copy of a given object, so you have to make sure that you handle that yourself (or use NSOrderedSet).
That said, there are a couple approaches here. If your category objects implement isEqual: to match category_title, then you can just use -indexOfObject:.
If you can't do that (because the category objects use a different definition of equality), use -indexOfObjectPassingTest:. It takes a block in which you can do whatever test you want to define your "test" - in this case, testing category_title string equality.
Note that these are all declared for NSArray, so you won't see them if you are only looking at the NSMutableArray header/documentation.
EDIT: Code sample. This assumes objects of class CASCategory with an NSString property categoryTitle (I can't bring myself to put underscores in an ivar name :-):
CASCategory *cat1 = [[CASCategory alloc] init];
[cat1 setCategoryTitle:#"foo"];
CASCategory *cat2 = [[CASCategory alloc] init];
[cat2 setCategoryTitle:#"bar"];
CASCategory *cat3 = [[CASCategory alloc] init];
[cat3 setCategoryTitle:#"baz"];
NSMutableArray *array = [NSMutableArray arrayWithObjects:cat1, cat2, cat3, nil];
[cat1 release];
[cat2 release];
[cat3 release];
NSUInteger barIndex = [array indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
if ([[(CASCategory *)obj categoryTitle] isEqualToString:#"bar"]) {
*stop = YES;
return YES;
}
return NO;
}];
if (barIndex != NSNotFound) {
NSLog(#"The title of category at index %lu is %#", barIndex, [[array objectAtIndex:barIndex] categoryTitle]);
}
else {
NSLog(#"Not found");
}
Not sure that I understand the question but something like this might work (assuming the Mutable Array contains objects of Class "Category"):
int indx;
bool chk;
for (Category *aCategory in theArray)
{
chk = ([[aCategory category_title] isEqualToString:#"valOfCategoryTitle"])
if ( chk )
indx = [theArray indexOfObject:aCategory];
}
Try this code much more simpler:-
int f = [yourArray indexOfObject:#"yourString"];

how do I create fresh NSMutableArray?

I have an NSMutableArray which only lasts during the session.
Currently I create it like this
NSMutableArray *temp = [[NSMutableArray alloc] initWithCapacity:10];
[self setScoreArray:temp];
[temp release];
Problem is when I go to check each index I'm getting an array outofbounds error
NSNumber *previousScore = [[self scoreArray] objectAtIndex:[self quizNum]];
if ( previousScore != nil )
{
[self clearQuizBtns];
NSInteger previousScoreValue = [previousScore integerValue];
[self selectButtonAtTag:previousScoreValue];
}else {
[self clearQuizBtns];
}
I've read in other posts that initWithCapacity doesn't actually create the array. So what can I populate the array with initially?
Thanks in advance.
Two ways:
first: to initiate array with default values of NSNull class
NSMutableArray *temp = [[NSMutableArray alloc] initWithCapacity:10];
for (int i = 0 ; i < 10 ; i++)
{
[temp insertObject:[NSNull null] atIndex:i];
}
[self setScoreArray:temp];
[temp release];
and then to check: if object is kind of NSNull class means it was a never set before
id previousScore = [[self scoreArray] objectAtIndex:[self quizNum]];
if (![previousScore isKindOfClass:[NSNull class]])
{
[self clearQuizBtns];
NSInteger previousScoreValue = [(NSNumber *)previousScore integerValue];
[self selectButtonAtTag:previousScoreValue];
}else {
[self clearQuizBtns];
}
second: store scores in NSMutableDictionary and use NSNumber's as keys
// scoreDictionary property of NSMutableDictionary class must be declared in self
NSNumber *previousScore = [self.scoreDictionary objectForKey:[NSNumber numberWithInt:[self quizNum]]];
if (previousScore != nil)
{
[self clearQuizBtns];
NSInteger previousScoreValue = [previousScore integerValue];
[self selectButtonAtTag:previousScoreValue];
}else {
[self clearQuizBtns];
}
NSArray does not support "holes". The capacity is just a hint to the initializer.
You could either fill the array with placeholder objects or, more typically, change your algorithm to either fully prepopulate the array or to lazy load it linearly.
Your problem seems to be that you're never actually setting any score in the score array.. are you? NSArrays have an actual count of items in them, and accessing an index beyond that count will blow up, as you've seen. If there will only ever be a fixed (small) number of scores, like 10, then you could set them all initially to something default like:
for (int i = 0; i < 10; i++) {
[temp addObject:[NSNumber numberWithInt:0]];
}
P.S. -initWithCapacity does "create the array", it just doesn't create any objects in the array. The capacity is a hint only.
Using the arrayWithObject: or arrayWithObjects: methods can provide an array with pre-populated values.
One cool thing about NSMutableArrays is that you can just do an "init" and the array will handle adding and removing objects on the fly. Remember that you generally addObject: or removeObjectAtIndex: when dealing with mutable arrays.

Object in Array is not recognised as having "methods"

I got my application working Awhile back, but after completely and accidentally deleting it, I have tried to create it from square one. unfortunately my rewritten program is a bit cranky; does anyone see or know the possible sources of error? Also, my if statements are acting up.
-(void)loadAnnotations
{
CLLocationCoordinate2D workingCoordinate;
iProspectLiteAppDelegate *appDelegate = (iProspectLiteAppDelegate *)[[UIApplication sharedApplication] delegate];
NSMutableArray *mines =[[NSMutableArray alloc] initWithArray:(NSMutableArray *) appDelegate.mines];
BOOL gold = [[NSUserDefaults standardUserDefaults] boolForKey:#"goldControl"];
BOOL silver = [[NSUserDefaults standardUserDefaults] boolForKey:#"silverControl"];
BOOL copper = [[NSUserDefaults standardUserDefaults] boolForKey:#"copperControl"];
for(id mine in mines)
{
NSLog(#"in the loop");
workingCoordinate.latitude = [[mine latitudeInitial] doubleValue];
workingCoordinate.longitude = [[mine longitudeInitial] doubleValue];
iProspectLiteAnnotation *tempMine = [[iProspectLiteAnnotation alloc] initWithCoordinate:workingCoordinate];
[tempMine setTite:[mine mineName]];
if ([[mine commodity] isEqualToString:#"Gold"] && [gold == YES])
{
[tempMine setAnnotationType:iProspectLiteAnnotationTypeGold];
[mapView addAnnotation:tempMine];
}
if([[mine commodity] isEqualToString:#"Silver"] && [silver == YES])
{
[tempMine setAnnotationType:iProspectLiteAnnotationTypeSilver];
}
if([[mine commodity] isEqualToString:#"Copper"] && [copper == YES])
{
[tempMine setAnnotationType:iProspectLiteAnnotationTypeCopper];
}
}
[mines dealloc];
}
where the workingCoordinate.latitude = [[mine latitudeInitial] doubleValue], as well as the longitude, and [mine mineName],it says " No '-latitudeInitiallongitudeInitial' method found" or the mineName/LongitudeInitial.
also, it complains about : before ] at all the if statement lines. I don't see any errors, do you?
You are using an iterator that is giving you objects of type id - calling a method on those will often confuse a compiler. Are you able to cast them to a known type?
Like for(MineType* mine in mines)?
And
[tempMine setTite:[mine mineName]];
Is that a typo? My guess is you would be calling that method setTitle.
i think changing the object type of mine object in the for loop to whatever custom class you have with latitudeInitial, longitudeInitial, mineName properties/methods should solve this.