How to reset an scene in Cocos2d? - ios

How can I reset an scene (restart the countdown and set the score to 0) the second time I start it? The second time I load the scene both initWithParameters and onStart are not called.
Cocos2D Game:
-(id) initWithParameters:(NSArray *) parameters
{
NSLog(#"init TheButton with parameters");
// Apple recommend assigning self with supers return value
self = [super init];
if (!self) return(nil);
gameParameters = parameters;
// Enable touch handling on scene node
[self setIsTouchEnabled:YES];
// Create a colored background (Dark Grey)
//CCNodeColor *background = [CCNodeColor nodeWithColor:[CCColor colorWithRed:0.6f green:0.6f blue:0.6f alpha:1.0f]];
//[self addChild:background];
CCMenuItem *starMenuItem = [CCMenuItemImage
itemFromNormalImage:#"ButtonStar.png" selectedImage:#"ButtonStarSel.png"
target:self selector:#selector(increasePoints:)];
CGSize size = [[CCDirector sharedDirector] winSize];
starMenuItem.anchorPoint = ccp(0.5f,0.5f);
starMenuItem.position = ccp(size.width/2, size.height/2);
CCMenu *starMenu = [CCMenu menuWithItems:starMenuItem, nil];
starMenu.position = CGPointZero;
[self addChild:starMenu];
timeLabel = [CCLabelTTF labelWithString:#"0.00" fontName:#"Arial" fontSize:18.0f];
//timeLabel.positionType = CCPositionTypeNormalized;
timeLabel.position = ccp(30,size.height-10);
// Add the time label
[self addChild:timeLabel];
NSLog(#"time: %#", [gameParameters objectAtIndex:0]);
clicksLabel = [CCLabelTTF labelWithString:#"0" fontName:#"Arial" fontSize:18.0f];
//clicksLabel.positionType = CCPositionTypeNormalized;
clicksLabel.position = ccp(size.width - 20,size.height-10);
// Add the time label
[self addChild:clicksLabel];
[self startGame];
return self;
}
-(void) startGame
{
clicks = 0;
myTime = [[gameParameters objectAtIndex:0] intValue];
[self schedule:#selector(update:)];
}
The scene (a cocos2d game) is integrated in a storyboard project. When it finishes (the countdown arrives to 0) it loads a new viewcontroller. From this viewcontroller I would like to load the game again when when the user press the "Play Again" Button. What happens is the scene is loading (I implemented it with an unwind segue) but both the countdown and the score are not reseted, how can I do this?
EDIT:
I finally get to reload and reset the scene from the CocosViewController but when I call performSegueWithIdentifier when the game finishes it does not load the viewcontroller. Method viewdidload is called but it does not show anything.
Cocos2dGame:
-(void) onExit
{
[super onExit];
//Send parameters
self.gameTracking = [[NSMutableArray alloc] initWithObjects:#"THE",#"QUICK", #"BROWN", #"FOX",#"FOO", nil];
NSDictionary * userInfo = [[NSMutableDictionary alloc] initWithObjectsAndKeys: [NSString stringWithFormat:#"%d",clicks], #"score", self.gameTracking, #"gameTracking", nil];
//Send a notification to the CocosViewController when the game is finished to load the new view controller
[[NSNotificationCenter defaultCenter] postNotificationName:#"GameEndedNotification" object:self userInfo:userInfo];
NSLog(#"game exit");
//[[CCDirector sharedDirector] end];
}
Cocos2DViewController
//Receive notification when the game finished
-(void)receiveNotificationFromGame:(NSNotification *) notification
{
if ([[notification name] isEqualToString:#"GameEndedNotification"])
{
NSLog (#"Successfully received the test notification! %#", [self class]);
NSLog(#"score: %d", [notification.userInfo[#"score"] intValue]);
//get variables
try.score = [notification.userInfo[#"score"] intValue];
NSLog(#"score: %d", try.score);
try.gameTracking = notification.userInfo[#"gameTracking"];
//show the next view
[self performSegueWithIdentifier:#"sg_showScore" sender:self];
}
}

Related

UIMenuController's canPerformAction method called on button tap

I have a message view in which user can see conversation and type & send message. Menu (kind of context menu) is displayed when user long taps on message. I have used TableView and Button for chat history and send message button respectively.
My problem is canPerformAction:withSender method is hit when I tap on Button or TableView. And moreover this code was working fine till iOS 9.0.
#interface MessageDetailViewController ()
- (void)updateDetailView;
- (void)setMessageBar;
- (void)setCallButton;
#end
#implementation MessageDetailViewController
{
}
#synthesize messageField;
#synthesize messageList;
#synthesize messageBarView;
#synthesize navigationBarView;
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"MessageDetailView: viewDidLoad method called.");
// Observe keyboard hide and show notifications to resize the text view appropriately.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didHideEditMenu:) name:UIMenuControllerDidHideMenuNotification object:nil];
[messageField becomeFirstResponder];
messageArray = [[NSMutableArray alloc] init];
typingImage = [[UIImageView alloc] init];
presenceImage = [[UIImageView alloc] init];
navigationBarView = [[UIView alloc] init];
viewHeight = self.view.frame.size.height;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
[messageField setDelegate:self];
messageList.delegate = self;
messageList.dataSource = self;
[self updateDetailView];
[messageList reloadData];
}
- (BOOL)canBecomeFirstResponder
{
return YES;
}
/**
* This method is called to send instance method to server.
*/
- (void)onSendMessageButtonPressed:(id)sender
{
if([messageField.text length] == 0)
{
return;
}
messageField.text = [messageField.text substringToIndex:160];
[[DatabaseManager getDatabaseManager] addMessageInDatabase:messageField.text];
[messageField setText:#""];
[self updateDetailView];
[messageList reloadData];
}
-(void)handleLongPress : (UILongPressGestureRecognizer *)gesture
{
TableViewCell *cell = nil;
UIMenuController *menu = [UIMenuController sharedMenuController];
if(gesture.state == UIGestureRecognizerStateBegan)
{
CGPoint p = [gesture locationInView:self.messageList];
NSIndexPath *ip = [self.messageList indexPathForRowAtPoint:p];
rowPosition = ip.row;
NSLog(#"row = %d", ip.row);
if(ip)
{
cell = (TableViewCell *)[messageList cellForRowAtIndexPath:ip];
[self becomeFirstResponder];
[menu setMenuItems:nil];
UIMenuItem *copyMenuItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(#"COPY_MESSAGE", #"") action:#selector(copyMessage:)] autorelease];
UIMenuItem *deleteMenuItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(#"DELETE_MESSAGE", #"") action:#selector(deleteMessage:)] autorelease];
if(cell.imFailIndication.image != nil)
{
UIMenuItem *resendMenuItem = [[[UIMenuItem alloc] initWithTitle:NSLocalizedString(#"RESEND_MESSAGE", #"") action:#selector(resendMessage:)] autorelease];
[menu setMenuItems:[NSArray arrayWithObjects:copyMenuItem, deleteMenuItem, resendMenuItem, nil]];
}
else
{
[menu setMenuItems:[NSArray arrayWithObjects:copyMenuItem, deleteMenuItem, nil]];
}
[menu setTargetRect:cell.frame inView:cell.superview];
[menu setMenuVisible:YES animated:YES];
return;
}
}
}
- (void)copyMessage:(id)sender
{
MessageDetailInfo *detailMessageInfo = [messageArray objectAtIndex:rowPosition];
[UIPasteboard generalPasteboard].string = detailMessageInfo.message;
}
- (void)deleteMessage:(id)sender
{
messageDeleteActionSheet = [[UIActionSheet alloc] initWithTitle:NSLocalizedString(#"PROMPT_MESSAGE_DELETE_CONFIRMATION", #"") delegate:self cancelButtonTitle:NSLocalizedString(#"CANCEL_BTN_TITLE", #"") destructiveButtonTitle:NSLocalizedString(#"DELETE_BTN_TITLE", #"") otherButtonTitles:nil, nil];
[messageDeleteActionSheet showFromTabBar:self.tabBarController.tabBar];
}
/*
The view implements this method to conditionally enable or disable commands of the editing menu.
The canPerformAction:withSender method is declared by UIResponder.
*/
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
UIMenuController *menu = (UIMenuController *)sender;
switch ([[menu menuItems] count])
{
case 0:
//This case is to display paste option for Message text field.
if(action == #selector(paste:))
{
return YES;
}
break;
case 2:
if(action == #selector(copyMessage:) || action == #selector(deleteMessage:))
{
return YES;
}
break;
case 3:
if(action == #selector(copyMessage:) || action == #selector(deleteMessage:) || action == #selector(resendMessage:))
{
return YES;
}
break;
default:
break;
}
return NO;
}
- (void)keyboardWillShow:(NSNotification *)notification
{
/*
Reduce the size of the text view so that it's not obscured by the keyboard.
Animate the resize so that it's in sync with the appearance of the keyboard.
*/
NSDictionary *userInfo = [notification userInfo];
// Get the origin of the keyboard when it's displayed.
NSValue* aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
// Get the top of the keyboard as the y coordinate of its origin in self's view's coordinate system. The bottom of the text view's frame should align with the top of the keyboard's final position.
CGRect keyboardRect = [aValue CGRectValue];
// Get the duration of the animation.
NSValue *animationDurationValue = [userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSTimeInterval animationDuration;
[animationDurationValue getValue:&animationDuration];
// Animate the resize of the text view's frame in sync with the keyboard's appearance.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:animationDuration];
/* change position of messageBarView based on visibility of keypadview. */
CGRect messageBarFrame = messageBarView.frame;
messageBarFrame.origin.y = viewHeight - keyboardRect.size.height - messageBarView.frame.size.height;
messageBarView.frame = messageBarFrame;
if(messageBarFrame.origin.y == (viewHeight - keyboardRect.size.height - messageBarView.frame.size.height))
{
[messageField becomeFirstResponder];
}
/* change height of messageList based on visibility of keypadView. */
CGRect messageListFrame = messageList.frame;
messageListFrame.size.height = messageBarView.frame.origin.y;
messageList.frame = messageListFrame;
[UIView commitAnimations];
/* scroll to table view at last message if messages are available. */
if ([messageList numberOfRowsInSection:0])
{
[messageList scrollToRowAtIndexPath:[NSIndexPath indexPathForRow ([messageList numberOfRowsInSection:0] - 1) inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
}
- (void)keyboardWillHide:(NSNotification *)notification
{
NSDictionary* userInfo = [notification userInfo];
/*
Restore the size of the text view (fill self's view).
Animate the resize so that it's in sync with the disappearance of the keyboard.
*/
NSValue *animationDurationValue = [userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSTimeInterval animationDuration;
[animationDurationValue getValue:&animationDuration];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:animationDuration];
/* change position of messageBarView based on visibility of keypadview. */
CGRect newFrame = messageBarView.frame;
newFrame.origin.y = self.view.frame.size.height - messageBarView.frame.size.height;
messageBarView.frame = newFrame;
/* Don't update tableview if datasource has been set nil. */
if(messageList.dataSource != nil)
{
/* change height of messageList based on visibility of keypadView. */
CGRect messageListFrame = messageList.frame;
messageListFrame.size.height = messageBarView.frame.origin.y;
messageList.frame = messageListFrame;
}
[UIView commitAnimations];
}
- (void)didHideEditMenu:(NSNotification *)notification
{
[[UIMenuController sharedMenuController] setMenuItems:nil];
}
- (void)didReceiveMemoryWarning
{
/* Releases the view if it doesn't have a superview. */
[super didReceiveMemoryWarning];
/* Release any cached data, images, etc that aren't in use. */
}
- (void)viewDidUnload
{
[super viewDidUnload];
/* Release any retained subviews of the main view.
e.g. self.myOutlet = nil; */
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIMenuControllerDidHideMenuNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
messageList.delegate = nil;
messageList.dataSource = nil;
}
-(BOOL)navigationShouldPopOnBackButton
{
NSLog(#"navigationShouldPopOnBackButton appearedFromComposeView = %d", [[NSNumber numberWithBool:appearedFromComposeView] intValue]);
if(appearedFromComposeView)
{
[self.navigationController popToRootViewControllerAnimated:YES];
}
return YES; // Process 'Back' button click and Pop view controler
}
- (void)dealloc
{
[messageField release];
[messageList release];
[messageBarView release]
[messageArray release];
[super dealloc];
}
#end

App freezes for some seconds when presenting UIActivityView or when presenting a second SKScene

When I press the play Button or Share Button the app freezes, but only the first time.
After the first time it runs without a freeze.
The Duration of the freeze is 2-4 seconds.
I tried for awhile to find a solution, but everything I try does not work.
GameViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
SKView * skView = (SKView *)self.view;
SKScene * scene = [Menu sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[skView presentScene:scene];
}
- (void) openShare
{
int highScore = [self highScoreAbruf];
NSString *shareText= [NSString stringWithFormat:#"The HIghScore is %i", highScore];
NSArray *itemsToShare = #[shareText];
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:itemsToShare applicationActivities:nil];
[self presentViewController:activityVC animated:YES completion:nil];   
}
- (int) highScoreAbruf
{
NSUserDefaults *myHighScore = [NSUserDefaults standardUserDefaults];
int highScore = [myHighScore integerForKey:#"Score"];
return highScore;
}
Menu.m
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"PlayButton"])
{
PlayButton.hidden = YES;
PlayButtonPressed.hidden = NO;
[self restartButtonPressed];
//[self performSelector:#selector(restartButtonPressed) withObject:nil afterDelay:(0.5)];
}
if ([node.name isEqualToString:#"ShareButton"])
{
ShareButton.hidden = YES;
ShareButtonPressed.hidden = NO;
NSTimer *buttonTimer = [NSTimer scheduledTimerWithTimeInterval:(0.5)
target:self
selector:#selector(ShareMethod)
userInfo:NULL
repeats:NO];
}
}
- (void) restartButtonPressed
{
[self.scene.view presentScene:[GameMyScene sceneWithSize:self.size]];
}
- (void) ShareMethod
{
GameViewController *vc = self.view.window.rootViewController;
[vc openShare];
}

Why is an init method of a child not called by a parent allocating that child in cocos2d v2.0?

I have this Class:
//Interface
#interface SavingDataPlist : SimpleTimedGameRecipe
{
NSMutableArray *moles;
int tagCount;
int moleCount;
CCSprite *mallet;
CGPoint malletPosition;
}
-(CCLayer*) runRecipe;
-(void) step;
-(void) initBackground;
-(void) createMoleAtPosition:(CGPoint)point withZ:(float)z;
-(void) processMoleHit;
-(void) addHiScoresToMenu;
-(void) loadHiScores;
-(void) addHiScore;
-(void) deleteHiScores;
-(void) startNewGame;
-(void) gameOver;
-(void) step:(ccTime)delta;
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
#end
which in its reunRecipe method calls this:
[self createMoleAtPosition:ccp(50,205) withZ:0];
and that call corresponds to this method:
-(void) createMoleAtPosition:(CGPoint)point withZ:(float)z {
CCSpriteFrameCache *cache = [CCSpriteFrameCache sharedSpriteFrameCache];
CCSprite *back = [CCSprite spriteWithSpriteFrame:[cache spriteFrameByName:#"mole_back.png"]];
back.position = ccp(point.x, point.y);
[self addChild:back z:z tag:tagCount];
tagCount++;
Mole *mole = [Mole spriteWithSpriteFrame:[cache spriteFrameByName:#"mole_normal.png"]];
[mole setDownPosition:ccp(point.x,point.y-30)];
[self addChild:mole z:z tag:tagCount];
[moles addObject:mole];
NSLog(#"moles.count %d", moles.count);
tagCount++;
CCSprite *front = [CCSprite spriteWithSpriteFrame:[cache spriteFrameByName:#"mole_front.png"]];
front.position = ccp(point.x, point.y);
[self addChild:front z:z tag:tagCount];
tagCount++;
}
The Mole Class init method looks like this:
-(id)init {
NSLog(#"moleinit");
self = [super init];
if (self != nil) {
state = MOLE_DOWN;
CCSpriteFrameCache *cache = [CCSpriteFrameCache sharedSpriteFrameCache];
//
//MEVPCHANGE
//Create framenumber array to populate ccanimation later
NSMutableArray *animationFramesArray = [[NSMutableArray alloc] init];
NSMutableArray *animationFramesArray2 = [[NSMutableArray alloc] init];
//MEVPCHANGE - add frames to array
[animationFramesArray addObject:[cache spriteFrameByName:#"mole_normal.png"]];
[animationFramesArray2 addObject:[cache spriteFrameByName:#"mole_hit.png"]];
normalAnim = [[CCAnimation alloc] initWithSpriteFrames:animationFramesArray delay:1.0f];
hitAnim = [[CCAnimation alloc] initWithSpriteFrames:animationFramesArray2 delay:1.0f];
//MEVPCHANGE - create animation
[animationFramesArray release];
[animationFramesArray2 release];
//
[self runAction:[CCRepeatForever actionWithAction: [CCAnimate actionWithAnimation:normalAnim]]];
}
return self;
}
Now in cocos2d v1.0 this code works fine. The Mole's get created and they pop up and down when they get whacked. But in v2.0, I only get the front facing moles but the NSLog in the Mole init method doesnt even get called (as evidenced by the lack of NSLog in the console).

Restarting game/scene from another layer

I’m having a real headache trying to diagnose this problem for quiet awhile now.
Details:
I have the following nodes:
GameLayer; the main game layer, also a semi-singleton.
HUDLayer; a simple HUD layer (for score and pause button), added to the scene along with GameLayer of course.
PauseLayer; a CCLayerColor subclass which holds a simple menu (resume, restart, and main menu).
The PauseLayer is added to the GameLayer as a child whenever the pause button is pressed.
Problem:
Restarting the game/scene works fine by: [self restartGame] from within GameLayer itself.
But invoking the same method from PauseLayer by using: [[GameLayer sharedGameLayer] restartGame] does not completely replace the GameLayer scene with a new instance; old scene is still there with no childs, same old score, etc, albeit GameLayer’s dealloc is being called (Only if no transition is used).
Code:
GameLayer
static GameLayer *sharedGameLayer;
#implementation GameLayer
- (id)init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super's" return value
if(self = [super initWithColor:ccc4(255, 255, 255, 255) width:[CCDirector sharedDirector].winSize.width height:[CCDirector sharedDirector].winSize.height])
{
NSLog(#"%s", __PRETTY_FUNCTION__);
sharedGameLayer = self;
.
.
}
+ (GameLayer *)sharedGameLayer {
#synchronized(self) {
if (sharedGameLayer == nil) {
sharedGameLayer = [[self alloc] init];
}
}
return sharedGameLayer;
}
- (void)pauseGame
{
NSLog(#"%s", __PRETTY_FUNCTION__);
if (![[CCDirector sharedDirector] isPaused])
{
// Disable the top menu.
self.hud.topMenu.enabled = NO;
// Pause game.
[[CCDirector sharedDirector] pause];
// Pause the background music.
[[SimpleAudioEngine sharedEngine] pauseBackgroundMusic];
// Disable touch detection.
[[CCDirector sharedDirector].touchDispatcher removeDelegate:self];
// Add the Pause Layer.
PauseLayer *pauseLayer = [[PauseLayer alloc] init];
pauseLayer.tag = 2;
pauseLayer.zOrder = 10;
[self addChild:pauseLayer z:10 tag:2];
}
}
- (void)restartGame
{
NSLog(#"%s", __PRETTY_FUNCTION__);
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[CCDirector sharedDirector].touchDispatcher removeAllDelegates];
[self stopAllActions];
[self unscheduleAllSelectors];
[self unscheduleUpdate];
[self removeAllChildrenWithCleanup:YES];
[[CCDirector sharedDirector] replaceScene:[GameLayer scene]];
//[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1.0 scene:[GameLayer scene]]];
}
- (void)dealloc
{
NSLog(#"%s", __PRETTY_FUNCTION__);
sharedGameLayer = nil;
}
#end
PauseLayer
- (id)init
{
if (self = [super initWithColor:ccc4(0, 0, 0, 128) width:[CCDirector sharedDirector].winSize.width height:[CCDirector sharedDirector].winSize.height])
{
// Create a menu.
// Resume button.
CCLabelTTF *resumeLabel = [CCLabelTTF labelWithString:#"Resume" fontName:#"Marker Felt" fontSize:32];
resumeLabel.color = ccc3(240, 240, 240);
CCMenuItemLabel *resumeButton = [CCMenuItemLabel itemWithLabel:resumeLabel block:^(id sender) {
[[GameLayer sharedGameLayer] resumeGame];
}];
// Restart Game button.
CCLabelTTF *restartLabel = [CCLabelTTF labelWithString:#"Restart" fontName:#"Marker Felt" fontSize:32];
restartLabel.color = ccc3(240, 240, 240);
CCMenuItemLabel *restartButton = [CCMenuItemLabel itemWithLabel:restartLabel block:^(id sender) {
[[GameLayer sharedGameLayer] restartGame];
}];
// Main Menu button.
CCLabelTTF *mainMenuLabel = [CCLabelTTF labelWithString:#"Main Menu" fontName:#"Marker Felt" fontSize:32];
mainMenuLabel.color = ccc3(240, 240, 240);
CCMenuItemLabel *mainMenuButton = [CCMenuItemLabel itemWithLabel:mainMenuLabel block:^(id sender) {
[[GameLayer sharedGameLayer] gotoMainMenu];
}];
CCMenu *menu = [CCMenu menuWithItems:resumeButton, restartButton, mainMenuButton, nil];
[menu alignItemsVerticallyWithPadding:10.0];
menu.position = ccp([CCDirector sharedDirector].winSize.width / 2, [CCDirector sharedDirector].winSize.height / 2);
[self addChild:menu];
}
return self;
}
EDIT:
If I add the Pause layer (as a child to GameLayer, and always visible) in the GameLayer's init method, everything works perfectly.. which is a bit weird.
Any input is highly appreciated.
Thanks in advance!
from the line
static GameLayer *sharedGameLayer;
You needed to write this line before #implementation class line to make it isn't class member variable. and at sharedGameLayer method you should change it to
+ (GameLayer *)sharedGameLayer {
#synchronized(self) {
if (sharedGameLayer == nil) {
sharedGameLayer = [[self alloc] init];
}
}
return sharedGameLayer;
}
And, when you define game layer class you don't call init method but you should call sharedGameLayer to make game layer class be singleton.
I would not suggest using singleton pattern on CCLayers, however did you override / edit the CCScene wrapper so it doesn't call init.
For instance
+(id)scene
{
CCScene* scene = [CCScene node];
[scene addChild:[GameLayer sharedGameLayer]];
return scene;
}
Then when you call
[[CCDirector sharedDirector] replaceScene:[GameLayer scene]];
Remember to restart your game right after
[[GameLayer sharedInstance] restart];
Or you could do that in the scene wrapper method.
Hope I got your point.
Atleast this will save you from reallocating space for the game layer all the time hehe..
The culprit of the problem was calling the CCDirector's ReplaceScene: method after pausing the game using the CCDirector's Pause method. What I did was implementing my own "Pause" functionality mainly using: [self pauseSchedulerAndActions]; and also in my case: [[self.spidersBatchNode children] makeObjectsPerformSelector:#selector(pauseSchedulerAndActions)]; for all the children inside of the spriteBatchNode. Another problem arised for which I'll make another question.Thanks for all the replies.

How to replace layers?

I started to learn Objective-C and use cocos2D about 1 month ago.
I want to replace three different layers by tapping buttons.
At first, I tried to use "CCLayerMultiplex." Then, use "if sentence." But then the layers just overlap or crash when the buttons are tapped. I want the previous layer to disappear when the new layer appears, but the old layer remains with my code now.
I think using "CCLayerMultiplex" is my best option, but I can't make it work as I want it to.
Below is my code. I'm afraid that there're some poor sentences...
#interface GSLayout : CCLayer {
// button items
CCMenuItemImage *file1;
CCMenuItemImage *file1Pushed;
...
// Layer (replace)
CCLayer *layer1;
CCLayer *layer2;
CCLayer *layer3;
// replace layers
CCLayerMultiplex* mpLayer;
}
#end
#implementation GSLayout
-(id) init{
if( (self=[super init])) {
CCLOG(#"%#: %#", NSStringFromSelector(_cmd), self);
self.isTouchEnabled = YES;
// buttons
file1 = [CCMenuItemImage itemFromNormalImage:#"Icon-Small-50.png"
selectedImage: #"Icon-Small.png"
target:nil
selector:nil];
file1Pushed = [CCMenuItemImage itemFromNormalImage:#"Icon-Small.png"
selectedImage:#"Icon-Small-50.png"
target:nil
selector:nil];
CCMenuItemToggle *toggleFile1 = [CCMenuItemToggle itemWithTarget:self
selector:#selector(selectOne:)
items:file1,file1Pushed, nil];
toggleFile1.anchorPoint = CGPointMake(0.5f, 0.5f);
file2 = [[CCMenuItemImage itemFromNormalImage:#"Icon-Small-50.png"
selectedImage: #"Icon-Small.png"
target:nil
selector:nil]retain];
file2Pushed = [[CCMenuItemImage itemFromNormalImage:#"Icon-Small.png"
selectedImage:#"Icon-Small-50.png"
target:nil
selector:nil]retain];
CCMenuItemToggle *toggleFile2 = [CCMenuItemToggle itemWithTarget:self
selector:#selector(selectTwo:)
items:file2,file2Pushed, nil];
toggleFile2.anchorPoint = CGPointMake(0.5f, 0.5f);
...
CCMenu *toggleMenu = [CCMenu menuWithItems:toggleFile1,toggleFile2,toggleFile3, nil];
[toggleMenu alignItemsHorizontally];
toggleMenu.anchorPoint = CGPointMake(0, 1.0f);
CGSize screenSize = [[CCDirector sharedDirector] winSize];
toggleMenu.position = CGPointMake(screenSize.width/2, screenSize.height);
[self addChild:toggleMenu];
// create layers
layer1 = [GameFile1 node];
layer2 = [GameFile2 node];
layer3 = [GameFile3 node];
mpLayer = [CCLayerMultiplex layerWithLayers:layer1,layer2,layer3, nil];
}
return self;
}
- (void) selectOne: (CCMenuItem*) menuItem
{
NSLog(#"The first menu was called");
if([layer1 isRunning])
{
nil;
NSLog(#"The layer1 is running");
} else if([layer2 isRunning]) {
[mpLayer switchTo:0];
NSLog(#"The layer2 was replaced");
}else if([layer3 isRunning]) {
[mpLayer switchTo:0];
NSLog(#"The layer3 was replaced");
} else{
[self addChild:layer1];
NSLog(#"The layer1 was called");
}
}
- (void) selectTwo: (CCMenuItem*) menuItem
{
NSLog(#"The second menu was called");
if([layer2 isRunning])
{
nil;
NSLog(#"The layer2 is running");
} else if([layer1 isRunning]) {
[mpLayer switchTo:1];
NSLog(#"The layer1 was replaced");
} else if([layer3 isRunning]) {
[mpLayer switchTo:1];
NSLog(#"The layer3 was replaced");
}else{
[self addChild:layer2];
NSLog(#"The layer2 was called");
}
}
- (void) selectThree: (CCMenuItem*) menuItem
{
NSLog(#"The third menu was called");
...
}
Please give me some advice!
Thank you in advance!
I'll add some codes.
#interface GameFile1 : CCLayer {
CCSprite* sprite;
}
#implementation GameFile1
-(id) init{
if( (self=[super init])) {
CGSize screenSize = [[CCDirector sharedDirector] winSize];
CCMenuItemImage *soundItem1 = [CCMenuItemImage itemFromNormalImage:#"button1.png"
selectedImage: #"Icon.png"
target:self
selector:#selector(doSomethingOne:)];
CCMenuItemImage *soundItem2 = [CCMenuItemImage itemFromNormalImage:#"button2.png"
selectedImage: #"Icon.png"
target:self
selector:#selector(doSomethingTwo:)];
...
CCMenu * myMenu = [CCMenu menuWithItems:soundItem1, soundItem2,soundItem3,soundItem4, soundItem5,soundItem6,soundItem7, soundItem8,soundItem9,soundItem10,soundItem11,soundItem12, nil];
[myMenu alignItemsInRows:[NSNumber numberWithInt:4],[NSNumber numberWithInt:4],[NSNumber numberWithInt:4] ,nil];
myMenu.position = CGPointMake(370, 120);
[self addChild:myMenu];
sprite = [CCSprite spriteWithFile:#"o0400026611355530621.jpg"];
sprite.scale = 0.5f;
sprite.position = CGPointMake(screenSize.width/2, screenSize.height/2);
sprite.anchorPoint = CGPointMake(1.0f, 0);
[self addChild:sprite];
- (void) doSomethingOne: (CCMenuItem *) menuItem
{
NSLog(#"The first menu was called");
[[SimpleAudioEngine sharedEngine] playEffect:#"one.wav"];
[sprite setTexture:[[CCTextureCache sharedTextureCache] addImage: #"one.jpg"]];
}
- (void) doSomethingTwo: (CCMenuItem *) menuItem
{
NSLog(#"The second menu was called");
[[SimpleAudioEngine sharedEngine] playEffect:#"two.wav"];
[sprite setTexture:[[CCTextureCache sharedTextureCache] addImage: #"one.jpg"]];
}
...
#end
Since you have already loaded the textures for all three layers, you might as well have all three sitting in separate CCLayers where two are hidden at any given state using a method similar to:
- (void) setLayer:(uint)show {
layerOne.visible = (show == 0);
layerTwo.visible = (show == 1);
layerThree.visible = (show == 2);
}

Resources