Battle Shock

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

Wednesday, December 29, 2010

If you build it...

Battle Shock for Android is officially in the Android market now! The last few weeks were a challenge. We kept thinking we were close, and then we would find a hole in game play that would send us back to retune.

The first problem we found is that you just didn't need the archers to win the game. They were too expensive and weren't all that effective. Well we made the black knight and the black archers impervious to magic. So it's now required that you have enough archers to handle these menaces. But that led to a problem where you would run out of money for archers and a black knight would stroll on screen! So you were helpless and had to sit back and watch him hack up your castle. So now we notice that situation and spawn enough lite troops that you can win enough coins to buy some archers.

But then we noticed that the archers weren't all that accurate. Now that we are depending on the archers, it was super annoying when knights would march all the way to the wall unscathed when you had a full rack of archers. Well, a little work and wahlah, they were hitting knights in the helmet from nearly full screen distances. That's what I like, and archer that earns his keep!

But now the archers were updating the balance of the game. They were too powerful. And also we noticed that it would be nice in general if there were more progression to the spells of the game. So we added 10 levels instead of 3 for all the spells. This added a lot to the game and there was now more strategy in how to spend your coinage. But this had now become a tuning nightmare. The game would be hard till level 50 and and then become too easy once you had leveled up certain spells. So after a few more weeks of tuning, I think we have a gem for you.

Hope you enjoy all the hard work we put into the game. There's a lot of attention to detail. We are always interested to hear your feedback. Please let us know how you like the game!

Wednesday, December 8, 2010

Die app, die!

I think it really runs counter to the Android philosophy to actually kill your application when you leave it. That makes sense for email or web or times when you are jumping around to different lightweight tasks. However, a game is another animal. It consumes most of the resources of your phone. It's a high intensity activity and you are not doing email or mutli-tasking while you are playing. And when you are done, you're done! It's on the shelf. You will come back when you have time.

In my case, there was actually a very nasty bug that occurred when you left the app and came back. Somehow I managed to completely sieze up the phone making even the volume and power keys unresponsive. The only way out was to yank the battery! That's a hard lock. But it was actually just a pegged cpu. I could watch the usage spike on the task manager. I know it's my bug, but it's hard to believe that the os would allow a process to runaway like that.

Anyway, long story short, it was better for everyone if my app just quits when the users leaves. Accomplishing that took some research. Many people posted answers that didn't work for me. The one that worked was:

protected void onStop()
{

     super.onStop();


    //kill this process. It does not reload cleanly. And I think most users appreciate the app leaving memory.
    ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    String packageName = getPackageName();
        am.restartPackage(packageName);

}


and then this would crash and throw up a dialog that my app had crashed and was ok to force quit. So to avoid that dumb message you have to add some permissions to your manifest so people know you can kill your own process.. not thrilled with the whole affair. Anyway, add this:


<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>

to your manifest, and you will have an app that behaves like 99% of the other os's out there.

Sunday, December 5, 2010

I can see the light

Just wrapped up the last of the issues I had to complete for this port. This weekend I knocked out the loading screen, memory leak on recycle, online score poster, assets larger than 1Mb, encrypting user saved files, and leaving a clean presence on the sdcard ( no sprites or temporary data ). All in all very productive. I'm lucky to have a wife that understands that sometimes I need to disappear in my office for two whole days...

There's really a lot I could share with someone doing a port. A lot of people seem to suggest that you should do a splash screen with an Activity. I didn't really want to do that because I want my main activity to keep focus. That's because it has the opengl surface - and since I want to be loading while we are staring at the pretty loading screen - I have to load textures in the thread of the opengl surface. Or rather, I need to bind them there. I guess I could load the data and bind them later. Oh well. I just made a custom dialog as a splash screen and that worked peachy.

And if you need to encrypt files it's really pretty easy. Here's an article on Sun's site that was helpful. Combine that with this and you have some really good leads on putting it all together. If anyone asks I can post the source.

In that same vein, if someone is looking to make an Android game that uses the cocos live site for highscores, I could share my port of their objective c code.

Hopefully you all will soon be able to play the finished product in an Android Market near you! Stay tuned for release dates.

Thursday, December 2, 2010

scruggly phone

I'm sure the G1 was a shining trophy of progress the day they first came out. But the one that arrived in the mail was beaten up, scratched, and eewwww.. slightly oily. I am the proud third owner of this cell phone that I bought off ebay last week. I got it just for development. And thank god, because I would hate to have to use it.

After a bath in windex, I plopped in the battery and fired it up. It wouldn't do anything without a sim card. It was stuck on an emergency dialer screen. I scrounged one from a pay per use phone I had lying in a drawer ( great for when the in-laws visit from Japan). Now it wanted me to sign up for a google account - and wouldn't let me get passed the regisration screen until I did. I had no cellular connectivity and it wouldn't allow me to setup the wireless connection. So I was stuck. I briefly worried that I had just purchased an $80 paper weight, and an fugly one at that.

Thankfully there are an army of people who have blazed this trail before me. There were online instructions on how to break into the phone without a cell account. For me it ended up being a long series of steps which was a combination of a bunch of different sites. I should probably list them all, but I don't have the energy. Basicly I had to downgrade the phone to RC29, then type in a code to enable adb connections - 'setprop persist.service.adb.enable 1', then fire up the wifi settings from an adb shell:
am start -a android.intent.action.MAIN -n com.android.settings/.Settings
Then setup wifi, go back to the phone registration and then complete the registration so I had access to the phone.

Now I had a 1.0 android phone with no attachment and no contracts! Yay. I needed to get to 1.6. This guide did the trick for me. An hour later and 4 flashes to the eprom and I had a usable phone at 1.6! I need it to be 1.6 because that's the earliest version of Android with OpenGLES support ( as far as I know ).

After that I downloaded my app and installed it on the phone. Fired it up.. and waited... and waited. Slowly the first menu came on screen. I hit the play button about 4 times. It was just slow to react. Slowly the screen changed. At about 1 frame per second, the bad guys dreamily came down from the top of the screen. I was now Flash and could issue 100 fireballs per each step of each guy. Clearly there are performance problems.

I was wondering how capable this device is. I downloaded the game Replica Island and I've tested on different phones and I know the author paid attention to performance. The game played fine. Maybe 20-30fps. And it was doing at least as much rendering as we. So clearly I'm going to need to do some digging. Good thing for me, the source for replica island is hosted on code.google.com!

Wednesday, December 1, 2010

burning on both ends

Whenever my life gets busy, for some reason I take on more. No telling why. Got home, ate dinner, and worked till 1:30 on the port. But enough about me.

I tracked down the bug causing guys to get hung up in the corner. I also locked the orientation in portrait mode. This was needed. A small orientation change would issue a pause and resume and cause a reload of assets.

The most exciting development last night was the discovery of deviceanywhere. They have a large suite of mobile phones that are all wired up for a kind of remote desktop control. So you can upload your application to a real device, not a simulator - and perform automated tests. Very exciting! They even seem to be reasonably priced. If you are a one man show like me, be sure to check out their discounted rates for Independent Developers.

I was able to upload BattleShock.apk to a Droid phone in their cloud and run the application - and it worked! Unfortunately I still hadn't solved the deployment of the sprites from the package to a dir on the /sdcard so there were no graphics. So I decided to implement the simplest thing first - I copied all the assets from the internal package to the /sdcard/BattleShock dir. This is by far the simplest to implement and debug. Here's some discussions that were very helpful.

I also took the time to reduce all the audio assets to 8 bit wav and 48kbs mp3. This makes for a much smaller apk and improves turnaround time when developing. Highly recommend it.

And so, after getting the assets unpacking correctly I deployed the new app to the cloud... where it crashed. Bummer. Now I want to know if I can remotely debug. Though I can't even debug locally, at least I get a callstack. I think I will have to resort to a good old local text log file - printf debugging ahoy!

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 :-) .