I am using cocos2d and view controllers in my game. I wants to call a view controller using cocos2d scene using following code
PlayAgainViewController* playAgain = [[PlayAgainViewController alloc] initWithNibName:#"PlayAgainViewController" bundle:nil];
[[[CCDirector sharedDirector] openGLView] addSubview:playAgain.view];
its adding view controller view on game scene but not calling another view controller by using view added on openGl view.
//if UR_COCOS2D_VERSION_2_0
AppController *app = (AppController*)[[UIApplication sharedApplication] delegate];
[app.navController presentModalViewController:playAgain animated:YES];
//Cocos2D 1.0, use viewController property in appDelegate.
AppDelegate* app = (AppDelegate*)[[UIApplication sharedApplication] delegate];
[app.viewController presentModalViewController:playAgain animated:YES];
Thanks a lot for your answer.as :
[[CCDirector sharedDirector] pause];
PlayAgainViewController* playAgain = [[PlayAgainViewController alloc] initWithNibName:#"PlayAgainViewController" bundle:nil];
AppDelegate* app = (AppDelegate*)[[UIApplication sharedApplication] delegate];
[app.navigationController pushViewController:playAgain animated:YES];
it helps me a lot and solved my problem.
But now i am facing a new problem which is when i am calling view controller from cocos2d layer using your answer its working excellent :), but when i want to call another view controller which is calling EAGLView usig following code:
if([[CCDirector sharedDirector] isPaused])
[[CCDirector sharedDirector] replaceScene:[Game scene]];
else
[[CCDirector sharedDirector] runWithScene:[Game scene]];
its showing white screen. I think the problem is texture. Can u please tell me how to release textures used in layer while calling view controller.
Related
1)I made a game using cocos2d-iphone v3.
2)I integrated a fullscreen advertisement.
3)I want to load a cocos2d scene, when user closes ad, but it doesn't work(I imported cocos2d framework).There is just a black screen after advertisement disappears with animation. "interstitialAdDidFINISH" appears in the output, so most likely, that last line is wrong.
-(void)interstitialAdActionDidFinish:(ADInterstitialAd *)interstitialAd {
interstitial = nil;
// [interstitialAd release];
// [ADInterstitialAd release];
requestingAd = NO;
NSLog(#"interstitialAdDidFINISH");
[[CCDirector sharedDirector] replaceScene:[CCBReader loadAsScene:#"MainScene"]];
}
I guess, that I can't load a cocos2d scene from UIViewController class so easy.....
How can I do this?
EDIT: So ? It's not nil
if ( [CCDirector sharedDirector].view != nil) {
NSLog(#"Hey there");
}
EDIT 2: I found out, that [CCDirector sharedDirector]]; is a ViewController too.
I tried something like this . The game crashes, after iAd finished.
[self addChildViewController:[CCDirector sharedDirector]];
[self presentModalViewController:[CCDirector sharedDirector] animated:NO];
[[CCDirector sharedDirector] replaceScene:[CCBReader loadAsScene:#"MainScene"]];
I'v found solution. May be helpfull for others.
First, that's, how I present iad view controller from the MainScene
*ViewControllerAdEx= [[ ViewControllerAd alloc] init]; // making an instance of iad class
[[CCDirector sharedDirector] presentModalViewController:ViewControllerAdEx animated:YES];
[ViewControllerAdEx showFullScreenAd]; // caling a method from class
In the iad class, when iad finishes work:
[self dismissViewControllerAnimated:YES completion:^{
[[CCDirector sharedDirector] replaceScene:[CCBReader loadAsScene:#"MainScene"]];
}];
Imagine a custom segue ...
-(void)perform
{
UIView *sv = ((UIViewController *)self.sourceViewController).view;
UIView *dv = ((UIViewController *)self.destinationViewController).view;
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
[window insertSubview:dv aboveSubview:sv];
[dv coverFromRight:0 then:^
{
[self.sourceViewController
presentViewController:self.destinationViewController
animated:NO completion:nil];
}];
}
Which in fact, only PARTIALLY (!) covers the "underneath, previous" scene,
and in fact DOES NOT call "presentViewController", so, the "underneath, previous" scene in fact keeps operating normally.
-(void)perform
{
UIView *sv = ((UIViewController *)self.sourceViewController).view;
UIView *dv = ((UIViewController *)self.destinationViewController).view;
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
[window insertSubview:dv aboveSubview:sv];
[dv coverButOnlyHalfWay:0 then:^
{
}];
}
Essentially, is this possible?
In fact, I've found from experiment the above works (!!). BUT when you come to the custom unwind segue, it does not work: everything crashes. (Perhaps as you'd expect.)
What's the situation? is there a way to make a custom segue, which, covers only say half the "original, underneath" scene and leaves that scene running?
(I appreciate you can just implement this using a container view, but it's not as clean as a whole segue scene.)
Why use a segue? You can just add your view as a subview and position it correct using CGRectMake, this would be much easier.
// Size Your View with X, Y coordinates
[viewController.view setFrame:CGRectMake(0, 0, 320, 192)];
[self.view addSubview:viewController.view];
[viewController didMoveToParentViewController:self];
[self addChildViewController:viewController];
How do I restart cocos2d scene and clean memory after the previous one?
[director replaceScene:s] is displaying pink screen. Can't get it to work.
The work-around I made is below, however after closing scene this way app runs very slow and slowly reacts to touch. MainViewController.m:
- (IBAction)startScene {
[CCTexture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA8888];
if ([director runningScene]) {
[director end];
works = NO;
}
if (!works) {
EAGLView *glview = [EAGLView viewWithFrame:CGRectMake(0,0, 768, 1024)];
[self.view addSubview:glview];
[director setOpenGLView:glview];
CCLayer *layer = [PlayLayer node];
CCScene *s = [CCScene node];
[s addChild: layer];
[director runWithScene:s];
}
}
Inside PlayLayer.m I go back from scene to view using:
CCDirector *d = [CCDirector sharedDirector];
EAGLView *v = [d openGLView];
[v removeFromSuperview];
Application is displaying images (1280x960x32, imageview inside scrollview) and when user presses the button he can start cocos2d scene. User can then leave from scene back to view (.xib) and continue browsing through images till he finds a new one to start scene with.
I believe this is not a good way to leave scene but everything else I tried is causing app to crash or I keep getting this pink screen 2nd time I start scene. How do I restart it ?
I finally could get rid of pink screen while replacing scene. This is how I am doing it. While adding scene, I check if it's running first time or subsequent times.
MyTestAppDelegate * appDelegate = (MyTestAppDelegate *)[[UIApplication sharedApplication] delegate];
EAGLView *glView;
//check if scene is running first time then create OpenGLView, add to director and run the scene
if ([[CCDirector sharedDirector] runningScene] == NULL) {
if( ! [CCDirector setDirectorType:kCCDirectorTypeDisplayLink] )
[CCDirector setDirectorType:kCCDirectorTypeDefault];
CCDirector *director = [CCDirector sharedDirector];
glView = [EAGLView viewWithFrame:[appDelegate.window bounds]
pixelFormat:kEAGLColorFormatRGB565 // kEAGLColorFormatRGBA8
depthFormat:0 // GL_DEPTH_COMPONENT16_OES
];
[director setOpenGLView:glView];
[director setDeviceOrientation:kCCDeviceOrientationPortrait];
[director setAnimationInterval:1.0/60];
[director setDisplayFPS:YES];
[appDelegate.window addSubview:glView];
[[CCDirector sharedDirector] runWithScene: [MyScene node]];
}
//if scene is to be reloaded, add back the openGLView which was removed when removing the scene
else {
[appDelegate.window addSubview:[[CCDirector sharedDirector] openGLView]];
[[CCDirector sharedDirector] replaceScene:[MyScene node]];
}
For removing currently running scene:
[[CCDirector sharedDirector] replaceScene:[MySceneTwoLayer scene]];
[[CCDirector sharedDirector].openGLView removeFromSuperview];
Adding MySceneTwoLayer is optional. It is an empty scene. I am using it to make sure previous scene was properly removed. And I checked, previous scene's dealloc is properly called.
I hope it helps.
I came across a simliar problem when using Storyboards and when returning to m original UI view which contained my CCGLView from another view.
//when leaving the scene containing the CCGLView.
[CCDirector director] popScene];
then I noticed in viewDIdLoad for that viewcontroller, it would go through this when reinstantiated bt the segue, where you can re add the scene again.
// in viewDidLoad
[CCDirector director] pushScene: theSceneIRemovedEtc];
Admititedly this mightnot work for all cases but certainly did for me..
Ok, found a solution that closes the scene from inside and works well.
While starting scene I add the notification observer in my viewcontroller:
(...)
[director runWithScene:s];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(mySceneEnd:) name:#"scene_ended" object:nil];
That is connected to:
- (void) mySceneEnd:(NSNotification *)notif {
if ([director runningScene])
[director end];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Then in the scene ending method I'm sending the notification to my viewcontroller:
EAGLView *v = [[CCDirector sharedDirector] openGLView];
[v removeFromSuperview];
[[NSNotificationCenter defaultCenter] postNotificationName:#"scene_ended"
object:nil userInfo:nil];
Works really nice, app runs fast after closing scene, but it's an old question/answer and there is surely a better way to do it now.
This is my first post at SO. I would like to thank all of the SO users, their contribution have helped me a lot in all of my projects. I am new to the iPhone Application development scene.
Aim of the project is to have a custom interactive User Interface (UI) on top of Movie Player objects (*.mov files on device). The underlying FullScreen MoviePlayers can be more than one and need to switch to different ones based on user Interaction.
I am using cocos2D to achieve the custom interactive UI and effects (for e.g. particle effects on swipe gesture). And I am using Multiple MPMoviePlayerViewController* to play the resident movie files (*.mov) on fullscreen mode (refered to MoviePlayer sample).
Requirement is to switch between movies by switching between default and alternate moviePlayer upon touch detection. Also, the switching should be as smooth as possible.
To achieve smooth switching I am using two moviePlayerViewControllers, each a subview of UIView object in AppController.
Problem a: I am not sure if this is the right way to achieve movie switching.
Problem b: In my current solution. The Default MoviePlayer is rotated in portrait mode, and sometimes the moviePlayer object is not visible. The behaviour is not consistent.
Problem c: The Alternate movie player (object of MPMoviePlayerViewController and added first as subview of UIWindow) rotates on device rotation and behaves properly the Default Movie Player (object of MPMoviePlayerViewController added after) doesn't. Can't think of logical explanation of it. Somewhere I read that MPMoviePlayerViewController creates it's own window and that might be an issue.
// From AppController.h
UIWindow *window; // Parent application window
UIView *viewCocos2D; // Cocos View
UIView *viewMovie; // Default MoviePlayer View
UIView *viewMovieAlternate; // Alternate MoviePlayer View
// From AppController.m
// From DidAppFinishLoading
{
...
// Init the window
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Init the views (Cocos2d, MOviePlayer and AlternateMOviePlayer)
viewCocos2D = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
viewMovie = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
viewMovieAlternate = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// cocos2d will inherit these values
[viewCocos2D setUserInteractionEnabled:YES];
[viewCocos2D setMultipleTouchEnabled:YES];
// create OpenGL view and attach it to a window
//[[[UIApplication sharedApplication] keyWindow] addSubview:window];
[[CCDirector sharedDirector] attachInView:viewCocos2D];
// Default texture format for PNG/BMP/TIFF/JPEG/GIF images
[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888];
// Create a
customMoviePlayerWithUI = [[CustomMoviePlayerWithUI alloc] initWithSuperView:window andMovieView:viewMovie andAlternateView:viewMovieAlternate andSelf:self];
CCScene *scene = [CCScene node];
CocosCustomLayer *cocosLayer = [customMoviePlayerWithUI cocosLayer];
[window addSubview:viewMovieAlternate];
[window addSubview:viewMovie];
// somehow this order lets cocos2D receive the touch events
[window addSubview:viewCocos2D];
[scene addChild: cocosLayer];
[window makeKeyAndVisible];
[[CCDirector sharedDirector] runWithScene: scene];
[UIAccelerometer sharedAccelerometer].delegate = self;
[customMoviePlayerWithUI start];
[self didRotate:nil];
...
}
So the View hierarchy is
Alternate Movie Player View is at bottom
Default Movie Player view is next
Cocos2D Layer View is on top -- Cocos2D view also receives all of the events.
// From CustomMoviePlayerWithUI.h
MPMoviePlayerViewController *moviePlayerView;
MPMoviePlayerViewController *moviePlayerViewAlternate;
// These delegates are used frequently to invoke some functions
AppController* delegateApplication;
UIView *delegateSuperWindow; // Window which contains everything -
UIView *delegateView; // View containing default MoviePlayer
UIView *delegateViewAlternate;// View containing alternate MoviePlayer
Following is the moviePlayerViewController init code -- basically it allocs and inits two moviePlayerViewController objects and adds them as subview to the Default and Alternate UIView objects from AppController
// From customMoviePlayer.m
// initAndPlayMovie is called from the init of CustomMoviePlayer
- (void)initAndPlayMovie:(UIView *)view andAlternateView:(UIView*) viewMovieAlternate
{
// Initialize a movie player object with the specified URL
moviePlayerView = [[MPMoviePlayerViewController alloc] init];
moviePlayerViewAlternate = [[MPMoviePlayerViewController alloc] init];
[moviePlayerView shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationLandscapeLeft];
[moviePlayerViewAlternate shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationLandscapeLeft];
//if (moviePlayer)
if (moviePlayerView && moviePlayerViewAlternate)
{
[[[moviePlayerView moviePlayer] backgroundView] setBackgroundColor:[UIColor blueColor]];
[[[moviePlayerViewAlternate moviePlayer] backgroundView] setBackgroundColor:[UIColor redColor]];
//[moviePlayerView setWantsFullScreenLayout:YES];
// private API call.. don't use it..
//[mp setOrientation:UIDeviceOrientationPortrait animated:NO];
[view addSubview:[moviePlayerView view]];
[viewMovieAlternate addSubview:[moviePlayerViewAlternate view]];
//[view bringSubviewToFront:[moviePlayerView view]];
//[[moviePlayerView moviePlayer] play];
}
}
Thanks for all of your help. Let me know if you need any more details on it.
I understand modal views cover the entire screen. But I really want a view that covers only half the screen just like the keyboard. So, please tell me why this doesn't work
MyController *controller = [[MyController alloc] initWithNibName:#"MyView" bundle:nil];
CGRect frame = CGRectMake(0,44,768,264);
[controller view].frame = frame;
contoller.delegate = self;
[[self view] addSubView:[controller view]];
[controller release];
I am trying to add a sub view to my current view and make it appear where the keyboard appears.
It throws a BAD ACCESS exception
In my code (above), I was using a custom UIViewController with it's own view [set to UIView on IB]. I couldn't get it to work by setting frame for the view controller's view.
So I added a custom UIView without a Nib file with all the controls (buttons, textfields) added on initWithFrame.
MyCustomView = [[MyCustomView] alloc] initWithFrame:frame delegate:self];
[self.view addSubView:MyCustomView];
Thanks for your comment, Jacob.