cocos2d / cocos2d-x

Cocos2d-x is a suite of open-source, cross-platform, game-development tools utilized by millions of developers across the globe. Its core has evolved to serve as the foundation for Cocos Creator 1.x & 2.x.
https://www.cocos.com/en/cocos2d-x
18.15k stars 7.05k forks source link

getPhysicsWorld()->setAutoStep(false) physics initialization issue in 3.7 rc0 #12691

Open jimrange opened 9 years ago

jimrange commented 9 years ago
// Description of Bug
//-------------------
// Sometimes the physics sprites are not setup/initialized properly when
// getPhysicsWorld()->setAutoStep(false) is used.
// e.g. a manual physics step is used instead of the auto phyiscs step.

// When using manual step for the integrated physics e.g. getPhysicsWorld()->setAutoStep(false) and
// getPhysicsWorld()->step(dt) is manually called in an update loop, there seems to be physics
// and sprite initialization issues.
//
// If a method is scheduled from inside of a callback, and that method replaces the current scene,
// for some reason the initialization of Physics objects, sprites, etc do not work as expected (when
// using manual physics step).
//
// When the button callback directly calls the replace scene, the strange behavior does occur, but
// it occurs less often than when a method is scheduled inside of the callback and the schedduled
// method replaces the scene.
//
// I think that the HttpClient also schedules methods from the asyc completion to try to get back on
// the main thread. It was the use of HttpClient where I first noticed this issue.

//----------------------
// Steps to Recreate Bug
//----------------------
// To recreate the issue:
// Clone the github repo located at: https://github.com/jimrange/cocos2dxPhysicsBug/tree/manualStep12691
// View Video of the behavior: https://youtu.be/WGzviqqClRo
// In HelloWorld.cpp, enable USE_PHYSICS_MANUAL_STEP and
// enable SCHEDULE_SELECTOR_IN_MENU_CALLBACK below.
// Then run the app and press the button in the lower right corner to replace the scene.
#define USE_PHYSICS_MANUAL_STEP 1
#define SCHEDULE_SELECTOR_IN_MENU_CALLBACK 1

//----------------------------
// Work-around Fix (temporary)
//----------------------------
// A hack work-around to fix the initialization issue described above is to delay calling
// getPhysicsWorld()->setAutoStep(false) and delay the manual calling of getPhysicsWorld()->step(dt).
#define DELAY_CHANGING_TO_MANUAL_PHYSICS_STEP 1

//----------------------------
// Worth looking into this
//------------------------
// Forcing the replace scene to the main thread seems to fix the issue. However, the initial setup on
// launch still seems to have unexpected behavior when using a manual physics step.
// To enable FORCE_REPLACE_SCENE_TO_MAIN_THREAD, you must also rename this file to HelloWorldScene.mm.
#define FORCE_REPLACE_SCENE_TO_MAIN_THREAD 0

// Calling the setup from the init method or from the onEneter did not seem to make a difference
// regarding this bug.
#define CALL_SETUP_IN_ON_ENTER 0
jimrange commented 9 years ago

Hopefully this bug can be confirmed and added to 3.8. I think this is a critical bug since it results in strange and unexpected behavior, essentially making the physics wrapper unusable without the temporary workaround I mentioned above.

Dredok commented 9 years ago

I think it is important to fix this. A workaround I use is to use scheduleOnce to set autoUpdate = false and manually guarantee this scheduleOnce is the first one to be executed.

jimrange commented 9 years ago

@dredok, can you provide more information about how you manually guarantee that the scheduleOnce is the first one to be executed. I am having some inconsistent results with the workaround that I proposed and want to try your fix.

jimrange commented 9 years ago

I figured out another hack that helps to stabilize the physics world initialization. The delay in changing from autostep to manual step that I described as my workaround had an issue. To fix the issue, I do the following immediately after creating the scene that has physics enabled.

_scene->getPhysicsWorld()->setSpeed(0);

Then after a short delay I call getPhysicsWorld()->setAutoStep(true) and start stepping the physics simulation.

jimrange commented 9 years ago

@WenhaiLin, did you have any issues reproducing this issue? Just curious why it is marked as unconfirmed.

Dredok commented 9 years ago

@jimrange By manually I mean that I know the flow of my instances and so I schedule this on a node which will be updated before any other node (for instance, the layer where physics world resides, which I know has more priority than any of its children). That's dirty and that's what I mean by "manually guarantee".

kamal-ik commented 6 years ago

Hi , Any possible fix for this issue?