Tuesday 6 May 2014

Parse JSON file in Coco2dx

I have written a simple wrapper around rapidjson for parsing json file in Cocos2dx-2.3.3. You can not use this wrapper in lower versions of Cocos2dx because they don't have included rapidjon library by default, therefore you have to add rapidjson externally for use.

JsonReader.h

#ifndef __JSON_READER__
#define __JSON_READER__

#include "cocos2d.h"
#include "cocos-ext.h"

#include <string>

USING_NS_CC;
USING_NS_CC_EXT;

using namespace std;
using namespace rapidjson;

class JsonReader
{
public:
    static JsonReader* getInstance();
    void read(const char *fileName);
    void purge(void);
    void destroyInstance(void);   
    void moveNext(void);
   
    int getRowCount(void);
    int getInt(const char* key, int def = 0);
    float getFloat(const char* key, float def = 0.0f);
    string getString(const char* key, const char* def = "");
    bool getBool(const char* key, bool def = false);
   
private:
    JsonReader();
    ~JsonReader();
   
    const Value& getSubDict(void);
    static JsonReader* m_pJsonReader;
    Document doc;
   
    unsigned char* m_pBytes;
    string m_sFileName;
    int m_nRowId;
};
#endif


JsonReader.cpp
#include "JsonReader.h"

JsonReader* JsonReader::m_pJsonReader = NULL;

JsonReader::JsonReader() {
    m_pBytes = NULL;
    m_nRowId = -1;
}

JsonReader::~JsonReader() {
    purge();
}

JsonReader* JsonReader::getInstance() {
    if (m_pJsonReader == NULL) {
        m_pJsonReader = new JsonReader();
    }
    return m_pJsonReader;
}

void JsonReader::read(const char *fileName) {
    unsigned long size = 0;
    m_sFileName = fileName;
    string jsonFile = m_sFileName + ".json";
    string jsonpath = CCFileUtils::sharedFileUtils()->fullPathForFilename(jsonFile.c_str());
    m_pBytes = CCFileUtils::sharedFileUtils()->getFileData(jsonpath.c_str(), "r", &size);
    CCAssert( m_pBytes!= NULL, "JSON file not found");
    CCAssert( strcmp((char*)m_pBytes, "") != 0, "JSON file is empty");
    string load_str((const char*)m_pBytes, size);
    doc.Parse<0>(load_str.c_str());   
    if(doc.HasParseError()) {
        CCLog("Parsing for JSON file failed : %s", jsonFile.c_str());
    }
    CCAssert(!doc.HasParseError(), doc.GetParseError());
}

void JsonReader::purge(void) {
    if(m_pBytes) {
        delete m_pBytes;
        m_pBytes = NULL;       
        m_nRowId = -1;
    }
}

void JsonReader::destroyInstance(void) {
    DictionaryHelper::shareHelper()->purgeDictionaryHelper();
    if(m_pJsonReader) {
        purge();
        delete m_pJsonReader;
        m_pJsonReader = NULL;
    }
}

void JsonReader::moveNext(void) {   
    m_nRowId++;
}

const Value& JsonReader::getSubDict(void) {
    return DICTOOL->getSubDictionary_json(doc, m_sFileName.c_str(), m_nRowId);
}

int JsonReader::getRowCount(void) {
    return DICTOOL->getArrayCount_json(doc, m_sFileName.c_str());
}

int JsonReader::getInt(const char* key, int def /* = 0 */) {
    return DICTOOL->getIntValue_json(getSubDict(), key, def);
}

float JsonReader::getFloat(const char* key, float def /* = 0.0f */) {
    return DICTOOL->getFloatValue_json(getSubDict(), key, def);
}

string JsonReader::getString(const char* key, const char* def /* = "" */) {
    return DICTOOL->getStringValue_json(getSubDict(), key, def );
}

bool JsonReader::getBool(const char* key, bool def /* = false */) {
    return DICTOOL->getBooleanValue_json(getSubDict(), key, def);
}


Sample JSON file: LEVELS.json

{ "LEVELS" : [ {
        "ID" : 0,
        "LOCK" : false,
        "NAME" : "LEVEL0",
        "SCORE" : 100,
        "SPEED" : 10
      },
      { "ID" : 1,
        "LOCK" : true,
        "NAME" : "LEVEL1",
        "SCORE" : 100,
        "SPEED" : 10
      },
      {"ID" : 2,
        "LOCK" : true,
        "NAME" : "LEVEL2",
        "SCORE" : 100,
        "SPEED" : 10
      },
      {"ID" : 3,
        "LOCK" : true,
        "NAME" : "LEVEL3",
        "SCORE" : 100,
        "SPEED" : 10
      },
      {"ID" : 4,
        "LOCK" : true,
        "NAME" : "LEVEL4",
        "SCORE" : 100,
        "SPEED" : 10
      }
    ] }


Sample function to parse JSON file using JsonReader wrapper class.

void parseJsonFile(void) {
    struct LevelItem {
        int id;
        bool lock;
        int score;
        int velocity;
        std::string name;

        void Print() {
            CCLOG("ID: %d", id);
            CCLOG("LOCK: %s", lock ? "true" : "false");
            CCLOG("SCORE: %d", score);
            CCLOG("VELOCITY: %d", velocity);
            CCLOG("NAME: %s", name.c_str());
        }
    };


    JsonReader* pReader = JsonReader::getInstance();
    pReader->read("LEVELS");

    int rows = pReader->getRowCount();
    for (int i = 0; i < rows; i++) {
        pReader->moveNext();

        LevelItem* pLevelItem = new LevelItem();
        pLevelItem->id = pReader->getInt("ID");
        pLevelItem->lock = pReader->getBool("LOCK");
        pLevelItem->score = pReader->getInt("SCORE");
        pLevelItem->velocity = pReader->getInt("VELOCITY");
        pLevelItem->name = pReader->getString("NAME");

        pLevelItem->Print();
    }
    pReader->purge();
}

Sunday 13 April 2014

Run Cocos2dx Android Project on Windows


I assume you have already created Android project using template provided with Cocos2dx and imported it in your Eclipse workspace using from existing Android project option and converted it to C/C++ nature.

Also I assume you have installed Android NDK and set up correct path in Eclipse and your workspace location is Cocos2dx default directory.

Note:This method does not require either cygwin or python to run Android project on Windows.

Software's: Cocos2d-x-2.2.2, Windows 8.1 64-Bit and Eclipse 4.4

Step 1: Add Environment Variables

 
Go to Eclipse -> Window -> Preferences -> C/C++ -> Build -> Environment

And add NDK_ROOT and NDK_MODULE_PATH in Environment variables:

1) NDK_ROOT
            F:\Android\NDK\android-ndk-r9
2) NDK_MODULE_PATH :
            F:\Coco2dx\cocos2d-x-2.2.2;F:\Coco2dx\cocos2d-x-2.2.2\cocos2dx\platform\third_party\android\prebuilt

* Note:
If you are using version Cocos2dx-2.2.3 then you don't need to add path for prebuilt modules in NDK_MODULE_PATH. You can only use path F:\Coco2dx\cocos2d-x-2.2.3;




Step 2: Link Resources


Now in your project you have to link your Resources and Classes folders to your eclipse project:

You have to create two folder link named classes and assets If assets folder already exist then delete and recreate it.

To create folder link :
Select Project -> Right Click -> New -> Folder -> Advanced

Linking Classes :
Type classes in folder name and select Link to alternate location (Linked Folder) and type PARENT-1-PROJECT_LOC/Classes

Linking Resources :
Type assets in folder name and select Link to alternate location (Linked Folder) and type PARENT-1-PROJECT_LOC/Resources




Step 3: Setting  C/C++ Builder

Select Project -> Right-Click -> Properties -> C/C++ Build -> Builder-Settings
Uncheck Use default build command option and enter ndk-build.cmd in Build-Command and then click Apply and then click Ok. 

Now eclipse will start building your whole Cocos2dx Android project.





This method build projects faster than Cygwin because Cygwin runs under emulated environment and usually it takes longer time to copy resources to assets directory when you build and run your projects.

Monday 20 January 2014

Handle back key event in Cocos2dx 2.2.2 Windows Phone 8 XAML and C++

Cocos2d-x-2.2.2 version has introduced new project template based on XAML and C++ Component  for Windows Phone 8 platform which allows you to develop games with C# and C++ mixed. You can use XAML components using this template but it's missing BACK key event handling which is primary key for Windows Phone application navigation. However there is a work around which allows you to handle BACK key in your C++ Component based game.

Open CocosRenderer.cpp and change the OnBackKeyPress() method as following:

bool Cocos2dRenderer::OnBackKeyPress()
{
    //return false;
    CCDirector::sharedDirector()->getKeypadDispatcher()->dispatchKeypadMSG(kTypeBackClicked);
    return true;
}



You can override virtual void keyBackClicked();  method in your Game Layer and handle back key event.

Tuesday 1 October 2013

Full screen Command Prompt on Windows 8

When you work with development environments where you needs to interact with command line debugging tools then it becomes very annoying work on Windows 7 and Windows 8 Command prompt window, because by default it opens a very small sized windows and you can not directly maximize them. However you can set manual width and height from properties but again its annoying job because once you have setup manually it won't save settings permanently. Hence here is another way you can use.

1) Open Command Prompt (Cmd)
2) Type "wmic" and hit Enter
3) Press "Alt + Space + X" and hit Enter
4) Type "quit"

This trick simply opens Windows Management Instrumentation Command-line utility which allows you to work in full screen mode. However if you want truly full screen Command prompt then must try Dos emulators like "DOSBox" etc.

* Note : - use all commands without double quotes.

Tuesday 10 September 2013

Remove hidden apps on Windows Phone 8

There are many apps in Windows Phone 8 which are per-loaded by Nokia/Samsung/HTC etc. displayed in settings menu. This all apps are great added features from OEM's but some times many apps doesn't work as expected and crashes randomly. I have seen this problem with the apps like Storage-Check, Feedback to Nokia etc. And if you want to remove or reinstall them then there is no option. But here is a trick that can easily do this job for you.

1) Change your device date to DD-MM-2112 and restart device.


2) Go to settings menu and select options like "Storage-check", "Feedback to Nokia".


3) A message will come with title "Problem with app", read the message and if you want remove it then select uninstall option.



This trick simply expires the date of security certificate with the application. Therefore whenever we open any app then system ask us to either Uninstall or Buy the application.