Cocos Studio: How to support multi resulation

Hi,
i’m using cocos2d-x V3.3 with cocos studio V2.
I have created an animation with cocos studio, it work fine on the ipad retina, but now i can’t figure out how i can support other resulations(iOS and android devices).
I can scale down the assets, but how about positions?
Please help me!

Thanks.

For now, you can use percentage positioning. Which is not great, because there is no percentage content size control, but with the anchor, you can at least do some multi resolution UI.

@nite
Will there be a easy way to change the folders where cocosstudio is searching for the files?

Example:
Structure:
sd (folder) (640*960)

  • background.png
    hd (folder) (1280*1920)
  • background.png

background.png is used in a scene which is 640960
DesignResolution is also 640
960

RealDeviceResolution is 640*960 (should use sd folder)

RealDeviceResolution is 1280*1920 (should use hd folder)

I am thinking of something similar to the multi resolution settings you need to code.
Thanks!

Does the scene created in Cocos Studio supports multi device resolution somehow?
What is the way to prepare scene for multiple resolutions in mind?

Any news? Anything?

I’d also be interested in the solution to this topic if there is one.

We ended up modifying the reader to not take the relative path of the scene file and used the path where the application existed. This then allowed us to use the built in setSearchPaths functionality to do what Michael was talking about. The positions all stayed the same since it relied on the design resolution instead of the device resolution.

that is so lovely! Could you show your code changes and maybe a small cocos studio example?

Why do you need to change the code of the reader?

If you are leveraging the design resolution in CS, you are basically positioning your assets based on the design resolution. As there is only one design resolution, there are no problems here.

The files published with CS are just holding references to the assets, not the actual asset data. If you are loading the CS data with the standard loaders in cocos2d-x, they try to load the assets referenced. The first step is in looking them up in the texture/sprite cache. If they are not found, they are loaded from the path specified in the CS files.

There’s a simple solution for that. Just load the atlas files with the assets used in the CS files as a first step. This ensures, that the cache is populated with the needed assets and the CS files will use them.
The multi-resolution problem is also accounted for with atlas files. Every resolution has it’s own atlas files. With that in mind, the cache is populated with the correct assets specific to the needed resolution. The design resolution of the CS files will not change and so the positions/offsets will not change. The only thing that happens is, that the correct assets are used and mapped to the device resolution.

1 Like

I suggest to forget about/change your thinking here.
Keep your CS files to your design resolution and use the 1:1 mapped assets as dummy files.

Pre-load the caches with the assets needed for your device resolution and the CS loader will take care of it by using the loaded files from the caches.

I think people have problem with multi-resolution, because they are over-thinking the problem and try to map the resolutions in the editor, instead of using the editor for a design-resolution design and treating the used 1:1 mapped assets only as placeholders. It would be a different story, if the assets are embedded in the files, but it’s not the case. They can be served by the (pre-loaded) caches. The pre-loading could also be done by streaming them from a network location. No limits here.

Another suggestion: can we please add an option in CS to drop the file suffixes? It’s an option in nearly every texture packer and you are forced to keep them, when using CS.

1 Like

Keep on reading my other replies, but here is the short version:

Design your CS files based on your design-resolution and using 1:1 mapped assets. Pre-load the texure/sprite caches with the assets based on your device-resolution and let the engine use the references and remap them to your device-resolution.

Woohooo, I certainly didn’t know that! Another thing learned!
Can you give an example how I need to preload the images for the CSLoader to use the correct ones?

For example I would like to use a picture.png. I am using it in Cocos Studio and it’s there under assets/png/picture.png . Now when I load the CS-File with CSLoader it would use the file which is under res/assets/png/picture.png .

What do I need to do to load a different picture.png which should be used instead of res/assets/png/picture.png .

I am so hyped right now XD

Just to give some reference and you can see why it works.

The important line is: SpriteFrame* spriteFrame = SpriteFrameCache::getInstance()->getSpriteFrameByName(path);

This will first try to fetch the asset from the cache given by the path as a key. If it’s not found, it will be loaded from the CS file, but only then! So pre-loading your assets before loading your CS files ensures, that they are in the cache already.

Node* CSLoader::loadSprite(const rapidjson::Value& json)
{
    const char* filePath = DICTOOL->getStringValue_json(json, FILE_PATH);
    Sprite *sprite = nullptr;
    
    if(filePath != nullptr)
    {
        std::string path = filePath;
        
        SpriteFrame* spriteFrame = SpriteFrameCache::getInstance()->getSpriteFrameByName(path);
        if(!spriteFrame)
        {
            path = _jsonPath + path;
            sprite = Sprite::create(path);
        }
        else
        {
            sprite = Sprite::createWithSpriteFrame(spriteFrame);
        }
        
        if(!sprite)
        {
            sprite = CCSprite::create();
            CCLOG("filePath is empty. Create a sprite with no texture");
        }
    }
    else
    {
        sprite = Sprite::create();
    }
    
    // fix memory leak for v3.3
    //sprite->retain();
    
    initNode(sprite, json);
    
    bool flipX          = DICTOOL->getBooleanValue_json(json, FLIPX);
    bool flipY          = DICTOOL->getBooleanValue_json(json, FLIPY);
    
    if(flipX != false)
        sprite->setFlippedX(flipX);
    if(flipY != false)
        sprite->setFlippedY(flipY);
    
    return sprite;
}

RTFM! Use the source, Luke! :wink:
Seems most people don’t know about the inner workings and features cocos2d-x provide.

The best thing(also performance wise) is to create a sprite atlas with your favorite texture packer tool and name the assets in the atlas config file after your path: “assets/png/picture.png”

Then load the atlas into the cache:

SpriteFrameCache *cache = SpriteFrameCache::getInstance()->addSpriteFramesWithFile("your atlas file");

The path depends on how your folder structure is set up inside CS. Just resemble the same structure in your atlas file.

The CS loader/engine will search for the file in the cache and find it(if it’s in the cache with that key).

Just change it in the atlas file and you are good to go.

Of course you can also add individual files by loading it as a texture into the cache. There are plenty of different methods/functions for that. Just look up the sprite-cache/texture-cache API.
The file-name(including the path) will be used as the key for the cache.

So it’s easier to create different sprite atlas files for different resolutions and just load the atlas which should be used.

Thanks, I will definitely try that!

Yes. Forget about loading individual texture files. They will be treated as a single texture resulting in wasted resources, draw calls and harm your performance.

Pack as much as you can into an atlas. All assets in one atlas are treated as one texture and so as one draw call/texture bind.

E.g.:
100 individual textures loaded in: 100 texture binds and 100 draw calls.
100 textures in 1 atlas: 1 texture bind and 1 draw call.

This is of course very generous and the optimum. It depends on context switches and various other things.

Sadly it’s not working :confused:
I am using cocos2d-x 3.4 final. I am also using lua.

CocosStudioMultiResolutionTest - CocosStudioProject (37.1 KB) As you can see I am using only one image (background.png, 640*480)

res.zip (143.8 KB) This file contains two sprite atlases (sd and hd) with the same assets/background/background.png key.

src.zip (1.6 KB) And here you have the two lua files (main.lua and IntroScene.lua). The main.lua is setting searchPath and contentScaleFactor. The IntroScene.lua is loading the CS-File.

Any ideas?

I was debugging with Visual Studio and set some breakpoints in the CSLoader. But the breakpoint in the loadSprite() method was never called. Meh.

Btw.: if your png file has the same name as your atlas config file, you don’t need to pass it as param:

cc.SpriteFrameCache:getInstance():addSpriteFrames("assets.plist", "assets.png")

It’s enough to just call:

cc.SpriteFrameCache:getInstance():addSpriteFrames("assets.plist")

Do you get an error message about not finding the sprite from CSLoader? If so, which is it?

Is the cache filled with the atlas asset key “assets/background/background.png”?

This method is not called for loading a node.
You have to set a breakpoint in Node* CSLoader::nodeWithFlatBuffersFile(const std::string &fileName) where it’s adding the textures into the cache:

for (int i = 0; i < textureSize; ++i)
{
    SpriteFrameCache::getInstance()->addSpriteFramesWithFile(textures->Get(i)->c_str());        
}

Check which texture keys were added by the atlas loader and compare them to the keys in the code above.

After digging through some source code:
First, this will work work CS 1.x out of the box.

As you are working with CS 2.x:
The file format supports textures, which are loaded into the cache. This is the atlas feature of 2.x.
What you have to do in 2.x, is to create/import your atlas and use those references in the editor.

The editor will only generate a file with atlas support, if you defined one in the editor. Unfortunately you can only import non-encrypted, non-compressed atlas files. But that does not matter, as you are pre-loading the real atlas files in the engine anyway.

Sorry for that bogus :blush: I just use CS 1.x more than CS 2.x.

I think, that this is some big missing feature.

1 Like

Hm… That means I need to create a atlas in CS 2, use it and in code I need to load a different atlas (with the same keys of course).

edit
weeeeeeee! It works <3

Exactly. The CS loader does not care where the assets came from, as long as they are in the correct location/have the same keys.
Regardless if CS does not support encrypted/compressed assets, they can be used as long as the engine supports them. The pre-loading ensures that the assets defined in the atlas used in CS are actually in the cache.

:smile:

I just want to point out that this is really annoying. Now I need to edit every scene in the project only that it loads from the SpriteFrameCache. @zhangxm @nite I think this could be improved.