DinoMage on Twitter RSS Feed

Author Archive

This is part 3 of my HowTo: SDL on Android series.
(prev)

Now let’s get some more native libraries linked into our app.  I probably don’t have to tell you how important this is, since you can’t make a whole lot of games or apps without text, sound, or music.

SDL_ttf

Adding a satellite library like SDL_ttf leads us through several steps.  These are roughly the same for each library, so I’ll only go over this one in specifics.

1) Download the source. Get the latest source from the Mercurial repository or grab a snapshot from the official page.

2) Place source in project. Put the SDL_ttf source directory alongside your SDL directory in your project (in jni/ so you get jni/SDL_ttf).

3) Gather dependencies. The way everything is set up, you have to be particular about the directory placement and naming.  The SDL extension libraries mostly expect their dependency directories to be in jni/ and to be named in their simple form (e.g. libDependency-0.3.0/ would be dependency/).  For SDL_ttf, we need to get the FreeType2 library.  Go to the FreeType official downloads.  You might end up in a list of files to download.  The latest version should be good.  As of this writing, that is “freetype-2.4.11.tar.gz” (you don’t need the doc or demo archives).  Yeah, you’ll probably need a good unzip program that can handle tar.gz or tar.bz2 archives.  Now, SDL_ttf strangely expects FreeType to live within the SDL_ttf directory.  Copy or move it over into the jni/SDL_ttf directory and rename it to “freetype”.

4) Add include and linker flags for the library. Open up your jni/src/Android.mk file.  Add $(LOCAL_PATH)/../SDL_ttf to the LOCAL_C_INCLUDES line.  That will give all of our files access to the SDL_ttf.h header. SDL_ttf knows how to build itself (it has an Android.mk), so it will create a shared library that we can link to.  Add SDL2_ttf (note the “2”) to the LOCAL_SHARED_LIBRARIES line.  The library is linked as SDL2_ttf so you can install it alongside SDL_ttf built for SDL1.2 as necessary.

5) Tell SDL to load the library at runtime. The last thing is to get the C library loaded from the Java code that really drives the app.  Open up src/org/libsdl/app/SDLActivity.java.  In the SDLActivity class, there’s a static block (line 58 in my copy) that loads the .so files.  Uncomment or add the line:

System.loadLibrary("SDL2_ttf");

Now when ndk-build runs, it should pull in SDL_ttf and pump out the .so.  Then when the .apk is installed and run, the Java code will load the C library for you.  Now you can work with the library just as usual.

If you have anything to add, please let me know in the comments!

Tags: , ,

This is part 2 of my HowTo: SDL on Android series.
(prev) (next)

Working with the Android platform is not so different from desktop platforms.  The biggest design difference is that the main input device is a touch screen.  Android devices can also be rotated to change the screen orientation via a built-in accelerometer.  There are also a few details that arise because we’re running native C or C++ code behind a Java front.  So we’ll have to handle touch events and orientation changes in addition to logging, file I/O, and interfacing with Java.

Touch Input Events

SDL 2.0 has a new member in its event structure for touch events.  We should at this point ignore mouse events (SDL_MOUSEBUTTONDOWN, etc.) and start responding to SDL_FINGERDOWN, SDL_FINGERUP, and SDL_FINGERMOTION event types.  event.tfinger holds the data for all types of touch events.

It works mostly like mouse data, except that the positions (x, y, dx, dy) are normalized to [0.0, 1.0].  You have to multiply them by the window’s width or height to get window coordinates.  This is so the concept of a touch device can be abstracted from the window.  To fully support multitouch, you also have to pay attention to tfinger.touchId (the device ID, not as important) and tfinger.fingerId (an ID for this particular touch).

Orientation Events

In Part 1 of this guide, I briefly mentioned enabling orientation events by making sure to specify in AndroidManifest.xml that your app can handle that kind of configuration change.  Once you have that, SDL pretty much just works how you’d hope.  When your Android device is rotated, your app receives an SDL_WINDOWEVENT_SIZE_CHANGED window event.  Note that window events in SDL2 are special events.  They all have the same event type SDL_WINDOWEVENT, then you have to check the event.window.event member to see which kind of window event it is.  The SDL_WINDOWEVENT_SIZE_CHANGED window event will have the new dimensions of the screen in the event.window.data1 and event.window.data2 members.  You can check what kind of orientation this results in (landscape is wide vs. portrait is tall) by comparing the values of the width and height.

Often, though, you have an app for which it doesn’t make sense to switch between landscape and portrait orientations.  You can lock the orientation with a specification in the AndroidManifest.xml.  In the same ‘activity’ element that has the configChanges attribute, add another attribute:

android:screenOrientation="sensorLandscape"

or

android:screenOrientation="sensorPortait"

These will let the screen flip upside-down if the device is held upside-down, but still lock to the aspect that you choose.  Notice that I use “sensorPortait” here, because for an older version of Android, someone made a typo.

Logging

Android uses a program called logcat to check the contents of the device log.  You can use logcat directly through adb or you can use Eclipse’s logging window.  Normal native apps typically use __android_log_print() or similar functions to print to the log.  This support is pulled from a library, so you would need to include <android/log.h> and link with -llog.  But…  don’t bother.  SDL has already done this for you.  SDL_Log() is a direct replacement for ‘printf’ or ‘cout’.  There are some other functions to help you filter your messages in logcat (check that wiki page).  I also like to wrap SDL_LogMessageV() for more control.

Assets with SDL_RWops

If you haven’t used them before, SDL_RWops are awesome.  They are an abstraction over reading and writing memory and can cover things like file access, in-memory loading, and even network data reading if you’re crazy.  They bring low-level data into your program and if an interface supports SDL_RWops (e.g. SDL_LoadBMP_RW), you can turn that data stream into something immediately useful.

What this means for us in Android may not be obvious right away.  The SDL_RWops creation functions (like SDL_RWFromFile) will first check *within* your APK, in its assets/ directory.  Since thing like SDL_image’s IMG_Load() are built atop of SDL_RWops, this makes them work automatically even though your assets are technically inside a zip file.  Just make sure to keep updated asset files in your project’s assets/ directory.

And if you’re using SDL_RWops directly, use SDL_RWread, SDL_RWwrite, and SDL_RWclose (which frees the SDL_RWops too).  For reference, here’s an example of how to read in all the bytes from an SDL_RWops:

SDL_RWops* rwops = SDL_RWFromFile(filename, "rb");
if(rwops == NULL)
{
    SDL_Log("Could not open file \"%s\".\n", filename);
    return -1;
}
long data_max_size = 100;
unsigned char* data = (unsigned char*)malloc(data_max_size);
long total = 0;
long len = 0;
while((len = SDL_RWread(rwops, data, 1, data_max_size)) > 0)
{
    // Do stuff with your 'len' bytes of data
    total += len;
}
free(data);
SDL_RWclose(rwops);

User Data

If you need to read or write data on the Android device, you can’t (can, but shouldn’t) do it directly in the APK.  It gets messy reading and writing inside a zip file (your APK).  Instead, SDL gives you some native access to the user directory with SDL_AndroidGetInternalStoragePath().  This returns the path to the user data directory for your app.  To specify a file there, append a ‘/’ and the file name.  You can use an SDL_RWops to open the file and you’re set.

Interfacing with Java

Typically, getting two different languages to communicate is verbose, messy, and error-prone.  Java and C are reasonably similar on the surface… but no, this will still be messy.

Java uses JNI (Java Native Interface) to communicate with C or C++.  JNI works both directions.  You can make native calls from Java (Java -> C) and you can make Java calls from the native side (C -> Java).  I, for one, wish it weren’t necessary, but there are some APIs that do not have a native implementation.

The gist of Java -> C is that Java needs to know exactly how to call the desired C function.  That means writing a declaration in Java and writing the called function in a special way in your native code.  The nice thing is that we don’t have to modify SDLActivity.java at all to customize our app’s Java-side behavior.  SDL gives us an “in” by way of inheriting from SDLActivity in our own Java source.  We just have to make sure that we let SDL continue to do what it needs to do.

Here’s my example for my Test1 class if I wanted key down events from the OUYA controller API:

import tv.ouya.console.api.OuyaController;
public class Test1 extends SDLActivity
{
public static native void OuyaControllerKeyDown(int player, int keyCode);  // Our native function declaration
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // Let SDL do its thing
    OuyaController.init(this);  // My turn
}
// I want to catch key events and send them to the native code
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    int keyCode = event.getKeyCode();
    if(event.getAction() == KeyEvent.ACTION_UP && onKeyUp(keyCode, event)) // I'm not including onKeyUp() for brevity
        return true;
    else if(event.getAction() == KeyEvent.ACTION_DOWN && onKeyDown(keyCode, event))
        return true;
    return super.dispatchKeyEvent(event);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    switch(keyCode){
        case OuyaController.BUTTON_O:
        case OuyaController.BUTTON_U:
        case OuyaController.BUTTON_Y:
        case OuyaController.BUTTON_A:
        case OuyaController.BUTTON_L1:
        case OuyaController.BUTTON_R1:
        case OuyaController.BUTTON_L3:
        case OuyaController.BUTTON_R3:
        case OuyaController.BUTTON_MENU:
        case OuyaController.BUTTON_DPAD_UP:
        case OuyaController.BUTTON_DPAD_RIGHT:
        case OuyaController.BUTTON_DPAD_DOWN:
        case OuyaController.BUTTON_DPAD_LEFT:
            if(event.getRepeatCount() == 0)
                OuyaControllerKeyDown(OuyaController.getPlayerNumByDeviceId(event.getDeviceId()), keyCode);  // The native call
            return true;
    }
    return super.onKeyDown(keyCode, event);
}
}

So, I declare my native function as public static native (and don’t use underscores!  You’ll see why soon.) and I make sure to pass control to the superclass by calling its corresponding super.* call whenever I override a method.

Now, the native side:

#ifdef __ANDROID__
#include <jni.h>
extern "C" void Java_com_dinomage_test1_Test1_OuyaControllerKeyDown(JNIEnv* env, jclass cls, jint player, jint keyCode)
{
    __android_log_print(ANDROID_LOG_VERBOSE, "Test1", "nativeOuyaControllerKeyDown(): player=%d, keyCode=%d", player, keyCode);
    // We got data!
}
#endif

C++ is a little naughty with its name-mangling, so declaring a function with C linkage (extern “C”) is pretty common.  Java wants us to do that here so it can find the function to call in our binary (a shared object on Android – that’s like a DLL in Windows).  In C, of course, you don’t need to do that.  Java also wants us to name the function very specifically.  You’ll notice that the underscores separate a uniquely identifying set of tokens.  “com.dinomage.test1” is the package/module name.  “Test1” is the Java class that has the native function declaration.  “OuyaControllerKeyDown” is the function name, finally.

JNI uses some special types in the native code so we can access the data.  Some are simple and obvious, like “jint”.  We can use it just like an integer, because it is one.  Some aren’t so simple.  With “jstring”, we would need to call a special function to extract the C string and then another to free it later.  Java does not store data the same way that either C or C++ do.  See the JNI reference for details.

That’s that for Java -> C.

C -> Java: TODO!

If you have anything to add, please let me know in the comments!

Tags: , ,

We just released our first app for Android (see the News post about that)!  I’m happy about that, but ugh, I feel bad for neglecting Don’t Blow It for so long.  Even so, it needs to wait a little longer.  Android has been where all my programming time has gone lately.  A big part of that work was getting my OpenGL wrapper library, SDL_gpu, further developed and working with OpenGLES.  It’s actually quite nice to use and it covers all of the features I currently need.

It was pretty exciting to get stuff running on my Kindle Fire HD.  I even ported Don’t Blow It to Android just to see how it would go.  It actually turned out great, but I won’t plan on releasing an Android version due to all the extra work it will be to get gamepads working and the game performance tuned and all that.  Maybe there will be an Ouya version eventually.  I’m really not a fan of games being brought to a touch device when the game is not designed for it (e.g. anything with a virtual joystick).  They can still be fun and worthwhile, but input works way better when it feels good and natural.

I did some fishing around for more Android devices to test our app on and I managed to get my mitts on a Samsung Vibrant (Galaxy S).  It was great fun to brick it for a while (sarcasm), then figure out how to get CyanogenMod on it.  In the end, I got a brand new version of Android on a phone that is not bad at all (relative to my sweet Nokia 1100).  It helped to fix a few bugs and now the app is out there for Kindle Fires and other Android devices.  We have already learned something concrete about the app market.  Discoverability stinks.  We will need to do quite a bit of marketing to make any sort of money on this app.

I’ll probably make a game on Android next.  I still have to see what kind of income we can manage when we do it right.

Meet our first Android app, Board Game Apprentice!  You can get it now at Google Play or the Amazon Appstore.

Board Game Apprentice promo image

It’s a simple thing, conceptually.  Board Game Apprentice is a set of 7 tools for helping you play board games.  If you’re missing a timer, dice, or a spinner, you can use a digital one instead (just don’t lose your phone!).  They’re even fun just to mess around with and a great thing to have handy when you need it.

Available for Android 2.3+, Kindle Fire, and Kindle Fire HD

App Includes:
Timer – Digital, hourglass, analog, and chess timers, each can run in the background when other tools are in use
Dice – Traditional pip dice and numbered dice from 4 to 20 sides, custom text and colors, hold tray, roll history
Spinner – Realistic feel with colored or numbered wedges, freespin mode for pointing at a player
Buzzer – Up to 4 buzzers, sound and glow indicate who rings in first
Doodle Pad – Quick sketching and erasing, supports multitouch (kids love it!)
Scoreboard – Auto sums, enter player names, no limit on number of players, undo and redo
Tokens – 4 colors of your choice, divided table, stackable, supports multitouch

Go get it!

en_generic_rgb_wo_60    amazon-apps-store-us-white

We don’t approach mobile apps in the all-too-typical way.  Our apps are more than just microgames.  Board Game Apprentice doesn’t skimp on any of the tools provided, offering way more value than other apps which contain just one or two of these tools.  We also can’t stand advertisements and devious business models.  We hope you do too.

Tags: , ,

This is part 1 of my HowTo: SDL on Android series.
(next)

I’ve been recently wanting to get into mobile development.  How does one do that?

Well, your main options are iOS (iPod, iPhone, or iPad), Windows Phone (7 or 8), BlackBerry (BlackBerry smartphones, PlayBook), and Android (most of the other devices on the market).  I had always leaned toward Android as it’s slightly more open than the others.  Also, we’ve been looking at getting a Kindle Fire HD sometime. So, we finally made the decision and bought a Kindle Fire HD 7″.  It’s a decent tablet, but I want to make games!

My experience and codebase is all based on SDL.  The SDL devs have done a lot of work recently getting the new version of SDL working nicely on mobile platforms.  I had barely messed with SDL 2.0 before this, so I really had to jump all in. This will be a work-in-progress tutorial-style post as I document the path I take to get started and get my existing code ported.  Read the rest of this entry »

I guess I should have shared this a long time ago, but better late than never!

Don’t Blow It was included in a PBS Off Book feature about indie game development.  Our presence at Boston FIG is the reason for this happening (you can see some other BFIG entries alongside us).  It’s pretty cool to be informally recognized as “indie enough”, or at least Cassie’s art gave people that impression. 😉

We’re at 0:43, right after that heartwarming holiday photo of Team Meat.

Here’s a quick look at one of the new possibilities in the future of Don’t Blow It.

What you see here is the work-in-progress of creating structures in-game: Building.  The new feature, which is pretty unusual for a platformer, lets you join certain “buildable” objects together.  This lets you solve many puzzles and obstacles with tremendous freedom (and lets us design some pretty awesome puzzles for you to solve).

Read the rest of this entry »

We’re still working on the new design for Don’t Blow It, so there will be lots to talk about soon.  For now, I’ve thrown together a video that shows what the Boston FIG version is like.  I hope you like it!

19
Oct

Spriter API for C++

   Posted by: in Dev

If I ever have a wish for making video games, it’s to do it faster and better. That’s why I spend a lot of time on tools. I don’t really like doing tool work, but it is important to developing an efficient workflow. This time, that tool is a C++ API for loading and using the Spriter character animation format, SCML.

Spriter is an animation creation application.  You drop images into the editor which will be put together to make your character.  Then you can set keyframes as you move the images around.  With this style of animation, the movement of the character is interpolated from these keyframes to give a smooth, continuous animation at any playback speed.  The animations are saved in a special XML format, named SCML.  Spriter had a very successful Kickstarter campaign this year, so it is in active development.  However, that is specifically for the editor itself and the data format.  The “plugins” that allow you to use the animations in various game engines and programming languages are community-driven.

Read the rest of this entry »

Tags: , , ,

5
Oct

Our new website

   Posted by: in News

Welcome to the new site!  We’re excited to have a home dedicated to our game development.

We’re still working on things back here, but since it’s mostly functional, it is worth exposing to you!

Keep an eye on this blog for official updates from DinoMage Games!