Battle Shock

Check out Luna Sea Games to see the iPhone version of Battle Shock in the AppStore now.

Monday, November 29, 2010

long day

I feel like I should have gotten more done for all the time I spent today. I did manage to get JSON queries against the cocos live service working. So the high scores are coming in. Reading JSON from Android was very helpful. As were the docs on HTTP services. Haven't gotten score posting working yet.

I was able to get the app to save and restore it's state. The key was to reload all the gl textures in the onResume - and to reset the variables that may refer to them in the onPause. You also have to be careful because the onResume will be called when the app first starts. So liberal protections from double init - double free, etc. Somehow I managed to break this in the last hour of working. Of course I don't have revision control setup. So this was the straw.

I create a git repository for all my local source. I usually always work with source control. Not sure what I was thinking. It's great to put a bookmark in when you have features working. I downloaded and built the osx client GitX. It's been a while since I used git and this made settings things up very easy.

btw, I wasted a lot of time tracking down the weird error. You find code like this in many examples. It doesn't work with Android SDK.


void Java_com_trial_filesys_SimpleTest_main(JNIEnv *env, jobject obj, jstring filename) {     const char *fnameptr = env->GetStringUTFChars(filename, NULL);
    env->ReleaseStringUTFChars(filename, fnameptr);
}


which will give this hoaky error:

error: request for member 'ReleaseStringUTFChars' in something not a structure or union

The fix for this is:


void Java_com_trial_filesys_SimpleTest_main(JNIEnv *env, jobject obj, jstring filename) {     const char *fnameptr = (*env)->GetStringUTFChars(env, filename, NULL);
    (*env)->ReleaseStringUTFChars(env, filename, fnameptr);
}



idea

The sales of BattleShock were pretty good on the iPhone AppStore but I started thinking about what could improve things, especially given the new launch on the Android Market.

I thought about different game play additions that might make things more interesting. I like the idea of building defensive burms and moats with my finger. I think the field should scorch and the grass should be burned away over time. A huge armored elephant or larger dragon should come out at some point. I'd like to see the enemy show more intelligence. Perhaps crouch behind some rocks that protect them from my magic. Then run scurrying out on the left as I attack on the right. But all these things will take a lot of time to implement.

I had a buddy who launched a free skateboarding game online about 10 years ago. It wasn't a fantastic game ( sorry man ) but he managed to get a pretty large following. The trick was to hold a weekly contest and offer free stuff from his sponsors. He got some skating gear from different companies and they in turn got some advertisement in his game. I'm not really one for advertisement in games, but I think the weekly contest could really help spread the word. I mean, how many mobile games can you play and actually win something? I bet if we put up $100 cash a week that it would attract at least that much in sales. And we could give small bonus points to referrals to encourage spreading the word. I was thinking that everyone in the top 100 point totals for the week would be in a drawing - not just the high score. And the more top 100 scores you had the better your chances.

I've never run a contest. So I know when money is involved there are rules. Gotta go do some reading...

Sunday, November 28, 2010

digging in

The port of my iPhone game to Android is going well. Game play is up. Some minor bugs. Sound is up. Still needs to accept volume tweaks. Io still coming off the sdcard. That is temporary and needs fixing but shouldn't be too hard. I decided to tackle the application life cycle.

Every time you hit the home button or generally leave your app you get an onPause event. You are expected to do everything needed to wrap up. Here, I discovered, I need to pause the MediaPlayer. It appears that a feature of the player is that it continues playing while in the background. Useful if I was writing a Pandora clone, but not for this game. Next I save the game state to the sdcard. So far this has been quick enough that I haven't run into the problems that some have hit.

http://zakattacktaylor.com/?tag=ndk Has some interesting insights into porting code to the ndk. It was good to learn that Android expects you to reload all your graphics back into memory after being paused. That's my project for tonight.

For anyone looking to know more about the application life cycle I recommend reading:
http://developer.android.com/reference/android/app/Activity.html

Friday, November 26, 2010

playable demo!


Things are progressing well now! Here's a little video of things so far. Once my templated vector was fixed game play was working. I needed to scale my input by the ratio of the new screen dimensions relative to the original iPhone dimensions. Then all the inputs lined up. 

I wrote a slim sound wrapper that captured all the sound events in the game into a queue. Then I poll the queue from my java loop once per frame. It consumes the queue and issues the sound calls to a Java SoundPool object. Music is handled as mp3 files sent to the Java MediaPlayer. It appears to handle it all very well. I specified 16 channels for the SoundPool which matches the original design on the iPhone. The SoundPool does an automatic sound selection based on a priority scheme. But right now all sounds have the same priority. May need to adjust it, but works fine for now. I don't have any of the pitch adjustments taking place now. I want to review the product with the original authors.

I noticed that the aspect ratio is different than the iPhone. It causes a slight distortion which you get used to very quickly. I'm not sure it's worth bothering about. 

The colors appear different too. Almost less saturated on my Droid X than my iPhone.

Still a lot more to do. I took some short cuts to get to this point. I need to go back and address file io. I have a bug where bad guys get stuck in the top left corner of the screen. I'm going to merge with the lastest drop of the engine and I hope things improve. I need to figure out how the app lifecycle works. The app music continues to play when you leave the game. And I need to learn how to maintain state so that we can jump to a phone call and come back to the game in the same state. By default now it starts all over each time you leave and come back. I was hoping the os would handle that by defualt. Oh well, it's not a desktop machine. But it certainly is cool what these little devices are capable of! 

Black Friday

Decided to try out the mobile android app for Ebay. I've lost the last three bids for used G1 phones. I want to have at least a small sample of hardware to test on. At least one older generation phone. I'm new to Ebay and keep getting outbid at the last moment. So with my shiny new Ebay app I set about searching for a phone.

I quickly find a number of G1 phones and I like how the interface shows bids in red that are nearly over. I scan a few pages to get an idea of the price range that they are going for. It seems like many are still going for over $100. I see one at $66 that has just 10 minutes left. I put in a bid with $70 as my max. The timer counts down in real time, which gives me reassurance that i will be able to put in a last minute bid. I get an email 3 minutes later that I've been outbid. Hrm. I was hoping to see that in my app. I decide to wait for 3 more minutes and then bid. The price is now $71. I bid a max of $75. Two minutes later I'm outbid. Less than a minute to go. This is where you have to decide what your limit is. I almost let it go. I set my limit at $75. But i check the other bids and many are going for over $120. So with 30 seconds to go I bid a max of $80. The price changes to $78. Then at the last moment the other person puts in a bid of $79... But I win with my $80! Wooot!

My first Ebay item that I've won. Very cool. I'm smiling and justifying my purchase to my wife. "I can deduct it!" I assure her, not really sure myself. I think I can. In any event, I'm glowing. I contemplate going for another older phone just for the fun of it... Nawww.

Thursday, November 25, 2010

frustration ;-(

Things have been going swimmingly up to this point. Last night I got touch events going into the app. Again just capturing the java touch events in my view and then calling their native counter parts in my game. So the game loop actually started... and then crashed about 3 seconds later.

Ok, now for debugging my c library linked into my java app. I knew I needed to set things up sooner or later. A few google queries later I find how to debug with ndk and I'm convinced I need to upgrade my eclipse from 3.5 to 3.6. I find 3.6.1 and decide to go with the latest. I try downloading the eclipse plugin from Sequoyah Project, but it says there's no files available. Hmm, perhaps I have too new a version of eclipse? I download the older 3.6. Again the install from within eclipse can not find any files to install from their site. So I download the zip file of the plugin and then try to install from zip archive in eclipse. Still it says there's no files to install. I try setting up the debug settings in the original post. I repeat my steps about 3 times and give up.

I decide to try the debug setup without the Sequoyah plugin. Now the problem is that it says my project is not a c project and can't do a c debug session. So I create a c project to build my jni source. Then I launch my java project, load the c library and break. I try to but it won't let me launch the c build because it says there's no target. I notice that the debug project specifies to use the armprocess file in the obj dir when debugging. That doesn't work.

I find a bunch more posts from people that have just given up on eclipse debugging, and I can understand why. I decide to try command line debugging. There's a debug script that's in the lib folder. I launch my java app, step past the loading of my c libary and break the java app. I'm able to connect to the running process through ndk-gdb script. Cool! I set a breakpoint on my load function - b LoadFile. Then I type continue. The app runs past my breakpoint and crashes. I try again, set my break and then continue the java app running. It ignores my breakpoint and crashes. I try 4 or 5 variations I can think of. Repeat a few that I'm sure should have worked. I restrain my urge to punch in my monitor. I don't need to buy a new one, and I'd probably just injure my hand.

Ok. Not working. At least I'm getting a stack trace from logcat. I add some commands to generate a map file and then look up the stack addresses. It appears that the path generation is crashing. By now I feel like I wasted hours and no further on what might be a simple fix. I decide to start the tried and true - printf debugging. Luckily there's a handy function I can call from c to send text to logcat.

Now at least I'm making slow but forward process towards finding the real problem. An hour of binary search leads me to suspect on of the routines in my hand rolled vector routine. I realize my error and make the small fix. Finally.

I may revisit my steps more slowly. Perhaps I was too impatient. I feel I'm usually one that figures things out fairly quickly. After 3 or 4 hours of failure I start blaming the process. Perhaps that's my problem. I have too much pride and start blaming the tool chain instead of patiently retracing my steps. I resolved to find some more authoritative docs and give them a thorough read when I'm more rested.

I left out the part where I tried to install STLPort and failed to find sufficient indication of how to build it under the andoid ndk. I think that's my best bet long term.

Tuesday, November 23, 2010

graphics up!


It's always refreshing when you first get a graphics loop going. Especially when there is so much going on. There really wasn't much too it.

I started with the SanAndreas java shell in $(androidndk)/samples/san-angeles. This creates just a basic Activity, creates an GLSurfaceView derived view, and assigns a GLSurfaceView.Renderer derived render with overloads for onSurfaceCreated, onSurfaceChanged, onDrawFrame. Next call our native versions of each of these and the graphics loop is going!

I did struggle with the file io from native code. I don't have a great solution yet and there seems to be some debate about the best practices here. It appears that files are stored zipped in the apk and must be unzipped if accessed directly from c. It's also a struggle to get a file descriptor down to c.. let alone call java code from c.. which I haven't figured out. For now I took the lazy way out. I put all my files on the sdcard under /sdcard/BattleShock and just did standard c fopen to access them. This works fine, but is no way to ship an app. All your source is just laying around for someone to tinker with. Then again.. that's what they do on a pc? Well, if it comes to that I will pack all the files in a single packed file.

I started to get a little worried about binary compatibility with other android phones. I'd like to test a few. I have a Droid X and an HTC Incredible. Both of these are second generation android phones. After watching Real Time Games for Android Redux it made me want to target 1.5 and 1.6 phones. They appear to be the majority of the market. I emailed Verizon asking for development phones and they politely sent me to google. It appeared the google was out of their development cache of phones. I spent some time on ebay and even bid some on some phones with smashed screens, but I got outbid! Seems like 1.5 and 1.6 phones are still going for @$200. I'd like to get a few, but don't have the budget.. what to do?

libBattleShock.so lives!

So I'm starting on this journey to port an iPhone game to the Android system. I thought I would document some of the steps and possibly pitfalls. I'm no Android guru. I'm new to Java. But I've done a fair amount of c development, so this shouldn't be too hard, right?

I lucked out that my iPhone game was mostly in c with an objective c wrapper hosting the game. My Android port will nicely parallel. It will be an native c library compiled against the arm cross compiler. I will dynamically load the library into a Java shell app that will pump os level events to my app. Not sure yet how I will go the other direction.

Setting up my development environment was a breeze. Just check out the steps on http://developer.android.com/sdk/installing.html. I'm developing on a mac. Since I'm building the native - and by native that means NOT java - c library I needed the NDK as well as the SDK.

I followed a quick little tutorial on JNI. Just create a c file with a special name declaration that matches the stub in Java. Then call your java stub function after you load the c library and you are good.

I followed the recommended setup for putting all my c source under $(project)/jni. I created an simple Android.mk. I recommend reading all the docs in $(androidndk)/docs. There's a bunch of text files in there. They are not too verbose and get you the details you need to know.

All my source files were .mm instead of .cpp because they came from an iPhone project. I tried telling my makefile that .mm was the new .cpp, but it just complained that there was no objective c compiler and seemed to ignore my directive. So I changed all the file extensions to .cpp and the .h files were fine. Ok, now down to business.

I decided to keep the remnants of the iPhone code around and just create all my changes in an #ifdef ANDROID block. I started by adding one .cpp file at a time to the Andriod.mk file and then running $(androidndk)/ndk-build and #ifdefing out most of the things I couldn't fix and putting //TO DO's here and there. File IO was of course out. No bundle here. Typedefs were my friend for NSString and many other types. The entire OpenAl sound engine I stubbed out. Ahh, STL. I briefly read around and it appears that STLPort is the one most are using on the android NDK. Looking at my source, there wasn't too much use. So I took a templated vector class I had and adapted it to work for the usage. Quick fix for now, perhaps I will return to STLPort. There was a pathing source that had more use of STL. But it turned out that most of the #includes were not actually used (!) and just commenting them out and using my vector hack got me going. Thankfully all the OpenGL came over with little modification - for compiling anyway. And in just about 4 hours I had a brand shiny new libBattleShock.so - with large parts turned off :-) .