How to implement pause/resume in cocos2d game? - iphone

My question is to look for design solution for pause/resume states (including all data info, which need save ) during cocos2d game.
Including following cases, but not limited:
1). User choose quit, then pop out one dialog for user to choose " quit directly", " pause " ;
2). Someone call in , pop out dialog for user to choose "quit " or " pause " game.
If choose "pause", everything which deserve saving, should be saved. Just like PC games do.
I know Director provides "pause" , "resume " , is that okay for this task ?
Thanks for anyone clues or comments.
Welcome for further discussing via email : apple.dev.sh#gmail.com

Here is a good example:
To pause:
- (void) applicationDidEnterBackground:(UIApplication *)application
{
[[CCDirector sharedDirector] stopAnimation];
[[CCDirector sharedDirector] pause];
}
- (void)applicationWillResignActive:(UIApplication *)application
{
[[CCDirector sharedDirector] stopAnimation];
[[CCDirector sharedDirector] pause];
}
When resuming:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[[CCDirector sharedDirector] stopAnimation]; // call this to make sure you don't start a second display link!
[[CCDirector sharedDirector] resume];
[[CCDirector sharedDirector] startAnimation];
}

Related

Cocos2d implementation of Pause - The Game scene/layer issue

I am trying to create pause screen for my game. The game is developed upon continuous scrolling background (top to bottom) with obstacles which are moving independently (left to right).
Below is the code:
PauseScene.h
#interface PauseScene : CCNode {}
#property (nonatomic, retain) HelloWorldScene *mainScene;
//+ (PauseScene *)scene;
- (id) init;
#end
PauseScene.m
#implementation PauseScene
- (id) init {
if (self = [super init]) {
// Adding RESUME and QUIT button and few others to make the whole Pause screen
}
return self;
}
// Called the method when Resume button is selected
- (void) Resume:(id) sender {
//[[CCDirector sharedDirector] startAnimation];
//[[CCDirector sharedDirector] resume];
self.mainScene.userInteractionEnabled = YES;
[self.mainScene removeChild: self];
[self.mainScene StartGame]; // StartGame in MainScene contains the same code which commented out above, I will paste StartGame method later
}
// Quit method is called when the Quit button is pressed
- (void) Quit:(id) sender {
//[[CCDirector sharedDirector] resume];
//[[CCDirector sharedDirector] startAnimation];
self.mainScene.userInteractionEnabled = YES;
[self.mainScene removeChild: self];
NSLog(#"Pre Reload", nil);
//[self.mainScene scheduleOnce:#selector(ReloadGame) delay: 1.0f];
[self.mainScene ReloadGame]; // Reload method contains the code commented above
}
#end
PauseScene is mere node class.
StartGame and ReloadGame methods in MainScene file
- (void) StartGame {
// Create and display HUD layer, like, scores, navigation buttons, etc.
// Resuming the game
//[[CCDirector sharedDirector] stopAnimation];
[[CCDirector sharedDirector] resume];
[[CCDirector sharedDirector] startAnimation];
}
- (void) ReloadGame {
// Resume the game
//[[CCDirector sharedDirector] stopAnimation];
[[CCDirector sharedDirector] resume];
[[CCDirector sharedDirector] startAnimation];
[[CCDirector sharedDirector] replaceScene:[HelloWorldScene scene] withTransition:[CCTransition transitionFadeWithDuration:1.0f]];
}
The pause button is displayed in HUD layer of MainScene, so, when the pause button is clicked, we will pause the game and display the PauseScene
- (void)onPauseClicked:(id)sender {
// Code to display the pause node of this scene
// Pause the game
[[CCDirector sharedDirector] stopAnimation];
[[CCDirector sharedDirector] pause];
}
When I comment out that stopAnimation and pause part the Pause and Resume works perfect. But when I implement any of these, at the time of quitGame, replaceScene is not working somehow. I think this is because game goes in pause mode but it is not working even if I call replaceScene using scheduler on delay of 5-10 seconds.
And if I don't use these stopAnimation and pause, some sprites which are given CCAction are not being paused and goes on even when my game is paused.
Your help is appreciated because I am using Cocos2d 3.0 and unable to find any proper help.
Thanks #LearnCocos2D for your tips.
I am able to successfully implement pause/resume by just removing the code stopAnimation or startAnimation and pause and resume methods. I just replaced these all with paused property for the node.
To pause the game, need to set paused = YES for every node in the game and reverse to resume.

iphone cocos2d v2.0.0-rc0 - can't disable touch

I've been trying to resolve a problem for a long time, unfortunately i couldn't find a solution. I hope you can help me...
I'm trying to develop a turn based game. Player 1 is the user, player 2 is the iphone. I want to receive touches when it's the player1's turn.
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
if (self.playerNo==1) { //control player1
CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
[self selectSpriteForTouch:touchLocation];
return YES;
}
//if it's not player1's turn, return NO
return NO;
}
When it's iphones turn, I want to disable touches during 5 seconds. I tried all the ways below, but no success.
-(void)iphonesTurn
{
[NSThread sleepForTimeInterval:5];
//
//game logic...
//
}
During 5 seconds I touch screen several times. I realised that all the touches looks like stored and the app reacts to all of my touches when it's the player1's turn.
How can I completely disable touches?
Thanks for your help.
I don't know where is located your snippet of code but if it runs into the main thread you must NEVER block (pause) it!
Try to do something like that (it works with the final version of cocos2d 2.0):
- (void)iphonesTurn
{
[[[CCDirector sharedDirector] touchDispatcher] setDispatchEvents:NO];
[self scheduleOnce:#selector(enableTouch) delay:5.0f];
}
- (void)enableTouch
{
[[[CCDirector sharedDirector] touchDispatcher] setDispatchEvents:YES];
}

Replacing Scene and Stop All Animations and Sounds

I have a home button on my scene which when pressed goes to the home menu. I use replaceScene to replace the current scene (Game Scene) with the HomeMenu Scene. For some reason the actions and sounds which are happening in the game scene are not stopped when I replace the scene. I have tried the following code but still when I am in the home menu I can hear the actions and sounds of the game scene playing.
// fired when the home menu is
clicked!
-(void) homeMenuClicked:(CCMenuItem *) item { NSLog(#"home menu clicked!");
CCScene *scene = [[CCDirector
sharedDirector] runningScene]; [scene
stopAllActions];
[self.layer stopAllActions];
[self unloadSoundEffects];
[[CCDirector sharedDirector]
replaceScene:[CCSlideInLTransition
transitionWithDuration:1.0
scene:[HomeScene scene]] ];
}
I must also add that the game layer also has a timer (NSTimer) object which starts in 2 seconds or something.
UPDATE 2:
Let me post some code! I think the problem is that when the player guess the correct answer the following method is invoked:
[self updateForCorrectAnswer];
Inside updateForCorrectAnswer I have a performSelector which is scheduled to fire in 6-7 seconds. I believe that performSelector is the culprit. If somehow can I stop that from being firing then the I think I will be fine.
[self performSelector:#selector(refreshScore) withObject:nil afterDelay:7.0];
You should not use NSTimer as cocos2d documents.
/* call scheduleUpdate in initializing */
[self scheduleUpdate];
It schedules update: method to be called every frame when this node is on the stage.
- (void)update:(ccTime)dt
{
/* This method is automatically called every frame. */
}
scheduleUpdateWithPriority:, schedule:interval: are also available.
And why don't you use like this instead of performSelector:withObject:afterDelay.
[self runAction:[CCSequence actions:[CCDelayTime actionWithDuration:7], [CCCallFunc actionWithTarget:self selector:#selector(refreshScore)], nil]];
If you use this method "[self performSelector:withObject:afterDelay:]", cocos2d will not manage it in this run loop. You should use it instead of the previous one:
[self schedule:interval:];
Then in your "homeMenuClicked:" method, just call this:
[self.layer unschedule:#selector(refreshScore)];
I haven't tried it but I think it'll be better.
For more information you can see the documentation here.

Can scripting in iphone app instantiate a variable

I am trying to understand the benefit of using a scripting language like lua in game development on the iphone (using cocos2d for instance) and if it can help solve my problem (and improve my coding skills).
In my game I have the following code:
-(void)MenuItem:(CCMenuItem *) menuItem {
switch (menuItem.tag) {
case 1:
[[CCDirector sharedDirector] replaceScene:[Level1 scene]];
break;
case 2:
[[CCDirector sharedDirector] replaceScene:[Level2 scene]];
break;
case 3:
[[CCDirector sharedDirector] replaceScene:[Level3 scene]];
break;
case 4:
[[CCDirector sharedDirector] replaceScene:[Level4 scene]];
break;
case 5:
[[CCDirector sharedDirector] replaceScene:[Level5 scene]];
break;
case 6:
[[CCDirector sharedDirector] replaceScene:[Level6 scene]];
break;
case 7:
[[CCDirector sharedDirector] replaceScene:[Level7 scene]];
break;
case 8:
[[CCDirector sharedDirector] replaceScene:[Level8 scene]];
break;
default:
break;
}
The problem with that function is if I have 50 levels, this function will take 3 pages of code. I would like to replace this entire function with:
-(void)MenuItem:(CCMenuItem *) menuItem {
[[CCDirector sharedDirector] replaceScene:[<script> #"Level" + menuItem.tag</script> scene]];
}
where script> /script> would be a way to embed a scripting language that would concatenate the string "Level" and the level number, thus creating the name of the class. So this function would be independent of the number of levels.
So my question is: Can scripting help ? If yes, how can it help and if no, is there a solution to do that?
I'd suggest this:
NSString *levelToLoad = [NSString stringWithFormat:#"Level%d", menuItem.tag];
[[CCDirector sharedDirector] replaceScene:[NSClassFromString(levelToLoad) scene]];
Yeah, I just saved you hours of typing.
AppStore rules prohibit the use of scripting languages in your apps.
But that is not your problem, you could use the reflection API:
[[NSClassFromString([NSString stringWithFormat:#"Level%i", menuItem.tag]) scene]];
Which is not the best way to go, since you are in control of all the code, therefore you don't need to use it, it "just works" and feels hacky.
You should rather implement a level manager and have it search for the given level for you (example):
[MyLevelManager levelWithId:menuItem.tag];

Implementing iphone's copy/paste controls on a custom view / uiview subclass

I will admit that there is already a question exactly along these lines here on S.O., but it lacks implementation details, a working answer, and I would like to be more specific, so I think a new question is in order. Obviously, let me know if I'm wrong and we can try to restart the thread over there.
Basically, I want to copy the text in a UILabel to the pasteboard when a user holds down on the label. Not hard to do, honestly. However, I think the best way to provide visual feedback is to prompt the user with the Copy menu option from UIMenuController.
According to the Event Handling section of the iPhone Application Programming Guide, specifically the section on Copy, Cut, and Paste Operations, it should be possible to provide copy, cut, and/or paste operations from a custom view.
So, I've sub-classed UILabel with the following implementation as described by the guide, but the UIMenuController won't show up. There's no indication in the guide that there's anything else required to do this, and the NSLog statement does print out to the console, indicating that the selector is being performed when I hold down on the label:
//
// CopyLabel.m
// HoldEm
//
// Created by Billy Gray on 1/20/10.
// Copyright 2010 Zetetic LLC. All rights reserved.
//
#import "CopyLabel.h"
#implementation CopyLabel
- (void)showCopyMenu {
NSLog(#"I'm tryin' Ringo, I'm tryin' reeeeal hard.");
// bring up editing menu.
UIMenuController *theMenu = [UIMenuController sharedMenuController];
// do i even need to show a selection? There's really no point for my implementation...
// doing it any way to see if it helps the "not showing up" problem...
CGRect selectionRect = [self frame];
[theMenu setTargetRect:selectionRect inView:self];
[theMenu setMenuVisible:YES animated:YES]; // <-- doesn't show up...
}
// obviously, important to provide this, but whether it's here or not doesn't seem
// to change the fact that the UIMenuController view is not showing up
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
BOOL answer = NO;
if (action == #selector(copy:))
answer = YES;
return answer;
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self performSelector:#selector(showCopyMenu) withObject:nil afterDelay:0.8f];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(showCopyMenu) object:nil];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(showCopyMenu) object:nil];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(showCopyMenu) object:nil];
}
#end
So, what else does one have to do to make this happen?
For those following along and trying to do this, too, you'll also need to set 'User Interaction Enabled' for the label
Edit:
For clarity, let me add that this should be similar to the little [Copy] menu item that appears over an image in certain iphone views when you hold down on it. -B
I'll say upfront I don't have an aswer, but I did some poking around and found more out. I'm sure you've looked at this already: CopyPasteTile
That code does work on my simulator and goes like this:
CGRect drawRect = [self rectFromOrigin:currentSelection inset:TILE_INSET];
[self setNeedsDisplayInRect:drawRect];
UIMenuController *theMenu = [UIMenuController sharedMenuController];
[theMenu setTargetRect:drawRect inView:self];
[theMenu setMenuVisible:YES animated:YES];
There are a few differences here:
drawRect is calculated from a giant view tile and tap point calculations
setNeedsDisplayInRect is being called
self is a large screen sized view, you may need screen coords instead of local coords (you can probably get that from self.superview)
I'd try making these adjustments to match the example first and see what kind of progress it gets me.