Problem with canvas fitWidth/fitHeight rendering delay

I have been using this runtime method to change the fit based on the aspect ratio of the screen on load.

    let canvas = this.node.getComponent(cc.Canvas);
    let aspectRatio = cc.view.getCanvasSize().height / 
    let designAspectRatio = cc.view.getDesignResolutionSize().height / 

    console.log("winSize", cc.winSize.toString())
    if (aspectRatio >= designAspectRatio) 
        canvas.fitWidth = true;
        canvas.fitHeight = true;

This works fine, but the problem is with the positioning of some of the elements, its off by a noticeable amount.
The current workaround I am using is to position the element after a delay like so:-

    this.scheduleOnce(()=> {
        // position the element
    }, 0.01);

FYI: I am calling the fitwidth/fitHeight method in the onLoad() function of the canvas component. Whereas the positioning of the element in the start() function of the same component.
Also I would like to know if we have any way to write methods on scene load itself.

Edit: Problem occurs when I use convertToNodeSpaceAR / convertToWorldSpaceAR values to position the element. It seems that the worldMatrix is not instantly updated after the fitWidth=true or fitHeight=true call.

I would also like to hear the DEVs answer to this. I have and many other have struggled with workarounds of all kind to handle everything regarding resolution, aspect ratio and positioning.

Hi, you will not need this kind of process once we fixed a minor bug of NO_BORDER mode (both leave fitWidth, fitHeight unchecked)

Hmm, you can place a component in the scene with your onLoad.

Yes, the worldMatrix should never updated by design policy or design resolution. What problem did you meet?

Hi @jare and thanks for your response!

Here I’ve attached one example project for CC 2.3.3 describing one problem with aspect ratio of different devices and positionings. (1.2 MB)

Here I use: cc.view.setDesignResolutionSize(960, 640, cc.ResolutionPolicy.NO_BORDER);

and have buttons placed with cc.widget in the edge of every side.
With Default resolution:

With another resolution:

With cc.view.setDesignResolutionSize(960, 640, cc.ResolutionPolicy.SHOW_ALL);
You get everything always visible but black bars.

This is the problem that requires workarounds where you have to check framsize and calculate aspect ratios and orientations and then manually apply the correct design resolution size that matches the screen size.

After that you can use the cc.widget as is.
Next step that makes things cumbersome that requires custom components are:

  • When you want custom positions (also, opacity, scale, color, etc.) depending on orientation, without needing to have everything duplicated under “landscape node or scene” and “portrait node or scene”.
  • When you want to fit something into the resolution by scale.
  • Fit something into resolution by keeping aspect ratio and deciding if it should fit by height or width (same as cc.ResolutionPolicy.SHOW_ALL does for everything)

@jare, this is a big thing and I’m curious to hear your vision of how to handle all of these things. I have it working myself, but requires a lot of custom code to create something that I feel could be in the game framework.

Thanks :slight_smile:

Yes, I confirmed this issue. Sorry for that inconvenience. We will review the NO_BORDER implementation, and ensure the cc.visibleRect/cc.winSize make sense. Thanks for you detailed explanation.

1 Like

@Jare, how exactly do I get access to a Scene’s onLoad method?
Are you saying, just have a node with a component and place it before the Canvas Node of the scene?
Please confirm

worldMatrix did update but it is delayed by a frame. So I use this workaround:-

this.scheduleOnce(()=> {
    // position the element
}, 0.01);

You can’t access to onLoad method. onLoad is called by the engine automatically, you should not invoke by yourself.
You can just place the node anywhere in the scene.

World matrix should never affected by resolution unless you were using a Camera with alignWithScreen set.
Currectly alignWithScreen only takes effect after onLoad or before rendering, causing this execution problem. We will adjust the execution order to ensure camera changing its position before all user scripts. Thanks for your feedback!

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