I'm starting the game with a UIViewController in this way:
navController = [[MyNavigationController alloc] initWithRootViewController:myController];
and when you push the game button the game start the scene in this way:
[[CCDirector sharedDirector] runWithScene:gameScene];
ok, now when I want to quit I just replace the UIViewController (because I did the menu with UIKit and the game with cocos2d) with the starting view controller to do the animation I want, it works fine... but obviously the old running scene still remains in memory, it is not deallocated in any way, I need to remove the scene and make the app as it was at the first running.
The replaceScene didn't work, I just need to stop the running scene and make everything as it was when the app started running, from the [CCDirector sharedDirector] direcly, how can I do it? popScene won't work too.
you can remove the CCDirector from the application.
the director is a simple UIViewController so, you can call
[[CCDirector sharedDirector] removeFromParentViewController];
and after call the [[CCDirector sharedDirector] end]; to remove the singlenton instance
Related
I'm not exactly sure what's going on and hope that I can provide enough relevant code to find an answer. I've set up my gesture recognizer in my appDelegate.m:
CCScene *scene = [HomeLayer scene];
HomeLayer *layer = (HomeLayer *) [scene.children objectAtIndex:0];
UIPanGestureRecognizer *gestureRecognizer = [[[UIPanGestureRecognizer alloc] initWithTarget:layer action:#selector(handlePanFrom:)] autorelease];
[director_.view addGestureRecognizer:gestureRecognizer];
m._gestureRecognizer = gestureRecognizer;
I've inserted some debugging messages to try to pinpoint at what point the app crashes:
- (void)handlePanFrom:(UIPanGestureRecognizer *)recognizer {
NSLog(#"Handle Pan From");
as well as some printouts for ccTouchBegan/Moved/Ended.
Every time the app crashes, it's while things are "moving", (ended never gets called), and handlePanFrom never gets called either.
Background info: My app has buttons that I use to switch between scenes, for example:
- (void) doSomethingThree: (CCMenuItem *) menuItem
{
NSLog(#"The third menu was called");
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1.0 scene:[HomeLayer scene] ]];
}
If I start up my app and go directly to the HomeLayer scene, and try to drag, the app crashes instantly 100% of the time (ccMoved gets called 1-2 times before crash). Clicking does not cause the app to crash, only anything that would invoke handlePanFrom.
The strange thing is that if I drag around on any other scene, the app does not crash, and handlePanFrom successfully gets called. Then, when I go back to the HomeLayer scene and drag around, it won't crash for some time, and it seems directly related to how long I spend dragging around on a different scene.
Has anyone seen these symptoms before? I'm not sure if the information I provided is relevant or correct, I'm still trying to learn my way around iphone dev. I'll also be happy for any debugging tips (those assembly looking hex lines aren't particularly enlightening to me...)
I figured out the problem with the help of NSZombies, finding out that the program was crashing while trying to reference the deallocated method handlePanFrom.
The ultimate root of the problem was that HomeLayer was being instantiated twice, the first time in appDelegate.m, and the 2nd time when i was doing the replaceScene.
This resulted in the first layer eventually losing all of its references and being deallocated while the gestureRecognizer was still trying to reference [layer handlePanFrom], causing the crash.
The problem was fixed by moving the gestureRecognizer from the appDelegate.m to HomeLayer.m, and for anyone who needs gestures across multiple layers, here's a piece of code that will remove any existing references of the gestureRecognizer to the view, and then add a new one that targets a method in the layer:
+(CCScene *) scene
{
HomeLayer *layer = [HomeLayer node];
[scene addChild: layer];
for (UIGestureRecognizer *gr in [[CCDirector sharedDirector].view gestureRecognizers]) {
// note that sharedDirector is a singleton and therefore is the same CCDirector
// as the one used in appDelegate.m
[[CCDirector sharedDirector].view removeGestureRecognizer:gr];
}
UIPanGestureRecognizer *gestureRecognizer = [[[UIPanGestureRecognizer alloc] initWithTarget:layer action:#selector(handlePanFrom:)] autorelease];
[[CCDirector sharedDirector].view addGestureRecognizer:gestureRecognizer];
return scene;
}
Hopefully that may help someone in the future who is trying to work with multiple scenes/layers in a view =)
so i'm currently working on an app that draws something on the screen, like a graph and things like that. while testing it and it's functionality i came across this issue.
i have a button that when pressed goes to a settings scene. i initialize the scene like this
+(id) scenew
{
CCScene *scene = [CCScene node];
Settings *layer = [Settings node];
[scene addChild: layer];
return scene;
}
in that scene i have two more buttons, a done button and a what's new button.
done = [CCMenuItemImage itemFromNormalImage:#"done.png" selectedImage:#"done.png" target:self selector:#selector(done:)];
pressing the what's new button goes instantly but the done button has a 2-3 seconds delay.
the app has some console messages appearing and it seems that when it is pressed it recalculates the whole graph just like when starting the app.
all the buttons call the same CCDirector function which is replaceScene.
-(void) whatNew: (id)sender
{
[[CCDirector sharedDirector] replaceScene: [New scene]];
}
-(void) done: (id)sender
{
[[CCDirector sharedDirector] replaceScene: [Main scene]];
}
is there a way for me to optimize this a little...i mean...an efficient way to use the replaceScene, or maybe something else that doesn't force the recalculation of the graph? because whenever that button is pressed it practically jumps at the top of my graph class implementation which has 4500+ lines O.o
I assume the first button you mentioned above is inside the Main scene, going to the Setting scene.
To retain the Main scene in the memory while transferring the app flow to the Setting scene, all you have to do is to use pushScene: instead of replaceScene::
// in Main scene class
[[CCDirector sharedDirector] pushScene:[Setting scene]];
Then, from inside Setting scene, simply use popScene to return to the Main scene:
-(void) done: (id)sender
{
[[CCDirector sharedDirector] popScene];
}
Basically pushScene: simply push the new scene on top of the current scene while popScene pops it out, reverting the app flow back to the previous scene that still remains in the device memory.
I want to run a cocos2D scene on a UIView, called camera_view.
So I try adding the camera_view to the openGLView :
[[CCDirector sharedDirector].openGLView addSubview:cameraView];
And then push my scene, called scene :
[[CCDirector sharedDirector] pushScene: scene];
But after doing that, I can only see the UIView, and the cocos2D scene is no longer visible. However, before adding the camera_view as a subview of the openGLView, the scene was working absolutely fine.
How can I fix this issue ?
Thanks.
My solution is as follows :
I added my camera_view and the openGLView, each as a subview of the UIWindow :
[window addSubview: camera_view];
[window addSubView: [CCDirector sharedDirector].openGLView];
Then I pushed the cocos2D scene :
[[CCDirector sharedDirector] pushScene: scene];
And that solved the problem. Now I can view the cocos2D scene on my UIView.
this is my first post so don't go too rough on me.
I have a problem with cocos2d. Im making a game with a HUD layer and a game layer. When I call replace main menu scene with [ClassicGameLayer scene] my HUD and game layer get init-ed this way:
+ (CCScene*)scene
{
CCScene *scene = [CCScene node];
HudLayer *hud = [[[HudLayer alloc] initWithMode:1] autorelease];
ClassicGameLayer *layer = [[[ClassicGameLayer alloc] initWithHUD:hud] autorelease];
[scene addChild:hud z:hudZ];
[scene addChild:layer z:layerZ];
return scene;
}
and when the user fails the game HUD layer calls
[[CCDirector sharedDirector] replaceScene:[GameOverLayer sceneWithMode:integer andScore:points]]];
dealloc of the HUD layer gets called but dealloc of the ClassicGameLayer is never called. I googled almost everything I could think of but still no luck.
Does anybody know whats causing me this problem? And if so how can I fix it? Every other scene is being released properly i think :)
If your autorelease pool never gets to the place where it deallocates stuff, it will never release any memory. I had this issue once with a Mac app I was writing. It won't show up as a memory leak in Instruments, either.
I recommend not using autorelease if you are having this problem.
I've been running through a good Cocos2d tutorial to implement iAds and am close to getting it implemented (I get iAd messages from the console)...
I keep coming back to this Warning on:
CCGLView *eaglView = [[CCDirector sharedDirector] openGLView];
"Instance method '-openGLView' not found..."
I think it has something to do with the switch from calling GLView to CCGLView (cocos2d)...
By using type CCGLView, I guess you are using cocos2d-iphone 2.x, while 1.x doesn't have CCGLView but have EAGLView.
In 1.x usually we access the property openGLView to get the OpenGL view object:
EAGLView *eaglView = [[CCDirector sharedDirector] openGLView];
In 2.x, CCDirector class doesn't have such a property. Instead, CCDirector is now a subclass of UIViewController on iOS (and NSObject on Mac OS X). So, if you want to get the OpenGL view object on iOS, just do this:
CCGLView *ccglView = (CCGLView *)[[CCDirector sharedDirector] view];
since view is a property of UIViewController.