Click here to Skip to main content
14,659,323 members
Articles » Mobile Development » Android » General
Posted 31 Oct 2012

Tagged as


47 bookmarked


Rate this:
4.93 (21 votes)
Please Sign up or sign in to vote.
4.93 (21 votes)
31 Oct 2012Apache
R.O.O.T.S is a real-time strategy game similar to games like Galcon, Eufloria, Tentacle Wars.


I want to introduce full source code of cross-platform game and hope it will be interesting someone. I think it is simple way to support many different platforms. Currently the game works perfectly on Android and Windows. I am going to support some other platforms in the future.

Image 1


R.O.O.T.S is a real-time strategy game. Similar to games like Galcon, Eufloria, Tentacle Wars, but this game has a lot of different gameplay.


  • It doesn't use any special game engine, only several open-source libraries
  • Visualization based on OpenGL ES 2.0
  • All textures are generated
  • Real-time generation of noise texture on GPU
  • Multipass rendering with Gauss blur
  • Unique form of a each tree based on fractal algorithm
  • AI based on negamax algorithm
  • Class for rendering of font on OpenGL with unicode support
  • Direct loading game data from APK file, including streaming music

Technical Information

There are some interesting solutions in the source code.

Load fonts, shaders, sounds and level data

You can load the game data from a APK file directly. It provides to conserve space on disk or sd-card. The APK is a ordinal ZIP file.

First you need to receive the full file path to your APK file in Java code:

String apkFilePath = null;
ApplicationInfo appInfo = null;
PackageManager packMgmr = context.getPackageManager();
try {
    appInfo = packMgmr.getApplicationInfo(getClass().getPackage().getName(), 0);
} catch (NameNotFoundException e) {
    throw new RuntimeException("Unable to locate assets, aborting...");
apkFilePath = appInfo.sourceDir;

There is invocation of native method init(apkFilePath); Second, use the libzip to open zip file and load some data in C++ code. It is implemented in the class ResourceManager:

ResourceManager::ResourceManager(const char *apkFilename): archive(0) {
    archive = zip_open(apkFilename, 0, NULL);
    if(archive) {
        int numFiles = zip_get_num_files(archive);
        for (int i=0; i<numFiles; i++) {
            const char* name = zip_get_name(archive, i, 0);
            if (name == NULL) {
                LOGE("Error reading zip file name at index %i : %s", zip_strerror(APKArchive));

ResourceManager::file ResourceManager::open(const char *filename) {
    zip_file *zfile = zip_fopen(archive, filename, 0);
    return file(filename, zfile);

unsigned int ResourceManager::file::read(void *buf, unsigned int size) {
        return 0;
    ssize_t rs = zip_fread(zfile, buf, size);
    return rs&gt0 ? rs : 0;

You can also read the file data like a stream, this technique used in the MusicPlayer for example. On other platforms you can simple collect all game resources into one ZIP file.

Rendering Planets

It uses a deformation in GLSL fragment shader to make illusion of volumetric spherical object. At the beginning it generate the texture:

void Render::generatePlanetTexture(int size) {
    std::vector<unsigned char> buffer(size*size*4);
    memset(&buffer[0], 0, buffer.size());
    int size2 = size/2;
    int cidx = size2*size+size2;
    for(int y=0; y<size2; ++y)
        for(int x=0; x<size2; ++x) {
            float d = std::min(sqrtf(float(x*x+y*y)) / size2, 1.0f);
            int idx0 = cidx+y*size+x;
            int idx1 = cidx-1+y*size-x;
            int idx2 = cidx-size-y*size+x;
            int idx3 = cidx-size-1-y*size-x;
            float xx = float(x+0.5f)/size;
            float yy = float(y+0.5f)/size;
            if(d<1.0f && d>0.0f) {
                float w = (1.0f-cosf(d*PI_2))/d;
            buffer[idx0*4] = buffer[idx2*4] = (unsigned char)((0.5f+xx)*255.0f);
            buffer[idx1*4] = buffer[idx3*4] = (unsigned char)((0.5f-xx)*255.0f);
            buffer[idx0*4+1] = buffer[idx1*4+1] = (unsigned char)((0.5f+yy)*255.0f);
            buffer[idx2*4+1] = buffer[idx3*4+1] = (unsigned char)((0.5f-yy)*255.0f);

            unsigned char c = (unsigned char)(d*d*d*d*d * 255.0f);
            buffer[idx0*4+2] = buffer[idx1*4+2] = buffer[idx2*4+2] = buffer[idx3*4+2] = c;


    planetTexture.init(&buffer[0], size, size, 4);

The x, y coordinates contain offset of target texture coordinates. The z-coordinate simulate the atmospheric density. There is example to use this texture in fragment shader:

void main(void) {
    vec4 p = texture2D(tex0, texcoord1);
    gl_FragColor = texture2D(tex0, p.xy*0.5);

The tex0 is our generated texture with deformation coordinates and tex1 is the surface texture. In the game for the tex1 used generated noise texture and the shader look like that:

void main(void) {
    vec4 p = texture2D(tex0, texcoord1 );

    float r = max(texture2D(tex1, p.xy*0.5+vec2(fract(index*23.0)*0.5, fract(index*7.0)*0.5)  ).x - 0.5, 0.0);
    float g = max(texture2D(tex1, p.xy*0.5+vec2(fract(index*17.0)*0.5, fract(index*13.0)*0.5) ).x - 0.5, 0.0);
    float b = max(texture2D(tex1, p.xy*0.5+vec2(fract(index*3.0)*0.5,  fract(index*29.0)*0.5) ).x - 0.5, 0.0);
    vec3 c = vec3(r, g, b)*0.7*(1.0-p.z) + vec3(p.z*0.25, p.z*0.25, p.z)*0.5;

    gl_FragColor = vec4(c, 1.0);

AI Algorithm

For AI use a Negamax modified algorithm for number of players two or more. Each computer player has their own independent AI. It makes a "shot" of the current game situation and then searchs for the best move. After that the loop is repeated.

All Mind objects work in the one separate background thread.

float Mind::alphaBeta(int pIdx, int depth, float alpha, float beta) {
    if(state == ST_ABORT)
        return -F_INFINITY;

        return -F_INFINITY;

    if(depth == 0)
        return evaluate(pIdx);

    std::vector<Mind::Move moves;
    calcMoves(pIdx, moves);

    float score = -F_INFINITY;

    for(unsigned i = 0; i < moves.size(); ++i) {
        makeMove(pIdx, moves[i]);

        for(size_t p = 0; p < genuses.size(); ++p) {
            if(p != pIdx && !isLooser(p)) {
                float eval = -alphaBeta(p, depth-1, -beta, -alpha);
                if(eval > score) {
                    score = eval;
                    if(score > alpha) {
                        alpha = score;
                        if(alpha >= beta) {
                            return alpha;
        if(state == ST_ABORT)
            return score;

    return score;

Run Game on Android x86 Emulator

Unfortunately the Intel Hardware Accelerated Execution Manager (HAEM) doesn't work on Linux system.

Image 2

However the good news, the game works perfectly on emulator without the HAEM.

Image 3


This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0


About the Author

Alex Saenko
Russian Federation Russian Federation
No Biography provided

Comments and Discussions

QuestionR.O.O.T.S Running on the pc android for x86 4.4 Pin
Dean-Ding8-Jun-14 23:42
MemberDean-Ding8-Jun-14 23:42 
GeneralMy vote of 5 Pin
whar28-Apr-13 23:44
Memberwhar28-Apr-13 23:44 
GeneralMy vote of 5 Pin
Kochise21-Apr-13 4:48
MemberKochise21-Apr-13 4:48 
GeneralMy vote of 5 Pin
Ștefan-Mihai MOGA18-Nov-12 7:35
professionalȘtefan-Mihai MOGA18-Nov-12 7:35 
GeneralMy vote of 5 Pin
yuske12-Nov-12 6:40
Memberyuske12-Nov-12 6:40 
GeneralMy vote of 5 Pin
pip0109-Nov-12 5:18
Memberpip0109-Nov-12 5:18 
GeneralMy vote of 5 Pin
gndnet7-Nov-12 7:28
Membergndnet7-Nov-12 7:28 
QuestionFound in the Google Play Pin
Jasmine25015-Nov-12 9:54
MemberJasmine25015-Nov-12 9:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.