Project page

Chessmind 3D, a 3D chess game for Android


New project on Android : a chess game.


Available on Android Market:
https://market.android.com/details?id=org.nicolasmy.chessmind3d

There's not so many chess game on Android, so I decided that it would be a good idea to make one. I also planned this program to be ad supported for a try.

Actually the hardest in chess program is off course, the artificial intelligence. I've worked a bit on the subject when I was at university, I've even written a program that I might reuse, but for a real challenging AI, I have no choice but to use some third party AI.
There are 2 open-source AI that I know : GNU Chess and Crafty, very good AI at least for my level ! There is licence issue in using open-source component in a commercial product that I shall workout.

For this project I'm aiming at achieving very good user experience, fancy menus, nice graphics, chess is a compact game so let's add some polish for a change =)

Devlog

20/11/2011
I've started to work on this project yesterday and I've already achieved some nice things : I've reused my Java 3D engine that I've started on Speedroid3D.
3D engine is designed for code reusability, but it also add some complexity, as it's supposed to be all purpose, ending up filling tons of structure just for displaying very simple things, or wondering how things works in some part of the engine (that I've written myself !).
Another nice things that I've just worked out : pixel perfect picking of 3d objects in scene. I'm using detection by color and glReadPixels to read from the framebuffer (actually I should use an off-screen buffer for the job to avoid artifact). I was stuck for moment before I realised that I wasn't in 32bpp and that's why colors that I've assigned to pickable objects weren't the one read from the framebuffer.

21/11/2011
I'm starting a new opengl gui project, tough work but I hope to capitalize for the future.
This time I'll try to stick to the factory design pattern.
ComponentLoader->ComponentFactory->TableLayoutFactory->ButtonFactory

23/11/2011
I've finished the code that parse data to a structure for the followings:
- TableLayout
- Button
- Image
- Paragraph
I have a simple hierarchy widget:
TableLayout contains 'Buttons' that contains 'Image' and 'Paragraph' (text).
Now that the content is fetch into data structure, the big thing is to create the graphical rendering of these data.
It tooks me about 2 days of 4 hours work....after work just to implement this parsing, coding is indeed a time consuming task. I really hope this boring coding will help with greater productivity in the future.

It's in fact possible to add buttons on top of an OpenGL surface on Android
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/SurfaceViewOverlay.html
But implementing my own gui provides more flexibility, for instance with 3d widgets.
It's perfectly sufficient for my chess game. I'll put my gui code to the side.

24/11/2011
I have to distinct aspect that I have to work on:
- IA, I didn't find any open-source project that allows for commercial use (and is good enough in term of speed and memory footprint) since I have a certain work ethic not to violate licensing term, I will build an IA from own my former work.
- User interface, I really want my interface to be good looking, smooth, simple, user-friendly with multi-touch gesture support.
One thing that should be aware off is not to rush things, I'd like to get the software out quickly and maybe make some money but here are my moto (I've invested so much time and energy in these project that I tend to look for a greater reward, I just have to stay focus and I hope things will pay in the end)
1. Take the time to get things done correctly.(but not overdone!)
2. Don't be too concerned about what others people do, focus on the task right in front of me.
3. It's just a small software to get things started, not necessarily the killer app, I'll still put my best into it.

High level gesture detection on Android
 
abstract boolean     onDown(MotionEvent e)
Notified when a tap occurs with the down MotionEvent that triggered it.
abstract boolean     onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
Notified of a fling event when it occurs with the initial on down MotionEvent and the matching up MotionEvent.
abstract void     onLongPress(MotionEvent e)
Notified when a long press occurs with the initial on down MotionEvent that trigged it.
abstract boolean     onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
Notified when a scroll occurs with the initial on down MotionEvent and the current move MotionEvent.
abstract void     onShowPress(MotionEvent e)
The user has performed a down MotionEvent and not performed a move or up yet.
abstract boolean     onSingleTapUp(MotionEvent e)
Notified when a tap occurs with the up MotionEvent that triggered it.
 

But nothing that really suits my need :
-2 fingers pinch zoom
-2 fingers rotate

28/11/2011
I haven't been working on this project today, too much procrastination...(and other things to do :( ), but I've finally found a suitable chess IA : Chenard chess engine which is public domain. I don't really care about the level of play but it has to be compact in memory and in computation time.
Now things are getting a bit complicate: three threads will be running concurrently :
1. Android UI thread (sends the events)
2. OpenGL game thread (render)
3. Chess IA (in C++ through JNI) thread
=> events will have to come from the UI down to the Chess engine.

30/11/2011
I've figured out to call my Java methods from C++ (which is itself called from a Java thread)

 
public class ChessThread extends Thread{
 
    public static Thread singleton;
    // Load the .so
static {
System.loadLibrary("main");
}    
 
// C functions we call
public static native int nativeStart();
public static native void nativeQuit();
 
    public void run()
    {
        nativeStart();
    }
 
    public static void getUserMove(int[] srcdest)
    {
 
    }
 
    public static int getPlayerWhiteType()
    {
        return 0;
    }
 
    public static int getPlayerBlackType()
    {
        return 0;
    }    
 
    public static int getMaxSearchTime()
    {
        int time = 0;
        return time;
    }
 
    public static void startChessThread()
    {
        if (singleton == null)
        {
            ChessThread mythread = new ChessThread();
            Thread singleton = new Thread(mythread);
            singleton.start();
        }
 
    }
}
 


C++ calling code
 
static JNIEnv* mEnv = NULL;
 
// Main activity
static jclass mChessThreadClass;
 
// method signatures
static jmethodID midGetUserMove;
static jmethodID midGetPlayerWhiteType;
static jmethodID midGetPlayerBlackType;
static jmethodID midGetMaxSearchTime;
 
// Library init
extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
return JNI_VERSION_1_4;
}
 
extern "C" void android_Init(JNIEnv* env, jclass cls)
{
mEnv = env;
mChessThreadClass = env->FindClass("org.nicolasmy.chessmind3d.ChessThread");
if (mChessThreadClass == 0)
    LOGD("[ChessMind3D]android_Init() - Warning couldn't find class 'ChessThread'");
midGetUserMove = mEnv->GetStaticMethodID(mChessThreadClass,"getUserMove","([I)V");
if (midGetUserMove == 0)
    LOGD("[ChessMind3D]android_Init() - Warning couldn't find method 'getUserMove()'");
midGetPlayerWhiteType = mEnv->GetStaticMethodID(mChessThreadClass,"getPlayerWhiteType","()I");
if (midGetPlayerWhiteType == 0)
    LOGD("[ChessMind3D]android_Init() - Warning couldn't find method 'getPlayerWhiteType()'");
midGetPlayerBlackType = mEnv->GetStaticMethodID(mChessThreadClass,"getPlayerBlackType","()I");
if (midGetPlayerBlackType == 0)
    LOGD("[ChessMind3D]android_Init() - Warning couldn't find method 'getPlayerBlackType()'");
midGetMaxSearchTime = mEnv->GetStaticMethodID(mChessThreadClass,"getMaxSearchTime","()I");
if (midGetMaxSearchTime == 0)
    LOGD("[ChessMind3D]android_Init() - Warning couldn't find method 'getMaxSearchTime()'");
}
 


01/12/2011
I have the IA playing and me making my moves by picking the square. Everything is put up in place little by little...
I still have trouble making my program interact with Android properly, Android killing my apps suddently, or the game crashing on rotation.

07/02/2012
More than two months after my last message, I've continuing this project.
I've fixed a few bugs :
- Camera
- Lighting calculation : very strange bug, hardware fixed lighting seems broken on the Tegra2 but was working on my Galaxy S phone. I really doubt that one could have release such a non working feature.
- Chess engine castle
- Chess engine capture
The game rules now seems fully fledged except : pawn promotion and en-passant.

The AI is still very strong for me.

I will now focus my work into delivering a smooth experience:
- Working suspend and resume
- Nice icons and button (stock android 2.3 is plain ugly, besides it's a 3d game so mixing 2d android buttons with a 3d game gives some awkward look)

To create a custom buttons, I've found this interesting page:
http://blog.androgames.net/40/custom-button-style-and-theme/

Principle for detecting pinch rotate and pinch zoom:
- The two motion are very similar but not compatible, ie: one can make a zoom or rotate the board but not both at the same time.
- The motion cannot be detected globally, one has to determine right between to finger motion event whether the gesture is a rotation or a zoom.
- Fingers are not that precise and a user might well closing in his two finger while attempting to mimic the rotate gesture.
=> I think that the first detection attempt should consider whether two fingers seems to rotate beyond a certain threshold which would be then a rotation.

08/02/2012
- Rotate gesture implemented but still some work has to be done to handle both pinch and rotate
- Fixed a bug that I had purposely created:
The piece picking is done "by color" => elements to pick are rendered with a particular color, then I read the pixel underneath the finger to know what the user selecting.
Problem is that I renderer the picking scene in the screen's framebuffer, causing a noticable blinking, but that was easier for me to implement and debug.
Now:
1) I create an offscreen pixel buffer
2) Make it the actual rendering target
3) Render the picking objects and compute the picking
4) Restore the original state
=> no more blinking.
=> and still fully compatible with OpenGL ES 1.0

I'm expecting to hit the market with this app by sunday, that is in 4 days. I will have to fix issue:
- add the evil admob stuff !
- add pawn promotion menu
- add shadow to the scene using shadow volume
- speed up loading time and lower hardware requirement.
- make some sexy banners and ads to make people download my app

The goals for this version are very clear to me:
- Minimal but working features
- Smooth UI / fast load time => to make people willing to use my app on regular basis

10/02/2012
- Admob added
- Working on Shadow Volumes

12/02/2012
- Shadow volumes done
- polishing things:
- I have the game to be tiltable on the fly : the game handle being switch from landscape to portrait and still continue fonctionning while all the graphical elements are set to their new place.
- Adding skybox and other textures

It's starting to look pretty bad ass !


- Fixed a dozen of bugs.
- Generated data are now cached to file to speed up loading time
- It works incredibly smoothly, stop / resume, switch from portrait to ldanscape and vice-versa withought hicups.

Critical missing features :
- start a new game
- pawn promotion (detection and menu)
Come on !

Ooops I just happens to see that the Samsung Galaxy S has no stencil buffer support ! Which means that a lot a entry level android phone won't either :(
I didn't want to make the mistake I've made before by targetting too high end devices, but it seems that yet again I've made that mistake.

13/02/2012
- start new game is working, with a ugly memory leaks but still no pawn promotion.
- Icon is ready, I will enforce my deadline and release it.

This time for the promotion, I'm not faking it, this not an open source project, not a 1 night project, it's serious : banner, icons, catchy text description everything that has to be done to make people download my app.

Good and bad of Chessmind3D:

Good:
* Good looking
* Solid IA
* Smooth interaction with Android (pause/resume and portrait/landscape tilt)

Bad:
* Too hardware demanding (Stencil Buffer is not available on many device, plus its slow)
* Impossible to play on small screen device (that is not a tablet)
* Lack of user feedback (who's turn is it, check, mate)
* Lack of animation
* No pawn promotion (arg!)
* No takeback/undo move

Btw I'm thinking about trying to release my app on the Amazon Appstore since, Chessmind3D should be well suited for the Kindle Fire.

I'm exhausted having worked until 4AM last night.
Still I need to fix 2 issues ASAP:
* Pawn promotion
* Slugish performance

There's some satisfaction : I sat on the train with my tablet and I played my game for the first time, not for debugging, just for...fun, and I enjoyed it, put up some musics, then move the pieces around, getting destroyed by the IA. My first check mate on my own program !
I'm must say, it's an overall nice application. Not because I've done it, because, it's simple, it's good looking, it's light, responsive (in some way), I can pause it to change my music, read something and the get back to my game : it's just...nice !
That how a I like any application to be.

14/02/2012
Partial fix for the pawn promotion, but no testing, I'm pushing it live.
About performance, I have the real numbers : 5 fps and 25 fps without shadows on my Xoom tablet, holly ! The scene is 310 000 triangles big. I guess my 3D assets are not tailored for real-time rendering.

I've found a GPU profiler for Android that might help me increasing perfomance:
http://developer.nvidia.com/nvidia-perfhud-es

5AM : I've finally found out why there's a huge performance loss with the shadows, expect a fix to be ready any time soon.
I also want to fix the knight shadow : the way triangles are not connected makes the shadow volume rendering to fail.
More environments will be added in the next version.

Some figures for the first day:
* 77 downloads : best start so far, I'd like to know how many people would retain my application.
* Admob : revenue $0.19 Request : 262     $2.02     36.26%     
=> 262 ad request : not bad because it means people are actually using my application.
4 click => $0.19 \o/ !
=> earning significant amount of money with Admob takes a lot of time, it's only suited for applications with a large user base (>10 000 users), I made the calculation that Chess is popular enough game so that Chessmind3D will reach a such high amount of users.

15/02/2012

No performance improve so far. 200 000 textured triangles gives 5 fps, that means that the throughput of my engine is 1Millon triangles per second. Not close to the 77 Million claimed by Nvidia. Maybe it's because of Java, but I doubt it since everything is cached and handled by OpenGL ES.
Anyway I'm looking for another set of chess pieces that will reduce hardware requirement by a factor 10=> 20 000 triangles.

Responsiveness is one crucial point for mobile device application, I will not be satisfied until I can get it right.

What kills performance is drawing triangle to infinty for the shadow volume, it's so fillrate heavy. I think it's possible to achieve the right effect with some "variable extrusion", so that the bouding is volume is big enough while not killing performance.

16/02/2012

By using Meshlab, which is a geat tool, I can reduce the mesh density therefore increasing performance, but it also significantly lower visual quality.
5 fps is low but it's only a chess game.
* I will make an attempt for super scale down : 800 triangles per chess piece.
=> I can have 2 different assets : high end and low end and select corresponding meshes by detection (screen resolution might be a good hint).

* New skyboxes on their way => should make ambient light adaptable to match skybox general color (here is would be slightly yellowish).

17/02/2012

Some figures after 4 days:
Android market downloads : 350

Revenue
$0.78
    
eCPM
$1.17
    
Requests
844
    
Impressions
671
    
Fill Rate
79.50%
    
CTR
3.73%

Not bad but it's not a takeoff, I should tailor down my application to fit small screen device and improve performance.
At least I know now that I kind attract people with nice graphics and attractive presentation on the Market, but now I should make my app usable on every targeted devices not only tablets.

Low performance on Tegra 2: I can't understand why performance are so low on tablet, with 20 000 triangles, no light calculation no shadow, I'm having 35 miserable fps, why with the not so powerful Galaxy S, I am getting a steady 60fps. I'm starting to wonder if OpenGL ES 1.0 is broken on Tegra 2.
Some people apparently are getting the same issue:
http://stackoverflow.com/questions/9278976/opengl-es-1-1-performance-issues-on-tegra-tablet

100 active installs!!

1    Samsung Galaxy Ace (GT-S5830)    7.0% (7)
2    Samsung Galaxy Tab    5.0% (5)
3    Samsung Galaxy S2    5.0% (5)
4    TF201    5.0% (5)
5    Samsung Galaxy Tab 10.1    4.0% (4)
6    Motorola XOOM (wingray)    4.0% (4)
7    Samsung Galaxy Ace (GT-S5830L)    3.0% (3)
8    Motorola XOOM (wifi_hubble)    3.0% (3)
9    SEMC Xperia Play    3.0% (3)
10    Samsung Galaxy S    2.0% (2)

Looks like it gets attention from many tablet owners, which what it was intended for in the first place.

18/02/2012

New version on Android Market:
* Improved performance (but lower visual quality)
* Better usability with visual feedback on touch
* Fixed pawn promotion bug
* Improved stability after idle
* Improved load time
* New background !

20/02/2012

I'm following carefully my admob request statistics because it's the only real-time feedback of my Chessmind3D current usage.

Saturday with 281 requests was a great day but then already by Sunday it drops sharply to 235 requests.
The overall figure is not growing that much which shows that new users are barely replacing early users => my first conclusion is that my user base is not growing. Is user satisfaction low ?!
I still kind of early to run into panic mode especially considering that the first usable version was only release friday.

21/02/2012

Ooops, spoke to quickly, yesterday's figure was even more awesome: 315 req, more than Saturday.
Currently 700 downloads, I might reach the 1000 mark before the end of this week.

22/02/2012
This time, I'm going all out, fear the dreadful youtube promotion video ! For you all internet haters !
http://www.youtube.com/watch?v=eP99b9GYtuc

23/02/2012
Amazing download numbers : 892 so far, the pace is now 100 dl per days. I think that the one star rating is hurting me, by I'm not keen into voting mysel or asking some ppl to rate my app. Too much work ethic out there I think.

Towards a new version:
* More stable rotate gesture
* Fix tiles highlights bugs
* Hghilight last move
* More user feedback (move + check + who's turn)
* More game options (difficulty level ?, point of view, human vs human)

24/02/2012
With 1022 downloads, I've overtaken the thousand mark !

25/02/2012
Crash report and resolution:
I received an insightful report, today, usually bug report are obscure dalvik error.
 
java.lang.NullPointerException
at org.nicolasmy.chessmind3d.Sd3dGame$Sd3dGameEntityManager.processFrame(Sd3dGame.java:135)
at org.nicolasmy.chessmind3d.Sd3dGame.processFrame(Sd3dGame.java:334)
at org.nicolasmy.chessmind3d.Sd3dGLSurfaceView$GLThread.guardedRun(Sd3dGLSurfaceView.java:470)
at org.nicolasmy.chessmind3d.Sd3dGLSurfaceView$GLThread.run(Sd3dGLSurfaceView.java:351)
 


The reason for this seems impossible to happen at first glance:
 
                if (mEntityList[i] != null)
                    if(mEntityList[i].isActive)
                    {
                    if (mEntityList[i].hasOnProcessFrame)
                    {
                        mEntityList[i].onProcessFrame((int)mElapsedTime);
                    }
 
                    if (mEntityList[i].isCamera)
                    {
                        scene.setCamera(mEntityList[i].getPosition(),mEntityList[i].getOrientation());
                    }
 
                    if (mEntityList[i].hasObject)
                    {
                        if (invalidateRenderElements)
                        {
                            for (int j = 0; j< mEntityList[i].mObject.mMesh.length;j++)
                             mEntityList[i].mObject.mRenderElement = null;
                            for (int l = 0;l < mEntityList[i].mObject.mMaterial.length;l++)
                             mEntityList[i].mObject.mMaterial[l].mColorName = 0;
                            if (mEntityList[i].mObject.mIsPickable)
                            {
                                mEntityList[i].mObject.pickedMaterial.mColorName = 0;
                                mEntityList[i].mObject.prepickedMaterial.mColorName = 0;
                                mEntityList[i].mObject.unpickedMaterial.mColorName = 0;
                            }
                        }
                        scene.addObject(mEntityList[i].mObject);
                    }
 
                    if (mEntityList[i].hasProcessTimer)
 

The crash is at the last line...

Except that I have method :
 
        public void reset()
        {
            for (int i = 0;i < mMaxEntity;i++)
            {
                mEntityList[i] = null;
            }
        }
 

Which is called from another thread when the new game button is pushed.
Some "synchronized" will fix this.

From a general point of view, I'm wondering if it's better for synching things between threads, to use a fifo queue, but then that would be heavy and not straight forward in code, as the usual model where object interact with each other.

26/02/2012
Oh sh...t, I've never seen this chess game, never made it to the Android market:
http://www.youtube.com/watch?v=V5l2QGQJUAI&feature=endscreen&NR=1
It might kill my attempt right away !

New version of Chessmind3D on Android Market (Black pawn promotion fix and bug report fix)

Chessmind3D future development:
The success of Chessmind3D almost took me by suprise, although I did work for it. I think I did get what people expect when they download Chessmind3D, it's not about Chess as there are so many very nice chess game and Android. It's all about the graphics and being able to deliver something different from any other chess game.
From the financial point of view, I need people to use my app on regular basis so I need to make them come back to my game as often as possible. I'm focus on delivering this user experience that will make my game the game you need to play everyday.

17/03/2012

Yay ! 2 two "not so negative" comment and ratings on my app, and on the same day.
Thanky you guys so much !

04/12/2012

9 months later : I've tried so hard to avoid it, but I am porting Chessmind to the current version of Sd3d. This would allow me to continue developping Chessmind3D as I've stopped everything waiting for this new version.

05/12/2012

Actually OpenGL ES 2.0 makes it much more simple to do color picking : reading pixels from the framebuffer is now platform independant (no more pbuffer), I just have to create the framebuffer, bind, draw the scene and then call glReadPixels() => GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE is the only format/type supported.