Cocos2d black screen after app archive - ios

I have cocos2d setup as a sub-project in my iOS app, running the latest release (3.5) and targeting iOS versions 9.0+. The problem I'm having is that the cocos2d screen is black when I download and install the app from TestFairy. I have debugged it both on the simulator and on real device and the cocos2d scene loads properly.
It's a simple finger painting app and it's all based on UIKit. Cocos2d is added to a ViewController in the standard way. The relevant code is:
CCDirector *director = [CCDirector sharedDirector];
// If the director's OpenGL view hasn't been set up yet, then we should create it now. If you would like to prevent this "lazy loading", you should initialize the director and set its view elsewhere in your code.
if ([director isViewLoaded] == NO) {
director.view = [self createDirectorGLView];
[self didInitializeDirector];
}
else {
director.view.frame = [self getCanvasFrame];
[director.view setNeedsLayout];
[director.view layoutIfNeeded];
}
director.delegate = self;
// Add the director as a child view controller.
[self addChildViewController:director];
// Add the director's OpenGL view, and send it to the back of the view hierarchy so we can place UIKit elements on top of it.
[self.targetView addSubview:director.view];
[self.targetView sendSubviewToBack:director.view];
// Ensure we fulfill all of our view controller containment requirements.
[director didMoveToParentViewController:self];
The createDirectorGLView is as follows:
- (CCGLView *)createDirectorGLView {
_glView = [CCGLView viewWithFrame:[self getCanvasFrame]
pixelFormat:kEAGLColorFormatRGB565
depthFormat:0
preserveBackbuffer:NO
sharegroup:nil
multiSampling:NO
numberOfSamples:0];
return _glView;
}
I also have a scene which contains the CCNode that handles the drawing. It is created like this:
#implementation IntroScene
- (id)init:(CGRect)frame {
self = [super init];
if (self) {
_canvas = [[LineDrawer alloc] init];
_canvas.contentSize = CGSizeMake(frame.size.width, frame.size.height);
_canvas.position = CGPointZero;
_canvas.anchorPoint = CGPointZero;
[self addChild:_canvas];
}
return self;
}
#end
I can't get access to the console logs for some reason while the app is running from TestFairy so I can't say what's going on there. When I debug from Xcode however, everything looks normal and the cocos2d canvas is loading/working just fine. I have a feeling it might be something to do with the way the project is archiving but I'm not sure. Any ideas?
Edit
So I managed to reproduce it in Debug mode on a device and I saw a few errors which I think are related to TestFairy's screen recording using OpenGL and cocos2d.
2016-06-06 12:49:56.362 GraffiTab[5654:2941813] *** Assertion failure in -[CCRenderStateGL initWithBlendMode:shader:shaderUniforms:copyUniforms:], /Users/georgichristov/Documents/Workspace/Examples/GraffiTab/GraffiTab-iOS/GraffiTab/ExternalLibs/Cocos2d/cocos2d/CCRendererBasicTypes.m:356
2016-06-06 12:49:56.362 GraffiTab[5654:2941813] [visit] error CCRenderState: Blending mode is nil
2016-06-06 12:49:56.705 GraffiTab[5654:2941813] TestFairy: Initializing SDK version 1.7.6 (20160531-772d18b7)
2016-06-06 12:49:58.057 GraffiTab[5654:2941813] TestFairy: Session started successfully
2016-06-06 12:49:58.929 GraffiTab[5654:2941813] Please remove uses of SCRCException!

Related

cocos2d-js game iOS Crash when enter the game at the second time

We are using cocos2d-js to develop an iOS App which can launch different games. So I add an button in the native app viewcontroller and start the game by clicking the button, just like this:
-(void)didClickGame2Btn:(id)sender
{
//加载游戏
cocos2d::Application *app = cocos2d::Application::getInstance();
// Initialize the GLView attributes
app->initGLContextAttrs();
cocos2d::GLViewImpl::convertAttrs();
// Use RootViewController to manage CCEAGLView
RootViewController *rootViewController = [[RootViewController alloc] init];
rootViewController.wantsFullScreenLayout = YES;
[self.navigationController presentViewController:rootViewController animated:YES completion:^{
// IMPORTANT: Setting the GLView should be done after creating the RootViewController
cocos2d::GLView *glview = cocos2d::GLViewImpl::createWithEAGLView((__bridge void *)rootViewController.view);
cocos2d::Director::getInstance()->setOpenGLView(glview);
NSString *documentDir = [SEGetDirectories dirDoc];
NSString *wPath = [NSString stringWithFormat:#"%#/GameData/Game2",documentDir];
NSLog(#"document------:%#",documentDir);
std::vector<std::string> searchPathList;
searchPathList.push_back([wPath UTF8String]);
cocos2d::FileUtils::getInstance()->setSearchPaths(searchPathList);
//run the cocos2d-x game scene
app->run();
}];
[[UIApplication sharedApplication] setStatusBarHidden:true];
}
the rootViewController contains the game view. And then we add an button in the game, which is used to exit the game. The click event code of the exit game button likes:
//exit the game and close the view controller
gameEndCallBack:function(sender){
cc.log("director end............");
cc.director.end();
var ojb = jsb.reflection.callStaticMethod("ViewControllerUtils", "dismissCurrentVC");
}
We use the reflection to dismiss the rootViewController:
+(void)dismissCurrentVC
{
UIViewController *currentVC = [ViewControllerUtils getCurrentVC]; //这里获取最顶层的viewcontroller
[currentVC dismissViewControllerAnimated:YES completion:^{
NSLog(#"xxx");
}];
}
Everything is ok when the first time to enter the game, but after dismissing the rootViewController, we try to enter the game again, it crash.
The crash line is in the ScriptingCore::runScript metod and executing the code:
evaluatedOK = JS_ExecuteScript(cx, global, *script, &rval);
And the crash info is "exc_bad_access".
It is much the same problem as this topic, but the approaches in it did not solve the problem.
http://discuss.cocos2d-x.org/t/how-to-destroy-a-cocos-game-on-ios-completely/23805
This problem has been confusing me serveral days, I have no solution for this. Can anyone give me some help?
You can make the app to support multiple games with in the app.
All you have done is required but in addition to that please follow the below instructions.
First of all, cocos provide a singleton instance of cocos2d::Application that can not be restarted again especially in iOS. So the approach of ending the Director cc.director.end(); won't help you.
You should start the application only once by using the function call cocos2d::Application::getInstance()->run(); and next time if you want to start the game layer, you should not call this method again.
Instead, just pause cocos2d::Director::getInstance()->pause(); and resume cocos2d::Director::getInstance()->resume(); the director when you want to stop the game.
In this approach, if you dismiss/dealloc the view-controller instance then you should create the glview cocos2d::GLView instance again without calling the run method.
One more problem is, take care of the delay in loading the new scene. GLView will display the previous game scene for a while. Do a work around that will show blank screen while the new scene is ready.
Hope this will help you.

Can't show the scene second time in Cocos3D

I have a viewController with cocos scene which I push in my navigation controller. In this view controller I have this methods:
-(void) viewDidLoad
{
[super viewDidLoad];
[_cc3FrameView addSubview: [self createGLView]];
CC3Backgrounder.sharedBackgrounder.shouldRunTasksOnRequestingThread = YES;
}
- (void) viewWillAppear:(BOOL)animated
{
if (!sceneInitialized) {
sceneInitialized = YES;
[CCDirector.sharedDirector runWithScene: [[self makePanoramaScene] asCCScene]];
} else {
[CCDirector.sharedDirector resume];
}
[CCDirector.sharedDirector startAnimation];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[self runningPanoramaScene] sceneWillShow];
});
}
-(AxPanoramaScene *)runningPanoramaScene
{
CCScene *scene = [CCDirector.sharedDirector runningScene];
AxPanoramaLayer *panoramaLayer = [scene.children lastObject];
AxPanoramaScene *panoramaScene = (AxPanoramaScene *)panoramaLayer.cc3Scene;
return panoramaScene;
}
-(void)viewWillDisappear:(BOOL)animated
{
[CCDirector.sharedDirector pause];
}
While I push this controller - everything is working, but when I pop this controller and push it again - I got the bright pink screen and continuos messages in log:
2014-12-12 19:30:06.447 UniversalMapExample[2262:258353] cocos2d: animation started with frame interval: 60.00
2014-12-12 19:30:06.452 UniversalMapExample[2262:258353] cocos2d: surface size: 768x973
OpenGL error GL_INVALID_OPERATION detected at -[CCES2Renderer resizeFromLayer:] 161
2014-12-12 19:30:06.452 UniversalMapExample[2262:258353] Failed to make complete framebuffer object 0x8219
2014-12-12 19:30:06.453 UniversalMapExample[2262:258353] cocos2d: surface size: 768x973
OpenGL error GL_INVALID_OPERATION detected at -[CCES2Renderer resizeFromLayer:] 161
2014-12-12 19:30:06.453 UniversalMapExample[2262:258353] Failed to make complete framebuffer object 0x8219
OpenGL error GL_INVALID_OPERATION detected at -[CCRenderer(NoARCPrivate) setRenderState:] 232
OpenGL error GL_INVALID_OPERATION detected at -[CCRenderer(NoARCPrivate) setRenderState:] 232
OpenGL error GL_INVALID_OPERATION detected at -[CCRenderer(NoARCPrivate) setRenderState:] 232
OpenGL error GL_INVALID_OPERATION detected at -[CCRenderer(NoARCPrivate) setRenderState:] 232
[***GL ERROR***] GL_INVALID_VALUE: Numeric argument is out of range from glUseProgram(15).
[***GL ERROR***] GL_INVALID_OPERATION: Operation not allowed in current state from glUniform3fv(7, 4, (0.329, 0.944, 0.000)) setting u_cc3LightSpotDirectionModel.
[***GL ERROR***] GL_INVALID_OPERATION: Operation not allowed in current state from glUniformMatrix4fv(12, 1, GL_FALSE,
[0.021050, -0.007339, -0.000000, 0.210503
0.000000, -0.000000, 0.017596, -0.977556
0.005937, 0.017031, 0.000000, -0.660065
0.005926, 0.016997, 0.000000, 1.339256]) setting u_cc3MatrixModelViewProj.
How to correctly push the controller with cocos scene several times? I changed the example from cocos sources to this code. What am I doing wrong here? Please, note - that my controller is not CCDirector - it just contains a view with Cocos scene - the realization is like CC3DemoMultiScene. Thanks!
Remember that the CCDirector is a UIViewController, but it is also a singleton, which give it some unique nuances.
For example, you seem to be invoking the createGLView method every time you want to replace your controller. If it follows the CC3DemoMultiScene design, this will try to recreate another CCGLView before the old one has been released from the CCDirector singleton.
It's generally best to treat the CCDirector and the CCGLView that you create for it as a self-contained reusable unit. As you pop the containing controller, leave everything as is, and simply add and remove the CCGLView from the view hierarchy each time.
...Bill
This is a copy/paste from my blog where I covered a similar issue. The only difference is that I wanted full UIKit integration. I did have the problem where the 2nd time through. Perhaps it will help you.
http://www.notthepainter.com/full-cocos2d-uikit-integration/
I was working on a cocos2d based tapping game and I wasn’t able to run my game twice. It was clear that I wasn’t shutting the 1st game down correctly or building the 2nd game correctly, or both!
There are a lot of tutorials on the web out there teaching you how to add UIKit buttons to your Cocos2D app, or how to launch Cocos2D from your UIKit based app. But I needed to do both. I wanted a UIViewController under my game and UIKit widgets on top of my game. I spent a lot of time reading and this is what I came up with.
First, building the Xcode project was a nightmare. I eventually used the cocos2d/box2d template and then ripped out the files I didn’t needed, and added all my original files back in. The AppDelegate.m file looks just like a non-cocos2d app should look. This goes against the grain of many of the tutorials which advise you to build your cocos2d environment in the AppDelegate. I struggled with that, didn’t have luck for most of a Friday and then on Monday I put in a Cocos2DSingleton and it pretty much ran first time.
Here is my GameViewController’s viewDidLoad method:
- (void)viewDidLoad
{
[super viewDidLoad];
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:NO];
TTCocos2DSingleton *shared = [TTCocos2DSingleton sharedCocos2D];
CCGLView *glView = [shared currentGLView];
[self.view insertSubview:glView atIndex:1];
}
There are a view things to note. GameViewController has game UIButtons, score UILabels, and other game type of UI widgets. This lets me do a lot of the game controls in Interface Builder, not laying them out by hand. Notice I hide the status bar since the game is full-screen.
I get my cocos2d instance via the singleton, get its glView and insert this into the GameViewController’s view at index 1. This puts it below all the game controls. I’ll show you the sharedCocos2D method later, lets look at viewWillAppear.
- (void) viewWillAppear:(BOOL)animated
{
if(![[CCDirector sharedDirector] runningScene]){
CCScene *scene = [MyGameLayer scene];
myGame = [MyGameLayer node];
myGame.delegate = self;
[scene addChild: myGame];
[[CCDirector sharedDirector] runWithScene:scene];
} else {
// we have a scene already, replace the original to get a new game
[[CCDirector sharedDirector] startAnimation];
CCScene *scene = [MyGameLayer scene];
myGame = [MyGameLayer node];
myGame.delegate = self;
[scene addChild: myGame];
[[CCDirector sharedDirector] replaceScene:scene];
}
}
Notice how we treat the first run differently from the second run. For the second, and subsequent runs, we replace the scene with a new one. This avoids all “restarting” problems. Also notice that I set a delegate. I use a delegate protocol to communicate between my game layer and my UIViewController.
My singleton pattern comes from the Duck Rowing blog which I must admit is a pretty awesome name for a blog. I’m not going to show all the singleton code here, this blog is about cocos2d, but here is how I build my cocos2d environment.
+ (TTCocos2DSingleton *) sharedCocos2D;
{
static dispatch_once_t onceQueue;
dispatch_once(&onceQueue, ^{
if (sharedInstance) {
return;
}
sharedInstance = [[TTCocos2DSingleton alloc]init];
// Create an CCGLView with a RGB565 color buffer, and a depth buffer of 0-bits
sharedInstance->glView = [CCGLView viewWithFrame:[[UIScreen mainScreen] bounds]
pixelFormat:kEAGLColorFormatRGB565 //kEAGLColorFormatRGBA8
depthFormat:0 //GL_DEPTH_COMPONENT24_OES
preserveBackbuffer:NO
sharegroup:nil
multiSampling:NO
numberOfSamples:0];
[sharedInstance->glView setMultipleTouchEnabled:YES];
[sharedInstance setupDirector];
});
return sharedInstance;
}
The singleton sets up the CCGLView, enables multi-touch and then sets up the director. (I put that in another method since I thought, erroneously, that I’d need to call it elsewhere. Turns out I didn’t need to.)
- (void)setupDirector
{
CCDirectorIOS *director = (CCDirectorIOS*) [CCDirector sharedDirector];
[director setView:glView];
[director enableRetinaDisplay:YES];
director.wantsFullScreenLayout = YES;
[director setDisplayStats:NO];
[director setAnimationInterval:1.0/60];
}
And in setupDirector we set the usual suspects needed for a cocos2d app. Now the game can be played multiple times, I have a full UIViewController/UINavController underneath it, and I have UIKit widgets on top of my game. Nirvana.

GLKViewController and GLKView - Rendering nothing the second time created

I have a MainMenuViewController and a GameViewController which is a GLKViewConrtroller.
The first time I go from the main menu to the GameViewController everything is rendered fine. If I go back to the main menu, the GameViewController and its view get dealloced (I logged it).
When now going back to the game, I see a blank screen, nothing gets rendered OpenGL-wise. The overlay test menu with UIKit is still there.
Thisis how I tear down OpenGL in the GameViewController's dealloc method, the last five lines were added as tries to make it work, so it doesn't work with or without them.
- (void)tearDownGL {
[EAGLContext setCurrentContext:self.context];
glDeleteBuffers(1, &_vertexBuffer);
glDeleteVertexArraysOES(1, &_vertexArray);
self.effect = nil;
_program = nil;
glBindVertexArrayOES(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
[EAGLContext setCurrentContext: nil];
}
I think that the problem is that you are not using a sharegroup - a place where OpenGL can share textures and shaders between contexts?
Here is code that will create a sharegroup that all your GLKViewController 's subclass. If you have multiple subclasses you will have to do something to make the shareGroup global, if that's appropriate.
- (void)viewDidLoad
{
[super viewDidLoad];
// Create an OpenGL ES context and assign it to the view loaded from storyboard
GLKView *view = (GLKView *)self.view;
// GLES 3 is not supported on iPhone 4s, 5. It may 'just work' to try 3, but stick with 2, as we don't use the new features, me thinks.
//view.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
//if (view.context == nil)
static EAGLSharegroup* shareGroup = nil;
view.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup:shareGroup];
if (shareGroup == nil)
shareGroup = view.context.sharegroup;
...

'NSInternalInconsistencyException: Do not initialize the TextureCache before the Director'

To find a solution I have gone thru this similar link:
TextureCache Error from Cocos2d when integrated into UIKit App
but seems like it is dealing with this error in a different context..
Question:
I have a UIKit project integrated with Cocos2d. When build, succeeds and runs but, at times crashes after receiving a memory warning with this error:
Assertion failure in -[CCTextureCache init], /Users/MyName/Documents/CSProject/CSProject/libs/cocos2d/CCTextureCache.m:90
Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘Do not initialize the TextureCache before the Director’
The cocos2d scene is run from the view controller when a button is touched and the code is given below:
In ViewController.m
-(IBAction)overToCocos:(id)sender{
CCDirector *director = [CCDirector sharedDirector];
CCGLView *glView = [CCGLView viewWithFrame:CGRectMake(-100, -50, 480, 480)
pixelFormat:kEAGLColorFormatRGBA8
depthFormat:0];
glView.opaque = NO;
self.imagePicker.cameraOverlayView.userInteractionEnabled = YES;
[self.imagePicker.cameraOverlayView insertSubview:glView atIndex:0];
[self.imagePicker.cameraOverlayView bringSubviewToFront:glView];
[director setView:glView];
[director runWithScene:[HelloWorldLayer scene]];
}
Since the crash occurs after receiving a memory warning, I tried this
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
if ( [ CCDirector sharedDirector ].view != nil ){
[[CCTextureCache sharedTextureCache] removeUnusedTextures];
}
}
Also added this to AppDelegate's applicationDidReceiveMemoryWarning.
But the crash still exists.. Please point me to the right direction to handle this error..
Thanks in advance!

Cocos2d v2.0 - Set Up Scenes, Layers, Sprites, etc

With Cocos2d v2.0.0, a lot of changes were made and a lot of people are experiencing some scaling problems and other conflicts ...
This is even more true if they read and test out Ray Wenderlich's great book : Learning Cocos2d : The viking guy is to big, the background is not centered, the suffix system for images is not working, ...
So, how to proceed ?
Basically, everything is already told in the sample project when creating a new cocos2d v2 project.
But, some of us need to get things pointed out.
Image Suffix System for iPhone (Non-retina & Retina) and iPad (Non-retina & Retina)
Check out lines 68-71 from AppDelegate.m
Here is what you need to remember :
You just need to call
CCSprite *mySprite = [CCSprite spriteWithFile:#"mySprite.png"];
No need for some if(iPad) then else if(iPhone) blabla
Make sure you called your images like as lines 68-71 from AppDelegate.m (Default : mySprite.png (iPhone) | mySprite-hd.png (iPhone Retina) | mySprite-ipad.png (iPad) | mySprite-ipadhd.png (iPad Retina)
Calling a Scene
Check out line 76 from AppDelegate.m
Just call the scene function from your class (using pushScene)
[director_ pushScene: [MyScene scene]];
Adding layers to your scene class
Supposing your scene class is called with the +(CCSene*)scene function (which is a good practice for cocos2d v2)
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
BackgroundLayer *backgroundLayer = [BackgroundLayer node];
[scene addChild:backgroundLayer z:0];
GameplayLayer *gameplayLayer = [GameplayLayer node];
[scene addChild:gameplayLayer z:5];
return scene;
}
Replacing the init function from your classes (CCScene, CCLayer, ...)
This is where scaling problems from v2 of cocos2d come from (but I do not know why).
Instead of calling -(id)init, call
-(void) onEnter{ //Do some sprite displaying with [self addChild:mySprite]; }
You can still call the -(id)init function for other things you need to load before displaying sprites.
Using SneakyInput (Joystick opensource library)
You can find how to use sneakyinput with cocos2d v2 here : http://cl.ly/1J2D2z0f3o0r3h041o3o
Multi Touch Enabling
Add this line to your layer (in the +(CCScene*) scene function or else where)
layer.isTouchEnabled = YES;
Then add this to the same .m
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSArray *touchArray=[touches allObjects];
if ([touchArray count] == 2)
{
NSLog(#"2");
}
else if([touchArray count]==1)
{
NSLog(#"1");
}
}
Finally, go to the AppDelegate.m and add this :
[[CCDirector sharedDirector].view setMultipleTouchEnabled:YES];
I would much appreciate if cocos2d v2 developers could help out and post stuff about how to use cocos2d v2 compared to v1.
cocos2d v2.0 migration guide:
http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:migrate_to_v2.0

Resources