Game Center lag with Memory Warning - iphone

I have almost finished an iPhone game made with cocos2d 2.0, and the last thing I did was add Game Center. I am using an iPod 4 for testing. I followed this tutorial: http://www.raywenderlich.com/23189/whats-new-with-game-center-in-ios-6
The problem is that when I try to submit a score to Game Center, the game starts to stutter / lag like crazy for 5-10 seconds. This happens when I call the following:
[gkScore reportScoreWithCompletionHandler:
^(NSError* error) {
[self setLastError:error];
BOOL success = (error == nil);
if ([_delegate
respondsToSelector:
#selector(onScoresSubmitted:)]) {
[_delegate onScoresSubmitted:success];
}
}];
The score is sent successfully without errors, but the game lags a lot when sending and memory warnings appear in the console. This problem seems to be related to a "CONNECTION INTERRUPTED" message that appears in the console beforehand, that seems to occur when the game's memory usage is around 60MB. The game doesn't lag when I try submitting a score earlier, before that message appears.
I searched around and found it strange that nobody else seems to complain about this, is this normal? Any help is much appreciated, thanks!

Related

Music not stopping when moving an app to the background

I am optimizing a game so that when there is an incoming call or if it is moved to the background for any other reason, it should stop the music, timers and pause correctly.
It works great other than the fact that for some reason the music doesn't stop playing even though I issued a command for it to stop. What's weirder is that when the game returns to the foreground there's 2 background musics playing instead of one.
Here is my some of my code, nothing too complicated or out of the ordinary:
...
NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.KEEP_AWAKE;
NativeApplication.nativeApplication.addEventListener(Event.ACTIVATE, handleActivate);
NativeApplication.nativeApplication.addEventListener(Event.DEACTIVATE, handleDeactivate);
...
private function handleActivate(event:Event):void
{
stage.frameRate = previousFrameRate;
//if the music was on when the game is moved to the background, then replay it when its moved back to the foreground
if(musicOn)
{
BGMusic.play();
}
}
private function handleDeactivate(event:Event):void
{
BGMusic.stop();
stage.frameRate = 0;
}
It is worth noting that if I don't replay the music when then game returns to the foreground (i.e. when I don't use BGMuusic.play() in handleActivate), there won't be any music as expected. It is only when I stop the music AND resume it later when moving to the foreground that the background music doesn't stop and I get two playing tracks.
Any ideas? As I said, everything else works fine, and the game correctly pauses. I am testing this on Flash builder Emulator since I don't have the necessarily certificates to test it directly on the iphone. So maybe it is a problem with the emulator itself rather than the code.
Thanks in advance
EDIT: Am writing this with flash and adobe air
Well that was stupid of me. Everything is working fine I just forgot to add another condition to the if statement. So instead of:
if(musicOn)
{
BGMusic.play();
}
It should be
if(musicOn && !BGMusic.isPlaying())
{
BGMusic.play();
}
Everything works fine now...I will change the variable name of musicOn to something clearer like musicButtonOn.
Anyways thanks for help. If you have any tips or comments feel free to tell me =D
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
NSLog(#"Playing stoped");
[player stop];
}

OpenAL initializing impairs performance of my iPhone game

I have a bad performance problem with OpenAL in my iPhone game. My game runs smoothly with 60fps but when I initialize OpenAL the game begins to jerk. This is my initialisation code:
ALCdevice* device = alcOpenDevice(NULL);
ALCcontext *context;
if(device) {
context = alcCreateContext(device, NULL);
alcMakeContextCurrent(context);
}
I don't create any OpenAL Sources nor load/play any sounds. The jittering (the game jerks all the time) is caused by the initializing of OpenAL.
The XCode instruments are saying that the game runs with stable 60fps yet it's obviously jittering (when I don't run the code above the game runs smoothly).
This also doesn't happen on an old iPod Touch 2G with iOS 3.1.3. On all my other devices with iOS 4 the jittering happens, which is also crazy.
I also tried to put the OpenAL stuff in a separate thread but it doesn't help.
Has anybody noticed a similar behaviour?
Try calling alcGetError() after context set up to ensure it succeeded.
Is this failing on the simulator or on an actual phone?
Are you doing anything with sound after the code you posted? In the code you posted if alcOpenDevice fails then you won't have a context, yet you don't return either.

Submitting Score to Game Center

I'm using a Game Center leaderboard, which works fine and shows scores as it should do. The only problem is when I simulate a network failure (well, put the phone into airplane mode) it still returns a null error when posting a score. The posting code is -
[scoreReporter reportScoreWithCompletionHandler: ^(NSError *error)
{
[self callDelegateOnMainThread: #selector(scoreReported:) withArg: NULL error: error];
}];
which you would expect to return "unsuccessful" in this case. I've no idea what's going on! Any help appreciated, thanks.
Well, I've sort of worked around it - I've used Apple's Reachability code just to check if the phone can connect, then I do the Game Center stuff. It's weird, but the Game Center doesn't show any error if there's no network when it submits a score, but it does if there is a network & it can't connect to its servers. Unless I'm doing something totally wrong, but it's more-or-less a cut & paste of their own example code.

How to play sound at precise moments on iPhone?

I'm working on creating a simple metronome on the iPhone. What the app does right now is to run a timer, entering the timer's function every 1/1000th of second. Then it checks the current time vs time of starting the app (I'm using CACurrentMediaTime() function).
CFTimeInterval currentTime = CACurrentMediaTime();
if (self.beatingStartTime == 0) {
self.beatingStartTime = currentTime;
}
if ( (currentTime - self.beatingStartTime) >= self.timeIntevalBetweenTicks * self.internalTimerCounter ) {
self.internalTimerCounter ++;
// ...
}
If there is a good moment to play audio, the code using OpenAL to play it gets fired.
Basicly that's it. I checked the sounds played when running both in simulator as well as on 2 devices (iPad and jailbroken iPhone 3GS) and there is a problem - when I recorded the sound and reviewed the waveform in Reaper software, some sounds play a bit too late, and some of them - bit too early (even I could understand the "too late" part, I don't really get how it can play earlier then it should - since the app checks the number of seconds every time, it basicly can't be ealier then specified time - yet it is, according to my recods).
At the same time there are some metronome apps that are known for being "rock-solid" when it comes to timing, so I guess there is a way. I just wonder what I'm missing...
edit: Changing timer call from 1/1000th second to, for example 1/100th doesn't help.
edit 2: When I switched from timer to threads (and I put the thread to sleep for specified time) I still get a strange behavior. The tempo moves around and while I could understand a little lag and playing some sounds too late, the problem is some of them do play too early - it means time distance between 2 beats is less then the time that should pass.
The diffrence is about 3%, which translates to about 10-15 miliseconds, which is quite a lot for me. Anyone got an idea why the sound can play earlier? I tried it both on iPhone simulator and on iPad actual device, and my only guess is there's something wrong with the timer - CACurrentMediaTime() returning more seconds that it should. Is it even possible?
Try using an NSSound, and load it up as an instance variable and don't release it unless your metronome isn't running. Delays can be caused by loading the file into memory on the loop. The other thing to consider is that a metronome probably doesn't need to poll every 1/1000th of a second. If you do it less often, you're less likely to saturate the CPU and you might get more consistent results.
Lastly, check out how Apple's demo works: http://developer.apple.com/library/ios/#samplecode/Metronome/Introduction/Intro.html
Might give you a better idea how to accomplish what you're trying to do :)
What you want is COCOS DENSHION which is a simple reliable easy to use sound library, that we have found solves all problems.
I (just personally) don't like "Cocos2D" but you can just take and use CocosDenshion.
Secondly -- 1000th of a second is ridiculous for a timer. Just totally forget it.
Thirdly -- AVAudioPlayer is worthless as you found.
Note - "ObjectAL" is a new, perhaps better, alternative
to CocosDenshion. Check it out.

GameCenter login alert

In a game I am developing using GameCenter, I want to handle the following scenario:
the user starts up the game. He is shown the system alert that prompts him to log on GameCenter. He ignores it for now.
after a while, the user wants to log in to GameCenter and clicks on(for instance) the Leaderboards menu item. He choses cancel instead of Log in, for now.
the process repeats several times. Eventually the user DOES want to log in to GameCenter. He clicks the Leaderboard menu item one more time.
In my tests, I have found that the alert popup raised by the call to "authenticateWithCompletionHandler" (as invoked by Apple's sample GameCenterManager) which suggests to log in to GameCenter only appears a limited number of times(4 or 5). The last time it appears, it says "Game Center Disabled, sign in with the Game Center application to enable"Afterwards". Afterwards, calling authenticateWithCompletionHandler no longer does anything visible -no prompt at all.
Playing FruitNinja I tried to replicate this. However, in their case, the popup saying "Game Center Disabled" does appear every time I click on a GameCenter item(Achievements, for instance).
What I'd like to do is to duplicate the functionality: that is, if you are not logged in to GameCenter, to have the standard game center alert appear all the times you click on the Leaderboard menu item.
Is there a way to learn whether the standard 'log in to game center' alert has appeared, or to force it to appear at all times(and not just the first couple of tries)?
Here's an is an idea to workaround this issue:
No matter if a "GC authenticateWithCompletionHandler"-Request is cancelled
by the user tapping "Cancel" in the dialog
or due to the fact that
GC is disabled on the device (which happens after the user has cancelled the alert-dialog exactly 3 times (in iOS 5 at least))
you will always receive an NSError with code 2 saying "The requested operation has been cancelled.".
The only differentiator that i could find is the time passed between the authenticateWithCompletionHandler-Request and the the execution of the completion-Handler.
So when sending the request i am saving the time:
requestTime = [NSDate date];
and in my completion handler i measure the time lapsed:
NSDate* now = [NSDate date];
CFTimeInterval elapsedTimeSinceAuthenticationRequest = [now timeIntervalSinceDate:requestTime];
NSLog(#"time Elapsed: %f", elapsedTimeSinceAuthenticationRequest);
If the user cancelled the request, the time passed will be significantly longer compared to the time passed if GC cancelled the operation. In my tests, it took a user at least one second to cancel the dialog, whereas a GC-cancelled request took less than 0.1 seconds (on my iPhone 4)
Of course, these values may vary depending on the device the code runs on and on what else the processor is busy with at the moment. One pitfall i already examined is the application launch: If you are sending the authenticationRequest during applicationDidFinishLaunching as suggested by Apple, it took much longer for GC to cancel the request in my case, because the device is busy loading views and whatever is necessary to launch the app.
So let me know if you tried this solution and if it worked for you, as will i once i have done further testing...
The behavior is something to the effect of, after N unsuccessful attempts - disable GameCenter for the app. Restarting the app or going to login in gamecenter itself will get it back online.
I forget which doc I read this in, but there is an Apple doc out there that explains this behavior.
I couldn't find a good answer for this either, so I decided to just replicate the message once the I start getting the cancel error. This is still in development but it basically changes the button callback to display the error alert rather than display the leader-board.
Just a note, not sure if this will be approved or not since I am replicating an Apple error message.
-(void) gcLogin: (id) sender {
[[GKLocalPlayer localPlayer] authenticateWithCompletionHandler:^(NSError *error) {
if(error) {
if([[error domain] isEqualToString:GKErrorDomain] && [error code] == GKErrorCancelled) {
[ResourceManager showAlertWithTitle:#"GameCenter Disabled" message:#"Sign in with Game Center application to enable"];
mGameCenterCancelled = YES;
}
NSLog(#"%#", [error description]);
} else {
[self updateMenu];
mGameCenterCancelled = NO;
}
}];
}
I am playing around with Game Center myself right now I have seen the very same behavior. There is nothing in the documentation saying anything about the dialog only showing up the first couple of times.
In my case I would like a way to tell beforehand if the user is already logged into Game Center, so that I can behave appropriately. But now I can not know this before the dialog is shown to the user.
Since we are running in the sandbox during development this behavior might of course be something that behaves differently during production but this is not an easy thing to find out.
May be the link will helpful (First three paragraphs):
http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/GameKit_Guide/Users/Users.html#//apple_ref/doc/uid/TP40008304-CH8-SW9
The main point is in a rectangle "Important".
I'm facing the same issue. Though I couldn't find a way to enforce poping up the same dialog for logging into Game Center, I did find a way to implement a warning message saying 'gamecenter is disabled' when user clicks on a leaderboard icon:
if([GKLocalPlayer localPlayer].authenticated == NO)
{
// Prompt a warning message alert saying game center is disabled
}
else
{
// Proceed with opening leaderboard
}
Hope this helps!
It appear that iOS will disable Game Center completely and prevent it from prompting after the user chooses to Disable Game Center (the option would appear on your fifth 5th Game Center cancel sign in).
To restore the device to the original state where the login prompt will appear again. Simply sign in using the Game Center app using a normal working Game Center account (non Tester). Once you are in, Sign Out. It should start prompting you again on within your app.