In cocos2dx v4.0, the screen becomes half size when you change the device from portrait to landscape

Hello.

I was using cocos2dx v3.12 in my iOS app, but I upgraded to cocos2dx v4 due to performance and the removal of UIWebView.

However, when I upgraded to the v4 system, I had a problem.
Specifically, if you change the orientation of the device’s screen from portrait to landscape, the cocos2dx screen is halved.

If you investigate, it seems that the CCEAGLView on the iOS side is not halved, but some component on the cocos2dx side is halved.

Codes for screen rotation are as follows

// create CCEAGLView

CCEAGLView* PlatformFunctions::getSharedGlView(CGRect bounding) {
    static dispatch_once_t onceToken;
    static CCEAGLView * o;
    dispatch_once(&onceToken, ^{
        auto app = cocos2d::Application::getInstance();
        app->initGLContextAttrs();
        cocos2d::GLViewImpl::convertAttrs();

        o = [CCEAGLView viewWithFrame: bounding
                          pixelFormat: kEAGLColorFormatRGBA8
                          depthFormat: GL_DEPTH24_STENCIL8_OES
                   preserveBackbuffer: NO
                           sharegroup: nil
                        multiSampling: NO
                      numberOfSamples:0 ];

        o.opaque = NO;
        o.multipleTouchEnabled = YES;
        cocos2d::Director::getInstance()->setOpenGLView(cocos2d::GLViewImpl::createWithEAGLView((__bridge void *)o));
        app->run();
    });
    return o;
}


// AppDelegate.cpp

bool AppDelegate::applicationDidFinishLaunching() {
    // initialize director
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    if (!glview) {
        glview = GLViewImpl::create("My Game");
        director->setOpenGLView(glview);
    }

    auto visibleSize = director->getWinSize();
    auto designResolutionSize = director->getOpenGLView()->getDesignResolutionSize();
    // Always display vertically at first.
    glview->setDesignResolutionSize(DESIGN_RESOLUTION_SIZE_LONG, DESIGN_RESOLUTION_SIZE_LONG, ResolutionPolicy::FIXED_HEIGHT);

    // Receive events from iOS when rotating the screen
    Director::getInstance()->getEventDispatcher()->addCustomEventListener(kOnScreenOrientationChanged, [=](cocos2d::EventCustom *event) {
        ScreenOrientation orientation = *(ScreenOrientation*)event->getUserData();
        ResolutionPolicy policy = orientation == Portrait ? ResolutionPolicy::FIXED_HEIGHT : ResolutionPolicy::FIXED_WIDTH;
        director->getOpenGLView()->setDesignResolutionSize(DESIGN_RESOLUTION_SIZE_LONG, DESIGN_RESOLUTION_SIZE_LONG, policy);
    });

#ifdef DEBUG
    // turn on display FPS
    director->setDisplayStats(true);
#endif

    // fps setting
    PlatformFunctions::adjustFPS();

    // create a scene. it's an autorelease object
    auto scene = BlankScene::createScene();

    PlatformFunctions::onApplicationDidFinishLaunching();

    // run
    director->runWithScene(scene);

    return true;
}


The development environment is as follows

  • iOS version: iOS 13.6
  • Device: iPhone XS / iPhone X / Simulator
  • cocos2dx version: v4.0

Capture

Here are the vertical and horizontal screen captures for my app on v3 and v4 systems.
The following captures have been simplified to make the glitch easier to understand.

Size winSize = Director::getInstance()->getWinSize();
ScreenOrientation orientation = winSize.width < winSize.height ? Portrait : Landscape;
auto _bg = LayerColor::create(Color4B::RED, winSize.width, winSize.height);
// this is Scene
this->addChild(_bg);

cocos2dx v3.12 capture

portrate

landscape

cocos2dx v4.0 capture

portrate

landscape

You should call setFrameSize before call setDesignResolutionSize on event ScreenOrientationChanged. It worked for me

@thaihoangduylinh
thank you reply!

I fixed this problem.
The reason for this is that every rotation generates a GLViewImpl and incorrect setDesignResolutionSize API width, height.

Hi nk5, I have the same problems when migrating my apps from cocos v3 to v4 and rotating the device.

Where did you find the incorrect setup of the size ?
Can you share the code of the fix, or let me know where to find it ?

Thanks !

Sorry for the late reply.

in OnScreenOrientationChanged, this code exec so work for me.

        ScreenOrientation orientation = *(ScreenOrientation*)event->getUserData();
         // check orientation
        ResolutionPolicy policy = orientation == Portrait ? ResolutionPolicy::FIXED_HEIGHT : ResolutionPolicy::EXACT_FIT;

        auto resolutionSize = director->getOpenGLView()->getDesignResolutionSize();
        float width = MAX(resolutionSize.width, resolutionSize.height);
        float height = MIN(resolutionSize.width, resolutionSize.height);
        Size fsize = director->getOpenGLView()->getFrameSize();
        Size winSize = director->getWinSize();

        if (orientation == Landscape) {
            Size visibleSize = director->getVisibleSize();
            Point origin = director->getVisibleOrigin();

            Size s = Size(fsize.height, fsize.width);
            director->getOpenGLView()->setFrameSize(s.width, s.height);
            director->getOpenGLView()->setDesignResolutionSize(width, height, policy);
        } else {
            director->getOpenGLView()->setDesignResolutionSize(width, height, policy);
        }

but, Node touch handler not work when landscape.
Upon further investigation, we found out that the actual Node location we can see and the coordinate location where the touch responds are different…
portrait mode is nothing problem. only happen landscape.
Specifically, the touch responds around the lower left corner of the visible node.
I would like someone to tell me how to solve this problem.

thank you.

After investigating, I found that changing the bounds and frame of the CCEAGLView does not reflect the change, and the size of the CGRect that is set when the CCEAGLView is first created is still being used after the screen rotation.

I would appreciate it if someone could tell me how to solve this problem.

Sorry to here your having trouble hopefully I got your cure Ok Been messing around with resolution and rotation. My finds where you need to update the rotation for cocos2dx.

Fist in you AppDelegate.h prototype add this function it lets Cocos know we when from landscape to
portrait.
void AppDelegate::applicationScreenSizeChanged(int newWidth, int newHeight);

//Add this function AppDelegate.cpp
/**
@brief This function will be called when the application screen size is changed.
@param new width
@param new height
*/
void AppDelegate::applicationScreenSizeChanged(int newWidth, int newHeight) {
if (newWidth > 0 && newHeight > 0) {
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
if (glview) {
Size frameSize = glview->getFrameSize();
if (!frameSize.equals(Size(newWidth, newHeight))) {
// Frame size changed
glview->setFrameSize(newWidth, newHeight);
ResolutionPolicy resolutionPolicy = glview->getResolutionPolicy();
if (resolutionPolicy == ResolutionPolicy::UNKNOWN)
resolutionPolicy = ResolutionPolicy::NO_BORDER;
// Set the design resolution
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, resolutionPolicy);
// if the frame’s height is larger than the height of medium size.
if (newHeight > mediumResolutionSize.height)
{
director->setContentScaleFactor(MIN(largeResolutionSize.height/designResolutionSize.height, largeResolutionSize.width/designResolutionSize.width));
}
// if the frame’s height is larger than the height of small size.
else if (newHeight > smallResolutionSize.height)
{
director->setContentScaleFactor(MIN(mediumResolutionSize.height/designResolutionSize.height, mediumResolutionSize.width/designResolutionSize.width));
}
// if the frame’s height is smaller than the height of medium size.
else
{
director->setContentScaleFactor(MIN(smallResolutionSize.height/designResolutionSize.height, smallResolutionSize.width/designResolutionSize.width));
}
// Send change orientation event (scenes should change elements position, size etc)
director->getEventDispatcher()->dispatchCustomEvent(“ChangeOrientation”);
}
}
}
}

/Bonus tip
I’m Working with textures in 32, 64 ,128 , 512 that sort of stuff so forget the 1920x 1080
set what you want I use 2000x 2000 although you view a rectangle
so I’m set to this resolution pick your Owen…

static cocos2d::Size designResolutionSize = cocos2d::Size(2000,2000);
static cocos2d::Size smallResolutionSize = cocos2d::Size(480, 320);
static cocos2d::Size mediumResolutionSize = cocos2d::Size(1024, 768);
static cocos2d::Size largeResolutionSize = cocos2d::Size(2048, 2048);

hope this helps.

Thank you reply!! :sob:

I added void AppDelegate::applicationScreenSizeChanged(int newWidth, int newHeight) my AppDelegate.
But, not called applicationScreenSizeChanged on iOS(iOS 14.0 simulator).

applicationScreenSizeChanged api code is this.

my RootViewController add

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return .all
}

and ios project Device orientation setting checked Portrait, Landscape Left and Landscape Right.

why not call applicationScreenSizeChanged??

It turns out that applicationScreenSizeChanged is not called by cocos2dx when the device screen is rotated, but needs to be called by itself.
So, it was called when I executed applicationScreenSizeChanged myself!

However, the problem is still not solved and the GLView’ size is still half size…

I was able to fix the problem!
Using setFrameSize in applicationScreenSizeChanged to resize the GLView did not update it.
Therefore, I decided to regenerate the CCEAGLView. (Set the frame size after screen rotation when regenerating)
If we regenerated CCEAGLView without thinking, the GLView drawing would overlap, so we implemented deleting the GLView in the iOS or Android layer and drawing it again.
The sample code is as follows.

CCEAGLView* PlatformFunctions::getSharedGlView(CGRect bounding, EAGLSharegroup *shareGroup) {
static dispatch_once_t onceToken;
static CCEAGLView * o;

if (o != nil) {

    // recreate CCEAGLView
    o = nil;
    o = [CCEAGLView viewWithFrame: bounding
                      pixelFormat: kEAGLColorFormatRGBA8
                      depthFormat: GL_DEPTH24_STENCIL8_OES
               preserveBackbuffer: NO
                       sharegroup: shareGroup
                    multiSampling: NO
                  numberOfSamples:0 ];

    o.opaque = NO;
    o.multipleTouchEnabled = YES;
    
    auto glViewImpl = cocos2d::GLViewImpl::createWithEAGLView((__bridge void *)o);
    cocos2d::Director::getInstance()->setOpenGLView(glViewImpl);
    
    return o;
}

dispatch_once(&onceToken, ^{
    auto app = cocos2d::Application::getInstance();
    app->initGLContextAttrs();
    cocos2d::GLViewImpl::convertAttrs();

    o = [CCEAGLView viewWithFrame: bounding
                      pixelFormat: kEAGLColorFormatRGBA8
                      depthFormat: GL_DEPTH24_STENCIL8_OES
               preserveBackbuffer: NO
                       sharegroup: shareGroup
                    multiSampling: NO
                  numberOfSamples:0 ];

    o.opaque = NO;
    o.multipleTouchEnabled = YES;

    

    auto glViewImpl = cocos2d::GLViewImpl::createWithEAGLView((__bridge void *)o);


    cocos2d::Director::getInstance()->setOpenGLView(glViewImpl);
    app->run();
});

return o;
}


// remove GLView and reset ( iOS code sample)
self.glView?.removeFromSuperview()
self.glView = nil

self.glView = PlatformFunctionsBridge.getSharedGlView(self.view.bounds, nil)
self.glView?.bounds = CGRect(x: 0, y: 0, width: width, height: height) // set device width, height

self.glViewContainer?.addSubview(self.glView!)

I hope this helps someone else.

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.