My Cocos2d CCMenu won't responding to touch - ios

Hi there when my game reaches it's Game Over Scene i have a button to return to the Main menu and for some reason this has stopped working
Here is the code that leads to my Game Over Scene:
[[CCDirector sharedDirector] pause];
[[CCDirector sharedDirector] replaceScene:[ResultsScreen node]];
In my Init function for Game Over
....
mainMenu = [CCMenuItemImage itemFromNormalImage:#"MainMenu.png" selectedImage:#"MainMenuClick.png" target:self selector:#selector(Menu:)];
[mainMenu setAnchorPoint:ccp(0.0f, 0.0f)];
menu = [[CCMenu menuWithItems:mainMenu, nil] retain];
menu.isTouchEnabled = YES;
[menu setPosition:ccp(75, 80)];
[menu setAnchorPoint:ccp(0, 0)];
[self addChild:menu z:Z_INTERACTION];
....
My Selector Function for the button
- (void) Menu:(id)sender
{
NSLog(#"Exit to MainMenu");
[[CCDirector sharedDirector] replaceScene:[MainMenu node]];
}
Now I've compared this with my other code, all my other buttons are working, the only difference is that is that i am specifying a 'z' value.
Any help would be very much appreciated
Update:
Ran a quick check with Leaks and Allocations and nothing seems to be an issue

I found my Issue in my - (void) onEnter {}
I wasn't calling [super onEnter];

Related

SpriteKit problems with SKScene

I have performance problems using iOS Sprite kit.
I did the main scene of the game and every thing run nice and smoothly, then I inserted a splash windows in the beginning and when I change the scene to the main scene the game seems laggy with frame drop, but fps, cpu and memory parameters are Ok.
I also have a game over screen and the behaviour is the same, when the game return to the main scene looks very laggy.
I have tried with [self removeFromParents] and removing children, and nothing happens.
Code:
#implementation Splash
- (id) initWithSize:(CGSize)size
{
if (self = [super initWithSize:size]) {
SKSpriteNode *sprite= [SKSpriteNode spriteNodeWithImageNamed:#"main"];
sprite.position = CGPointMake(160,284);
[self addChild:sprite];
}
return self;
}
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// Transition back to the Game
SKScene *myScene = [[MyScene alloc] initWithSize:self.size];
SKTransition *reveal = [SKTransition fadeWithDuration:0.5];
[self.view presentScene:myScene transition:reveal];
[self removeAllChildren];
[self removeAllActions];
[self removeFromParent];
}
#end

Push a ViewController from a Cocos2d scene

I am loading a cocos2d game inside an Storyboard. I implemented a CocosViewController that loads the cocos2d scene (IntroLayer) and IntroLayer that starts the game. I would like to go back to CocosViewController or open a new viewcontroller when the timer (countdown) is zero in the game.
I tried calling [[CCDirector sharedDirector] popScene]; when the countdown arrives to zero and with CocosViewController *cocos = [[CocosViewController alloc] init]; [cocos.navigationController dismissViewControllerAnimated:YES completion:nil];
in onExit method but the app crashes when the countdown arrives to zero, any suggestion?
My CocosViewController set up cocos2d
-(void)setupCocos2d {
CCDirector *director = [CCDirector sharedDirector];
//[[[self navigationController] navigationBar] setHidden:YES];
if([director isViewLoaded] == NO)
{
// Create the OpenGL view that Cocos2D will render to.
CCGLView *glView = [CCGLView viewWithFrame:self.view.bounds
pixelFormat:kEAGLColorFormatRGB565
depthFormat:0
preserveBackbuffer:NO
sharegroup:nil
multiSampling:NO
numberOfSamples:0];
// Assign the view to the director.
director.view = glView;
// Initialize other director settings.
[director setAnimationInterval:1.0f/60.0f];
[director enableRetinaDisplay:YES];
}
// Set the view controller as the director's delegate, so we can respond to certain events.
director.delegate = self;
// Add the director as a child view controller of this view controller.
[self addChildViewController:director];
// Add the director's OpenGL view as a subview so we can see it.
[self.view addSubview:director.view];
[self.view sendSubviewToBack:director.view];
// Finish up our view controller containment responsibilities.
[director didMoveToParentViewController:self];
// Run whatever scene we'd like to run here.
NSArray *parameters = [[NSArray alloc] initWithObjects:#"3", #"sound", #"countdown", nil];
if(director.runningScene)
[director replaceScene:[IntroLayer scene];
else
[director pushScene:[IntroLayer scene];
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"cocos2d controller viewdidload");
[self setupCocos2d];
}
-(void)viewDidUnload {
NSLog(#"did unload");
[[CCDirector sharedDirector] setDelegate:nil];
[[CCDirector sharedDirector] end];
}
IntroLayer creates the scene for the game. This is my onExit method:
-(void) onExit{
NSLog(#"Introscene exit");
[super onExit];
}
And this is the game. I want to load a viewcontroller when the game finished.
-(void)update:(ccTime)dt{
if (myTime > 0) {
myTime -= (float)dt;
[timeLabel setString:[NSString stringWithFormat:#"%.2f", myTime]];
} else {
myTime = 0;
[timeLabel setString:[NSString stringWithFormat:#"0.00"]];
[[CCDirector sharedDirector] popScene];
}
if (clicks < currentClicks) {
clicks = currentClicks;
//[clicksLabel setString:[NSString stringWithFormat:#"%i", clicks]];
}
}
-(void) onExit
{
[super onExit];
[[CCDirector sharedDirector] stopAnimation];
CocosViewController *cocos = [[CocosViewController alloc] init];
[cocos.navigationController dismissViewControllerAnimated:YES completion:nil];
// [cocos.navigationController popViewControllerAnimated:YES];
//AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
//[app.navController popViewControllerAnimated:YES];
//dismissModalViewControllerAnimated:YES
NSLog(#"game exit");
}
For pop IntroLayer To ViewConrtroller As below code
[[[CCDirector sharedDirector] navigationController] popViewControllerAnimated:YES];

CCButton not working completely when pressed in Cocos2D v3 iOS

I have a gameplay scene, over which I add a CCNode as a child. My Game Over node has a replay CCButton in it.
The button is supposed to restart the game play scene. The problem is, when I press the "Restart" button, it goes through the lines but it doesn't perfrom replaceScene. Also it doesn't highlight when pressed. Here's my relevant code:
The code where I add the Game Over Node in my GamePlay Class (.m):
CCNode GameOver = [[GameOverNode alloc] init];
[self unscheduleAllSelectors];
[self stopAllActions];
[[OALSimpleAudio sharedInstance] stopBg];
[[CCDirector sharedDirector] stopAnimation];
[[CCDirector sharedDirector] pause];
[self addChild:GameOver z:5];
and here's the code for GameOver Class (.h):
#interface GameOverNode:CCNode {
CCButton *_aButton;
}
#property (nonatomic, retain) CCButton *aButton;
- (id)init;
- (void)ButtonPressed:(id)sender;
and Game Over (.m):
-(id)init {
if ( self = [super init] ){
CCSpriteFrame *replayFrame = [CCSpriteFrame frameWithImageNamed:#"Replay.png"];
_aButton = [CCButton buttonWithTitle:#"" spriteFrame:replayFrame];
_aButton.position = ccp(200,200);
[_aButton setTarget:self selector:#selector(ButtonPressed:)];
[self addChild:_aButton z:2];
}
return self;
}
- (void)ButtonPressed:(id)sender
{
NSLog(#"Button pressed");
CCTransition* t = [CCTransition transitionFadeWithDuration:0.4f];
t.outgoingSceneAnimated = YES;
t.incomingSceneAnimated = YES;
[[CCDirector sharedDirector] replaceScene:[GamePlayScene scene] withTransition:t];
}
The thing is, it prints out "Button pressed", also goes through the rest of the code of the method, but nothing happens.
I'll appreciate if you can let me know what I am doing wrong.
Thanks!
It does not work because you have paused the CCDirector. Remove the following line:
[[CCDirector sharedDirector] pause];
Alternatively if you really need that, resume the director before you attempt to replace the scene.
[[CCDirector sharedDirector] resume];
[[CCDirector sharedDirector] replaceScene:[GamePlayScene scene] withTransition:t];

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.

Orientation problem while using GKLeaderboardViewController

Unfortunately, I don't understand UIViewControllers very well, nor do I understand exactly how they mesh with cocos2d scenes. However, I am able to load a standard Game Center leaderboard view on top of my cocos2d (landscape-only) game successfully on the iPhone. But, my game is a universal app and when I try it on iPad, the Game Center view loads in portrait orientation, is about half the size it should be (fills up only one quarter of the screen), and is not centered. When I rotate the device, the Game Center view orients itself to landscape but gets really stretched out and looks like it wasn't designed for iPad in landscape view.
Does anyone have any advice?
- (void) showLeaderboard
{
if(![MyAppDelegate isGameCenterAPIAvailable])
return;
if ([GKLocalPlayer localPlayer].isAuthenticated == YES)
{
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
tempVC = [[RootViewController alloc] init];
GKLeaderboardViewController *leaderboard = [[[GKLeaderboardViewController alloc] init] autorelease];
if (leaderboard != NULL)
{
leaderboard.leaderboardDelegate = self;
[[[CCDirector sharedDirector] openGLView] addSubview:tempVC.view];
// Pause game
[[CCDirector sharedDirector] pause];
[tempVC presentModalViewController:leaderboard animated: NO];
leaderboard.view.transform = CGAffineTransformMakeRotation(CC_DEGREES_TO_RADIANS(0.0f));
[leaderboard.view setCenter:CGPointMake(screenSize.height/2, screenSize.width/2)];
leaderboard.modalPresentationStyle = UIModalPresentationCurrentContext;
}
}
}
- (void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController
{
[tempVC dismissModalViewControllerAnimated: YES];
[tempVC.view.superview removeFromSuperview];
[tempVC release];
tempVC = nil;
// Resume game
[[CCDirector sharedDirector] resume];
}
Please take a look at Implementing iAds in Cocos2d Application.
[self.view addSubview:self.bannerView];
In this tutorial, addSubview UIView object to RootViewController.view, that is in the cocos2d application template, instead of EAGLView.

Resources