Setting up Cocos2d-x 3.0beta2 for Android on Windows and Ant build

Objectives

  • Install everything needed to build and run Cocos2d-X 3.x beta samples on an Android 4.3 device
  • Uses only the command line, (NOT using eclipse at all).

Prerequisites

  • Some game programming knowledge
  • Windows 7 PC
  • Android device with Android 4.3 (if not, either use the emulator or download the necessary SDKs and modify the tutorial as necessary)

Download

Note: Python 3.x is not supported by the python script files in Cocos2d-x 3.x (at the time of writing)

Installation

  • Extract Android SDK bundle to somewhere (without spaces in the path), e.g. D:\
  • Extract or install the rest of the downloads into the Android SDK folder, e.g. D:\AndroidDevelopmentKit, so it should now contain these:
  • In a text editor, create the following setup_cocos_env.bat, and save it into D:\AndroidDevelopmentKit
set NDK_ROOT=D:\AndroidDevelopmentKit\android-ndk-r9c\
set path=D:\AndroidDevelopmentKit\Portable_Python_2.7.5.1\App;D:\AndroidDevelopmentKit\Java\jdk1.7.0_45\jre\bin;D:\AndroidDevelopmentKit\apache-ant-1.9.3\bin;D:\AndroidDevelopmentKit\sdk\tools;D:\AndroidDevelopmentKit\sdk\platform-tools;%path%
set JAVA_HOME=D:\AndroidDevelopmentKit\jdk1.7.0_45
cd cocos2d-x-3.0beta2
cmd
  • This sets up the various paths necessary for building the Cocos2d-X samples.
  • Building and installing the samples
  • Double-click on this batch file. It will open a command prompt in the Cocos2d-X folder.
  • Run the following commands to see if the paths are set up correctly (simply type those commands in without additional parameters, and without changing directory)
    • android
    • adb
    • ant
    • python
  • If any of these fail, check your paths
  • If ok, go on to build the samples
cd build
python android-build.py all (This will take a while)
  • Go to build the java files needed for creating the apks.
cd cocos\2d\platform\android\java
android update project -p . -t android-18 (assuming you have a device with Android 4.3)
ant debug
ant release (so that we won’t need to do it again)
  • Go to every project folder and do the following (using HelloCpp as example):
cd ..\..\..\..\..\samples\Cpp\HelloCpp\proj.android
android update project -p . -t android-18
ant debug install
  • It will be installed on your device.
  • Run the samples!

Eclipse Notes

  • I’ve not covered how to set it up with Eclipse because that wasn’t my focus.
  • I’ve quickly tried, and it doesn’t package the apk with the libs, but didn’t investigate further. Another time perhaps. 🙂

Takeaways from GDC Taipei Summit 2013

I was at Game Developers Conference (GDC) Taipei Summit 2013 recently and made some notes from attending various lectures and meetings there. Maybe it would be interesting to some other people as well, so I thought I’d write them down here. Its more focused on the regional gaming situation then technical topics.

Feel free to drop in the comments anything I might have left out, or you might be interested to know.

Taiwan

  1. Taiwan has a population of 23 million, half of which play games.
  2. Most popular type of games are RPG/MMORPG and card battle games.
  3. Mobile devices: iOS 25%, Android 45%. Android monetise better than iOS as well, and publishers will ask for Android version of mobile games.
  4. One publisher mentioned that for RPGs, their main customers are working males, and there’s always a revenue spike for their in-app purchases on payday.

Hong Kong & Taiwan

  1. One speaker mentioned that games made for Taiwanese audiences will work just as well for Hong Kong audiences.
  2. Facebook games are popular in both Taiwan and Hong Kong, unlike China, where its unavailable.
  3. Mainland Chinese game publishers are increasingly interested in expanding into Taiwan and Hong Kong, both by bringing mainland chinese games over and vice versa. Some are also interested in partnering with companies in this region for development and publishing. The reverse is also true, that developers and publishers from this regions are also interested in expanding into mainland China.

China

  1. Biggest publisher in China is Tencent, due to its massive userbase from its QQ messenger. They publish games for all platforms, and provide many services for developers, such as QQ cloud.
  2. Tencent is so dominant such that there is a saying: there’re 2 universe in China, one with Tencent, and one without.
  3. China Mobile Games and Entertainment Group (CMGE) is the next largest mobile game publisher. But according to them, there are at least 3 Tencent games that each have more revenue than their total revenue combined.
  4. There’s no Android Google Play store in China, but numerous other Android stores.
  5. Most popular games in China are also RPG/MMORPG. Some publishers also bring in Western games with some successes, e.g. Angry Birds or Fruit Ninja. Games based on the Chinese classical stories of Three Kingdom and Journey to the West are oversaturated, but there is still lots of interest in games based on them.

Messaging Apps

  1. From what I heard, and what I observed on people’s phone, the most popular instant messaging apps by countries are
  2. China: WeChat (Note the dominance of Tencent yet again)
  3. Taiwan: Line and KakaoTalk
  4. Hong Kong: Whatsapp
  5. This would be relevant to developers trying to target games on these platforms

Game Engines

  1. Cocos2D-x is a widely used game engine in the region, funded by Chukong Technologies. However, 2 speakers (Ying Shuling of CMGE and Ralph Barbagallo of FLARB LLC) are of the opinion that Unity is the way forward.

The case of the teleported static lib functions

This bug came back to bite my teammates today even though I resolved it some time ago. Because its quite an interesting bug, I felt resolved to write it down. There is this particular well known middleware library that we use, and it came in a few modules which are packaged as static libs each. Let’s just call 2 of them modules Fundamental and Extras, because one provides some fundamental functionalities, and the other, extra and optional (to some people) functionalities. The latter has a dependency on the former. There are 2 Visual Studio (VS) solutions, one with just module Fundamental, and the other with both modules, each in their own VS project. (So, Fundamental.sln has Fundamental.vcxproj, while Extras.sln has both Fundamental.vcxproj and Extras.vcxproj)

On one particular platform, we added a slight modification (2 new initialisation functions) to module Fundamental, and none to module Extras. Then we compiled the module Fundamental from its standalone solution, link them to our code, without any warnings or errors. All is good. Then one day, we were forced to upgrade to a newer version of this middleware due to some technical requirements. So we applied the same changes, build everything fine, and run the project. Bam, it crashed after the module initialisation, with some nonsensical pointer values, which, obviously means our initialisation code isn’t working. But because the crash happens after the init function returns, and not in the init function itself, we can’t tell what’s wrong straight away. I can’t remember what happened when I step through the init function, other than the fact that it all seems fine.

Tried switching back to using the default init code, and all is well. We went through the usual steps of proofreading the code, check the documentation and change log, etc, and it all seems fine. Then we tried to apply our changes step by step. First, we copied the default init function initSDK() exactly to our customInitSDK(). Bam! Crash again. What?! Its byte for byte the exact same code as the working default one. Tried all kinds of funny things after that, for example, we renamed the function to something else, but yet still called it with customInitSDK, and the program could still link to the lib! Eventually, we guessed that the customInitSDK() wasn’t being linked to correctly. But why?

So I open up the compiler and linker documentation, and look through all the options available, and eventually settled on enabling the writing of linker map, which means the linker will report which object files the symbols are linked from. That confirms that our customInitSDK() wasn’t being linked to, even though I checked that it is in the static lib. Tried many other things, and in the end, I found that it finally worked when I compile both modules Fundamental and Extras using the VS solution with both modules. And what does the linker map says? It says that all the functions in the Fundamental module appeared inside the Extras module, and everything is being linked from the Extras’ static lib! What the?! Anyway, we left it as that since it works fine, We only knew what had happened, but not why it happened this way.

But this bug came back today because we were working in another branch, and we had not rebuilt the two modules’ static libs in this branch. And the poor guys working on it wasted quite a few hours trying to figure out what’s happening. They thought they had done everything correctly, and I had forgotten about this bug after so many months. It was only after they came and discussed with me for a while then I suddenly recalled it.

Takeaway #1 – The many compiler and linker options can be useful to help track down some errors.
Takeaway #2, and this is important – When any bug is resolved, especially strange ones like this, do document the cause and solution properly, and put it in a place where the next soul working on it has a chance of seeing it!

Adding Google Maps into Mobile Atlas Creator

Mobile Atlas Creator is an awesome tool for generating offline maps for mapping applications, such as the equally awesome RMaps for Android. Unfortunately, due to restrictions from many map providers, Mobile Atlas Creator no longer provides access to many map sources.

However, it is able to read user-customised map sources. So with the help of httpfox, I have managed to get google maps hooked up again. Just unzip the following files into the “mapsources” subdirectory of your Mobile Atlas Creator installation location, and then restart it.

Enjoy!

Google Maps (google_map)

<?xml version="1.0" encoding="UTF-8"?>
<customMapSource>
    <name>Google Maps</name>
    <minZoom>0</minZoom>
    <maxZoom>19</maxZoom>
    <tileType>png</tileType>
    <tileUpdate>None</tileUpdate>
    <serverParts>0 1 2 3</serverParts>
    <url>http://mt{$serverpart}.google.com/vt/lyrs=m@144&amp;hl={$lang};&amp;x={$x}&amp;y={$y}&amp;z={$z}</url>
    <backgroundColor>#000000</backgroundColor>
</customMapSource>

Google Satellite (google_satellite)

<?xml version="1.0" encoding="UTF-8"?>
<customMapSource>
    <name>Google Satellite</name>
    <minZoom>0</minZoom>
    <maxZoom>19</maxZoom>
    <tileType>PNG</tileType>
    <tileUpdate>None</tileUpdate>
    <serverParts>0 1 2 3</serverParts>
    <url>http://khm{$serverpart}.google.com/kh/v=138&amp;x={$x}&amp;y={$y}&amp;z={$z}</url>
    <backgroundColor>#000000</backgroundColor>
</customMapSource>

Google Satellite + Overlay Hybrid (google_satellite_hybrid)

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customMultiLayerMapSource>
    <name>Google Satellite Hybrid</name>
    <tileType>PNG</tileType>
    <layers>
        <customMapSource>
            <name>Google Earth</name>
            <minZoom>0</minZoom>
            <maxZoom>19</maxZoom>
            <tileType>PNG</tileType>
            <tileUpdate>None</tileUpdate>
            <serverParts>0 1 2 3</serverParts>
            <url>http://khm{$serverpart}.google.com/kh/v=138&amp;x={$x}&amp;y={$y}&amp;z={$z}</url>
            <backgroundColor>#000000</backgroundColor>
        </customMapSource>
        <customMapSource>
            <name>Google Earth Maps Overlay</name>
            <minZoom>0</minZoom>
            <maxZoom>19</maxZoom>
            <tileType>png</tileType>
            <tileUpdate>None</tileUpdate>
            <serverParts>0 1 2 3</serverParts>
            <url>http://mt{$serverpart}.google.com/vt/lyrs=h@145&amp;hl={$lang}&amp;x={$x}&amp;y={$y}&amp;z={$z}</url>
        </customMapSource>
    </layers>
</customMultiLayerMapSource>

Google Terrain (google_terrain)

<?xml version="1.0" encoding="UTF-8"?>
<customMapSource>
    <name>Google Terrain</name>
    <minZoom>0</minZoom>
    <maxZoom>19</maxZoom>
    <tileType>png</tileType>
    <tileUpdate>None</tileUpdate>
    <serverParts>0 1 2 3</serverParts>
    <url>http://mt{$serverpart}.google.com/vt/lyrs=t,r&amp;hl={$lang}&amp;x={$x}&amp;y={$y}&amp;z={$z}</url>
    <backgroundColor>#000000</backgroundColor>
</customMapSource>

If you look at the url in the files, you can see that all the map tiles are downloaded from 1 google server mt0, when in google maps, tiles are downloaded from mt1 as well for load distribution. I don’t know if Mobile Atlas Creator supports this or not.

If I ever get to figure out how Bing or Yahoo map tiles are named, then I’ll probably post about them. But it is likely I won’t get to that 😛

Edit (10 Apr 2012):
This forum topic, post #6 suggests to copy the map source files over from an older version:
http://www.noeman.org/gsm/creating-maps/201179-mobile-atlas-creator.html
Yahoo & Google maps seems to work for me as well, while Microsoft/Bing maps didn’t. Didn’t test with other map sources.

Edit (7 Oct 2013)
Tested and updated the urls. They should now work again, but requires MOBAC 1.9 Beta 7 or newer, as it uses for parallel downloads from google servers.

Directly deleting files in OS X

In OS X, I’m so not used to having to send files to Trash first before emptying it, just to get rid of files I no longer want. In the end, I created an Automator service that does the job for me.

(File download at the bottom of this post)

How To Use

1. Select the files to delete, and right-click:

 

 

 

 

 

 

2. Confirmation Prompt:

 

 

Simple as that.

How It Is Done

Here is how it is done in Automator:

The guid in the text box of the “Ask for Confirmation” step is a hack to insert the file names into the prompt dialog (step 2 above). It is the guid of the variable “Files” in “Set Value of Variable”, obtained by opening the document.wflow file of this Automator service in a text editor and searching for it there. It is unfortunate that Automator doesn’t support variables in the text of the confirmation dialog.

So if the user clicks “Yes” to the dialog, the shell script will do our favourite rm -r on each file. Why “-r”? Because the file could be a folder too, which we delete -recursively.

Download and Install

The Automator Service bundle can be downloaded here: delete_Files_Mac.zip It is just a bunch of xml in a Mac bundle which you can freely examine in Automator or any text editor.

I don’t know if any install step is needed.

  • Unzip it and copy the app bundle to /Users/YourUserHome/Library/Services.
  • Try right-clicking on any unwanted files in Finder, and see if the “Delete File(s)” option appears at the bottom of the context menu.
  • If not, maybe try to open and save it via Automator and try again.

2 API differences between iOS and Android

These are just 2 differences that I’ve encountered recently, and I’m sure there’ll be more to come. Points to note when doing cross-platform coding.

Signed-ness of char type

char type is signed in iOS, but unsigned in Android NDK. For the latter, I’ve just discovered this post, which suggests that its an ARM code generation behaviour for gcc that can be handled by passing LOCAL_CFLAGS := -fsigned-char. I will give this a try.

Accelerometer reading values

iOS returns accelerometer readings in units of g, while Android returns in ms^-2. So for a device lying screen up on the table, iOS reports z = -1, while Android reports z = -9.81

Android also has a constant defined for the gravitational constant of Death Star.

Debugging release mode code with __asm int 3

Sometimes we have to run release mode code, either because it is what we’re testing, or it just takes too long to run the program in debug mode (I had one level which took > 15 mins to load up in debug mode, and that’s without the debugger attached!). While solving bugs in this case, I would sometimes like to break the process when some invalid situation occurs. I do this way:

if ( _isnan( someNumber )
{
    __asm int 3    // semi-colon not necessary
}

int 3 is a software interrupt that, in this example, gets triggered when someNumber is invalid, which means most likely the latter is an uninitialised variable. This is quite useful when logging to output is not an option.

Notes:

  • This is definitely not cross-platform
  • DebugBreak() and __debugbreak() should do the same thing, but its more l337 to use asm when debugging 😛

Actionscript TransitionManager Class

Actionscript 3 has a rather useful TransitionManager class to provide transition effects to movie clips. It provides a convenient function static TransitionManager.start() that we can use for adding effects (e.g. blinds, fly, zoom, etc). Whats missing from the documentation though is that the class that the effect is being applied on must be declared a dynamic class. This is something to note if you’re using it on a custom MovieClip sub-class. The MovieClip class itself is dynamic, so its not a problem. Doesn’t apply as well if you are using the instanced method startTransition(. . .).

Another useful thing to note is that the Transition class provides events for when the transition is completed, those being “transitionInDone” and “transitionOutDone”, depending on the transition direction. This is shown in the documentation example. It is unusual though that, unlike other events, they do not provide a static constant for these events, and we have to quote them as literal strings.

My renderer is cross-platform!

I’ve finally gotten my OpenGL ES code to cross compile and run on both iOS and Android. Have learned lots of things in the process. It’s still an extremely primitive “spinning cube” code, so there’s still heaps more work to be done, but at least most of it should be platform-neutral.

iOS (left), Android (right)

Its quite obvious from the screenshots that the lighting is different on both of them. Still have to figure that out too.

Back to work!