«

»

Sep 08

Cocos2dx Migration -> Sixth update (40 hours) JNI We meet again

Things were moving ahead quite nicely, converting my obj classes to C++ went smoothly, cocos2d-x is really well refined. I even found out that there was a problem in my declarations for using sprites with sprite frame names, so I fixed that code. I also wrenched in some ad frameworks, and most of all I’ve been working back and forth with the folks at Kiip. After my first (bad) impression, they were kind to follow through with all my information requests and clarifications. So in the end I said ‘if it’s not too hard to integrate, i’ll give it a go’. Well the issue we have here is that Kiip is native for iOS and android, but I want it to work on both. Plus, all my code is cocos2d-x (c++) with no calls to Java (well very few), so I’d need a JNI wrapper to handle Kiip. I’ll get to that in a second.

First things first, I think my first post I mentioned I love the new ‘create’ initializers, however I had an issue with create(), well that’s because I called the wrong init! There is actually a createWithSpriteFrameName(”). If you use just create(”) it’ll look for that file, not a frame name, hence the second initializer. It just brings it inline with what they’re doing, and it’s great. So to sum up.

To create sprite with a file call this:

CCSprite *mySprite = CCSprite::create("filename");

To create one with a spriteframename

CCSprite *mySprite = CCSprite::createWithSpriteFrameName("frameName");

Ok that’s cleared up let’s keep moving, as we have some more work to do! So Integrating the ad networks (I use mobclix and admob open allocation) was pretty easy, I actually migrated the code from my other app ‘Retro Art Studio’ for android, and dropped it in. I did have an issue doing the layout in the XML file, so I just did it programmatically and it worked fine. The only thing I’m not doing which I’d like (which I do on iOS) is control when the ads show and hide. Right now they just are a view and show over the game when the app opens, sorry I just don’t have time right now to fix that. Ideally I’ll plug in some JNI calls and have them hide / show during the right times.

JNI… first of all, I write code in many many languages, C, C++, OBJC, Python, (some ruby, basic, shell, action script, javascript), etc. One language that I’ve used in the past, and try to avoid at all costs is JAVA. I find it repulsive, I won’t go into the details, but the sum is ‘write once run everywhere’ the original motto never worked, so everyone who jumped on it got screwed. It’s the most difficult to develop and debug language around. By attempting to simplify (‘HEY NO POINTERS NEEDED!’) they’ve encouraged sloppy programming standards, and an over complicated way of delivering underperforming code. — Sorry for the rant, just got stuck in the Java mud and it pains me every time — Professionally I tell clients I don’t do Java, and they assume I don’t do android, on contrary I do android, via C++, if you want a Java / web based app, there’s plenty of people out there for that. I’ve worked at Apple, I’ve used Java (not at apple), I’ve used Windows for many years (prior to my job at apple), and in the end I choose the tools I like, which are Linux/Apple OS’s, C based languages, Xcode (for C++/OBJC/etc), Python for scripting, vim for editing on the command line. P.S. I have zero fear of managing memory, I actually enjoy it.

OK! Rant over, back to work. So Kiip, these guys have an interesting idea, but like I said I wasn’t sold on their initial pitch, but going back and forth it seemed like something I’d be willing to try on this android version of the app, and if it worked well I’d put it in the iOS version. The basics of Kiip is that you can reward players at certain levels with unlock able real-world items. Mainly coupons, vouchers, gift cards, etc. I don’t provide them, they are provided by the advertisers, e.g. If you unlock level 20 in your game, then you’re rewarded a coupon for a bag of Chippy brand Fish Sticks. Which apparently you can take and redeem at your local Chippy brand grocer. (Or something like that).

So to integrate I needed it to work on both iOS / android. First thing is their setup is pretty good, I’ll admit the walk through was easy to follow. And I called into the iOS api instantly and was up and running in about 20 minutes. Their website has great debugging as well, you can real time watch the log of you logging in and unlocking achievements. Impressive. Now for android… My contact at Kiip was great, when I mentioned I was doing cocos2d-x he sent me a wrapper class another dev had created for JNI. This was a huge help, until 6 hours later I realized it didn’t work. No fault of Kiip (they said it wasn’t their code, and was unsupported), and no fault of the original Dev. It was built against a different version of cocos2d-x and Kiip, so it just wasn’t up to date.

I had to put on my JNI hat again, and grrr… go to java. Well I hit so many roadblocks, first this code was made without JNIHelper, which simplifies a lot of code that was written, second I couldn’t get the method signature right for the kiip call to the ‘saveLeaderboardScore’ method. I could get access to the static singleton, but couldn’t call the method inside. I tried every combination I could think of, and it just wasn’t going. So after a while, I just implemented JNIHelper and that simplified the code by about 140 lines. However it still wasn’t doing what I needed, the signature was wrong. I called it the way the API said, no luck, I called it the way javap said, no luck, I made up ways to call it, no luck. So in the end I did a ‘hack’, but it worked and it was clean and easy.

I implemented a method in my root java class (the one called by the app that loads up my c++ code), and in there I added a simple static method that called the actual lib and submitted the score. Then in the JNI wrapper, I replaced all the code in there with a call to my simple static method and hey, it worked! Ideally I should call the method directly, but that wasn’t going well, and I feel that if I can do the same in < 10 lines of code that was done in > 100 then I’m probably ok. Obviously you don’t want to add a ton of new methods to your .java file, but this really is a single one as I’m only using leader boards right now, so I didn’t mind.

Here’s the code I ended up using in my .java file

	 static public void kiipSubmitToLeaderboard(String boardName, int score)
	 {
	     Kiip.getInstance().saveLeaderboard(boardName, score, null);
	 }

Then to call it from my wrapper class.

void GameResults::SubmitHighScore()
{
...
    KiipWrapper::sharedKiipWrapper()->reportScoreForLeaderboard("highscore", _score);
...
}

You can have multiple leader boards, so just create a const char * for whatever the name of your leader board is along with the score amount. There’s probably many other ways to do this, but for 6 lines of code, not bad.

After that, the kiip code was up and running and I just tweaked out the alignment a bit (which is done via their web interface, in real time which is cool.)

Depending on how my (and my users) experience with Kiip goes, I’d be more inclined to explore it more on my other apps, as well as provide a step-by-step approach to get it up and running in cocos2d-x. But first I have 8 more hours to go to hit my deadline!

Leave a Reply