, , , , , , , , , , , , , , , , , , , , , , ,

/

May 13, 2016

[Cocos2dx] FileUtils Cross-Platform Resource Handling For IOS and Android

Prerequisite :
I hope the one going through this tutorial have prior knowledge of cocos2dx development and is currently using cocos2dx for one of their game project. A basic understanding of C++ and use of preprocessors is required to implement  this tutorial in one of your project.

Problem :
In most of the cross platform game development using cocos2dx scenarios their are multiple developer working on the same project faces a common issue related to paths of files in resource folder specially the assets like images and audio.
e.g
on ios / mac

Sprite *anSprite = Sprite::create(“some.png”);  works irrespective of it’s location in directory under Resource folder.
While for android you might have to specific the path to image like “path/to/image/some.png”

This wastes a lot of time if you have to port the project to run on either of the platform or any other supported by cocos2dx

How A Lazy Developer Solves This Problem  :

The shortest way to solve this is to put all the images and files under Resource Directory of cocos2dx.
Surely you don’t have bother about anything but again image if you have lots of asset that needs to be managed carefully for each resolution .

Cococ2dx Solution :-

Earlier CCFileUtils now FileUtils handle this problem for you with ease but i’ve seen most of the developer who only have to run the project on single platform will never care to use these methods and even if you use this it does make you code look a little ugly.

Usage :-
FileUtils::getInstance()
This singleton class provide lots of helpful and very useful methods for  file handling operations specific to different platforms.

Suppose you have various subfolder in your resource folder.
like this
Resource\Images\ipad\hero.png
Resource\Images\iphone\hero.png
Resource\Images\ipad\level1.png
Resource\Images\iphone\level1.png

Resource\Images\GameGUI\ // contains all UI related assets
To create any sprite from this you can write following like on iOS
Sprite *hero = Sprite::create("hero.png");
Sprite *levelBG = Sprite::create("level1.png”);

And this is not going to work when you run the code on android platform. As for android you need to specify full path of the resource or it should be  direct under Asset Folder and suppose you have various resolutions like HVGA WVGA etc so cocos2dx provide following flow.

Add Search Path in FileUtils specify resolution  anywhere in your code.
FileUtils::getInstance()->addSearchPath("Images");
FileUtils::getInstance()->addSearchPath("Images/GameGUI/“);

FileUtils::getInstance()->addSearchResolutionsOrder(“iPad”);
FileUtils::getInstance()->addSearchResolutionsOrder(“iPhone”);

Get path for File Name
FileUtils::getInstance()->fullPathForFilename(“hero.png”)

OR
FileUtils::getInstance()->fullPathForFilename(“level1.png”)

will return exact path to these images based on device resolution or type from the Resource folder.

Sprite *hero = Sprite::create(FileUtils::getInstance()->fullPathForFilename(“hero.png”));
Code will this work on any platform supported by cocos2dx.

Short Trick:
Now C++ is an excellent language and it does provide a lots of feature that an programmer can use to not only
optimise the code but make it look beautiful.
Using #define preprocessor will not only save your time writing FileUtils everywhere you need to access a resource but also make your code look clean.

Add these lines either in AppDelegate.h or any file where you put your constants or configurations
#define IMAGENAMED(__FILE_NAME__) (FileUtils::getInstance()->fullPathForFilename(__FILE_NAME__))
#define AUDIONAMED(__FILE_NAME__) (FileUtils::getInstance()->fullPathForFilename(__FILE_NAME__))
// just to make code look tidy.

#define ADDPATH(__FILE_PATH__) (FileUtils::getInstance()->addSearchPath(__FILE_PATH__))
#define ADDRESOLUTION(__RESOLUTION__) (FileUtils::getInstance()->addSearchResolutionsOrder(__RESOLUTION__))

Now i’ve this IMAGENAMED thing and i’m so obssessed with it ever since I started programming games for iPhone back in 2009 but you can feel free to use anything to define it in your code.

So the previous code block now becomes .

ADDPATH("Images");
ADDPATH("Images/GameGUI");

ADDRESOLUTION(“ipad”);
ADDRESOLUTION(“iphone”);

Sprite *hero = Sprite::create(IMAGENAMED(“hero.png”));
Sprite *levelBg =  Sprite::create(IMAGENAMED(“level1.png”));

You can use it anywhere for eg. in menu
MenuItemImage *btn_menu = MenuItemImage::create(IMAGENAMED(“menu_button.png”), IMAGENAMED(“menu_button.png”), CC_CALLBACK_0(GameSceneUI::onMenu, this));

I hope this short trick help you handle Resource across different platform easily .

Feel free to write me back for any query or questions or issue in my above tutorial.