ZhouWeikuan / cocos2d

cocos2d for android, based on cocos2d-android-0.82, and now ported from cocos2d-iphone 0.99.4. The googlecode address is here: http://code.google.com/p/cocos2d-android-1/ . There are several demos to watch.
609 stars 291 forks source link

CCDirector.setDeviceOrientation() doesn't correct Sprite dimensions #21

Open dustinanon opened 13 years ago

dustinanon commented 13 years ago

If you first set the orientation to Landscape, then change to Portrait (or visa versa) and add sprites to a scene, then the sprite will be rotated and positioned correctly, but the dimensions will be wrong.

That is, what was once the width is now the height, and what was once the height is now the width. This makes wide objects look squished horizontally and make tall objects look squished vertically.

I'm trying to fix the problem now, but I don't know if it's been encountered before.

ZhouWeikuan commented 13 years ago

Screen Orientation is controlled in manifest file, originally we didn't check the CCDirector's setDeviceOrientation function.

I will merge the commit soon.

Thanks, Weikuan Zhou

2011/7/7 dustinanon < reply@reply.github.com>

If you first set the orientation to Landscape, then change to Portrait (or visa versa) and add sprites to a scene, then the sprite will be rotated and positioned correctly, but the dimensions will be wrong.

That is, what was once the width is now the height, and what was once the height is now the width. This makes wide objects look squished horizontally and make tall objects look squished vertically.

I'm trying to fix the problem now, but I don't know if it's been encountered before.

Reply to this email directly or view it on GitHub: https://github.com/ZhouWeikuan/cocos2d/issues/21

dustinanon commented 13 years ago

Ah, fantastic :D

Thanks for the fast response!

dustinanon commented 13 years ago

Any luck? I'm on a bit of a tight schedule, sadly, so if a fix can't be posted, then is there a known workaround?

Thanks again!

ZhouWeikuan commented 13 years ago

Oh, I thought you sent a commit yesterday, but not.. We didnt' have a fix for this yet.

Thanks, Weikuan Zhou

2011/7/8 dustinanon < reply@reply.github.com>

Any luck? I'm on a bit of a tight schedule, sadly, so if a fix can't be posted, then is there a known workaround?

Thanks again!

Reply to this email directly or view it on GitHub: https://github.com/ZhouWeikuan/cocos2d/issues/21#issuecomment-1529057

dustinanon commented 13 years ago

Ah, I see... is all of that controlled in CCDirector? I'm not quite sure what the problem is, because I can't find exactly where the coordinate translations and CCNode transformations take place when you change the orientation.

ZhouWeikuan commented 13 years ago

No, there is no transform about the coordinates. When I translated the code from obj-c, I removed them.. Originally, I assume the orientation is controlled only by manifest.

2011/7/8 dustinanon < reply@reply.github.com>

Ah, I see... is all of that controlled in CCDirector? I'm not quite sure what the problem is, because I can't find exactly where the coordinate translations and CCNode transformations take place when you change the orientation.

Reply to this email directly or view it on GitHub: https://github.com/ZhouWeikuan/cocos2d/issues/21#issuecomment-1530571

dustinanon commented 13 years ago

Alright man, I'm going crazy. If I try to apply OpenGL transforms then I get the following exception:

E/AndroidRuntime(11653): FATAL EXCEPTION: GLThread 29 E/AndroidRuntime(11653): java.util.ConcurrentModificationException E/AndroidRuntime(11653): at java.util.WeakHashMap$HashIterator.next(WeakHashMap.java:165) E/AndroidRuntime(11653): at org.cocos2d.opengl.GLResourceHelper$2.perform(GLResourceHelper.java:87) E/AndroidRuntime(11653): at org.cocos2d.opengl.GLResourceHelper.update(GLResourceHelper.java:122) E/AndroidRuntime(11653): at org.cocos2d.nodes.CCDirector.drawCCScene(CCDirector.java:702) E/AndroidRuntime(11653): at org.cocos2d.nodes.CCDirector.onDrawFrame(CCDirector.java:667) E/AndroidRuntime(11653): at org.cocos2d.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1245) E/AndroidRuntime(11653): at org.cocos2d.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1056)

I'm going a little bit crazy figuring out exactly the best way to do this stuff... are you at all familiar with the problem I'm having?

To replicate it, create and run a scene and add a few sprites. Then switch the orientation. You'll see that the dimensions displayed on the screen are something crazy (in my case, it was roughly 700x700) and that all the sprites will be distorted.

This is what I'm trying to correct. Do you have any advice on where to look?

Thanks for your help and patience!

ZhouWeikuan commented 13 years ago

What about create two activity and one for landscape, one for portrait?

2011/7/12 dustinanon < reply@reply.github.com>

Alright man, I'm going crazy. If I try to apply OpenGL transforms then I get the following exception:

E/AndroidRuntime(11653): FATAL EXCEPTION: GLThread 29 E/AndroidRuntime(11653): java.util.ConcurrentModificationException E/AndroidRuntime(11653): at java.util.WeakHashMap$HashIterator.next(WeakHashMap.java:165) E/AndroidRuntime(11653): at org.cocos2d.opengl.GLResourceHelper$2.perform(GLResourceHelper.java:87) E/AndroidRuntime(11653): at org.cocos2d.opengl.GLResourceHelper.update(GLResourceHelper.java:122) E/AndroidRuntime(11653): at org.cocos2d.nodes.CCDirector.drawCCScene(CCDirector.java:702) E/AndroidRuntime(11653): at org.cocos2d.nodes.CCDirector.onDrawFrame(CCDirector.java:667) E/AndroidRuntime(11653): at org.cocos2d.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1245) E/AndroidRuntime(11653): at org.cocos2d.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1056)

I'm going a little bit crazy figuring out exactly the best way to do this stuff... are you at all familiar with the problem I'm having?

To replicate it, create and run a scene and add a few sprites. Then switch the orientation. You'll see that the dimensions displayed on the screen are something crazy (in my case, it was roughly 700x700) and that all the sprites will be distorted.

This is what I'm trying to correct. Do you have any advice on where to look?

Thanks for your help and patience!

Reply to this email directly or view it on GitHub: https://github.com/ZhouWeikuan/cocos2d/issues/21#issuecomment-1551717

dustinanon commented 13 years ago

that's not quite an ideal solution because I can't use any page turn transitions... apparently something was stripped out of cocos2d-iphone during the port... my coworker can easily switch the page orientation, but I can't quite find what the difference in code is..

dustinanon commented 13 years ago

Okay, so if you try to set the screen size twice then you get the same error. I think that the problem lies in the fact that you need to do:

CCDirector.sharedDirector().setScreenSize(h, w) when switching, but opengl doesn't like you to just change like that... hmmm

dustinanon commented 13 years ago

okay, continuing forward, changing the screensize does appear to be necessary. I figured out that the issue is that whenever you change orientation in Android, the system destroys the Activity (going through the entire lifecycle) and recreates it.

This causes a race condition in the GLThread, particularly when iterating through the WeakHashMap reloadMap.

The best thing I have come up with so far is to add the following property to your activity node in AndroidManifest.xml :

android:configChanges="orientation"

which causes the Activity to not be destroyed when the orientation is switched. This allows me to switch orientation freely.

However, when I switch to Portrait orientation, cocos2d shows about 150 ~ 200 pixels of black space at the top of the screen and I can't figure out how to move the display region back up.

So... that's my progress so far -__-

pboklashov commented 13 years ago

Hello dustinanon,

I believe than an activity can be destroyed also in some other cases, not only during orientation change.

I found the following solution (almost a solution to be honest).

I followed http://developer.android.com/reference/android/opengl/GLSurfaceView.html and http://developer.android.com/guide/topics/resources/runtime-changes.html#RetainingAnObject and modified my activity as written in the code below.

It works fine (at least in AVD as I don't have android device yet) except you need to restart all actions. This probably can be solved by adding public method to CCActionManager to get/set private "targets" field and retain it also.

public class CocosTest extends Activity {
    private CCGLSurfaceView mainView;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
       // setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

        mainView = new CCGLSurfaceView(this);

        setContentView(mainView);

        CCDirector.sharedDirector().attachInView(mainView);
        //CCDirector.sharedDirector().setDeviceOrientation(CCDirector.kCCDeviceOrientationLandscapeLeft);
        CCDirector.sharedDirector().setDisplayFPS(true);
        CCDirector.sharedDirector().setAnimationInterval(1.0/60);

        Object prevScene = getLastNonConfigurationInstance();
        if((prevScene!=null)&&(prevScene instanceof CCScene))
            CCDirector.sharedDirector().runWithScene((CCScene)prevScene);
        else
            CCDirector.sharedDirector().runWithScene(SpriteTestLayer.getScene());
    }

    @Override
    public void onStart() {
        super.onStart();
    }

    @Override
    public void onPause() {
        super.onPause();

        CCDirector.sharedDirector().pause();
        mainView.onPause();
    }

    @Override
    public void onResume() {
        super.onResume();

        mainView.onResume();
        CCDirector.sharedDirector().resume();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        CCDirector.sharedDirector().end();
    }

    @Override
    public Object onRetainNonConfigurationInstance () {
        return CCDirector.sharedDirector().getRunningScene();
    }
/**  
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }
*/
}

Best Regards, Petr Boklashov