cocos2d / cocos2d-objc

Cocos2d for iOS and OS X, built using Objective-C
http://www.cocos2d-objc.org
Other
4.07k stars 1.16k forks source link

Crashes with v3.5 start-up code #1361

Closed ejmarchant closed 8 years ago

ejmarchant commented 8 years ago

I'm using CCProjectGenerator (87781f3).

The new start-up code in v3.5 recommends initialising a scene earlier than in previous versions (in application:didFinishLaunchingWithOptions rather than directorDidReshapeProjection: ). This can cause problems - for instance adding the following to the end of init in MainScene causes a crash:

let renderTexture = CCRenderTexture(width: 40, height: 40)
renderTexture.begin()
renderTexture.end()
s1ddok commented 8 years ago

Even the official 3.4.9 suggests adding scene creating code in applicationDidFinish. It is unlikely to be changed, because we're heading to possibility for creating multiple cocos2d instances in one application.

This is only appears in iOS version, Mac works alright. I will take a look on this, maybe even before cocos2d 3.5 release.

Generally speaking it might not be a good idea to perform drawing inside scene init, but we should at least try to fix it.

s1ddok commented 8 years ago

Problem persists for 4 years already. Proof: http://stackoverflow.com/questions/7889557/is-applicationdidfinishlaunchingwithoptions-really-a-good-place-to-initialize

The solution is up there: use scene initialization in applicationDidBecomeActive, but you should keep in mind that you will have to prevent double initialization somehow.

I don't think we could do anyting about that, it is how Apple made things.

ejmarchant commented 8 years ago

Even the official 3.4.9 suggests adding scene creating code in applicationDidFinish.

No it doesn't - in 3.4.9 scene creation is done in startScene which was called from directorDidReshapeProjection:.

Your commit 81b2107 changed that behaviour, where you decided to do scene initialisation in application:didFinishLaunchingWithOptions: instead.

s1ddok commented 8 years ago

Look at the 3.4.9 source code:

// This is needed for iOS4 and iOS5 in order to ensure
// that the 1st scene has the correct dimensions
// This is not needed on iOS6 and could be added to the application:didFinish...
-(void) directorDidReshapeProjection:(CCDirector*)director
{
    if(director.runningScene == nil) {
        // Add the first scene to the stack. The director will draw it immediately into the framebuffer. (Animation is started automatically when the view is displayed.)
        // and add the scene to the stack. The director will run it when it automatically when the view is displayed.
        [director runWithScene: [_appDelegate startScene]];
    }
}
ejmarchant commented 8 years ago

Also from the source code ...

/**
 Most Cocos2d apps should override the CCAppDelegate, it serves as the app's starting point and provides a CCNavigationController.

 At the very least the `startScene` method should be overridden to return the first scene the app should display.

 To further customize the behavior of Cocos2D, such as the screen mode of pixel format, override the `setupCocos2dWithOptions:` method.
 */
// -----------------------------------------------------------------------
/** @name Creating the Start Scene */
// -----------------------------------------------------------------------

/**
 - *  Override this method to return the very first scene that Cocos2D should present.
 - *
 - *  @return The first scene of your app. It will be presented automatically.
 - */
- (CCScene*) startScene;

I think it's pretty clear that this is the recommended way of initialising the first scene rather than following an untested suggestion made in an implementation file several years ago.

s1ddok commented 8 years ago

Well, this documentation exists because it just works this way now.

Perfoming drawing in the initialization of the scene is a pretty bad code practice, but if you really want to do that, you could move the initializition to didBecomeActive method The way start up code works now was implemented quite the same in v4. Even though I implemented it myself (it is not a backport, I found out that later), the ideology behind this is the same.

The problem you describe is not a bug, it is how Apple decided to create OpenGL ES framework. If you really need that type of init, there is a workaround I provided above. Your code was working because of cocos2d start-up design flaw, now it is fixed, and it is better for general code quality.

startScene method should and will be gone. Because the whole CCAppDelegate will be gone in the future releases. It makes cocos2d apps not obvious and generally complicated. For example you can't even handle 3d touch shortcut to launch level with the current implementation. Also you can't even override application* methods, because there are default implementation for them and no documentation as well. This is bad. Really bad.