javascriptcocos2d-html5

Cocos2d-html5 - Restarting/quitting engine possible?


With Cocos2d-html5, is there any way to “quit” the engine and re-initialize its state so you can later restart the engine. We are using a Cocos2d game in a single page web app. If the user navigates to another page, we want to programmatically remove the canvas div and attempt to exit the Cocos2d engine. Unfortunately, it seems there’s no good way to do this and attempting to load a new game causes errors.

How can you cleanly unload a scene and quit the engine?

We are using V3.1 and tried several approaches, none of them seem to work. For example:

  1. Trying to reset many variables that are held in the cc object (detailed below). This approach forces you to reset variables that look private as they start with _ and are not in the documentation.
  2. picking, choosing and rewriting some of CCBoot.js but this appeared complicated and not sustainable for engine updates as so much of it is depended upon throughout the library.

Other approaches I thought of but all sound like a hack:
3. Null the whole cc object and somehow run the script again but that might mean stripping out a script tag or module and adding and running it again.
4. Wrap the cc object in another object so it is easier to reset. CCBoot.js looks like it might attach some things to the window object.

I have got furthest with the first approach but am stuck with context issues. When leaving the canvas, before I remove it from the DOM I call these:

// Remove anything that might possibly keep a reference to the old context
cc.textureCache.removeAllTextures();
cc._drawingUtil = null;
cc.stencilBits = null;

// Purge the cc.director, schedules, event listeners, running scene, animations, cached data.
cc.director.purgeDirector();

// Remove references to the context
cc._renderContext = null;
cc.webglContext = null;
window.gl = null;
cc._mainRenderContextBackup = null;

// Remove reference to DOM elements
cc._canvas = null;
cc.container = null;
cc._gameDiv = null;

// Reset CCBoot variables that might stop us from re-initialising
cc._rendererInitialized = false;
cc._setupCalled = false;
cc._renderType = -1;

Then when we restart on the second or subsequent time call

// Reset all system and flag variables
cc._initSys(cc.game.config, cc.game.CONFIG_KEY);

cc.game.run();

And here are the kind of errors I get. It looks like it's not properly resetting the context:

WebGL: INVALID_OPERATION: bindTexture: object not from this context
WebGL: INVALID_OPERATION: texImage2D: no texture
WebGL: INVALID_OPERATION: uniformMatrix4fv: location is not from current program
WebGL: INVALID_OPERATION: vertexAttribPointer: no bound ARRAY_BUFFER

Solution

  • I've managed to get it stopping/resuming enough for a specific use case now, here is a demo: http://plnkr.co/edit/BQmmHi?p=preview

    There is now a public way to pause a game in v3.13, so I can call:

    cc.game.pause();
    

    followed by removing the cc.container from the DOM:

    cc.container.parentNode.removeChild(cc.container);
    

    Then I can place it back in the DOM again anywhere I would like:

    targetContainerEl.appendChild(cc.container);
    

    Then resume the game by calling:

    cc.game.resume();
    

    Note: The next line was was needed after replacing in the DOM in a complex app in cocos2d v3.5, but not sure if it's needed in v3.13 any more:

    cc.EGLView._instance._frame = cc.container.parentNode;
    

    The demo from the link above is being removed and placed in 2 different DOM elements and pausing/resuming.