Sunday, July 15, 2012

[Baddies] Dev Diary–Day 1

I’ve started the baddies game again, this time with a twist, I’ll be using the RT-Desk library, a yet unreleased library that aims to change the paradigm of how games are updated, by making all the entities free to decide when to update themselves, only tied to the processor speed, and using messaging to do so.

It’s going to be part of my End-Year-Project, so there’s only so much I can share, but I shall be writing down how the development progresses, for my own reference, and for anyone else who needs to know how to work with this library once it’s released.

In the past few days, I started by making a rough outline of a timeline of the work I have to do:

Timeline

From there I decided the only way to get to understand RT-Desk was a hands on approach, so I decided to make a “Pong” clone and have it run both in Loop mode (traditional game loop) and in Message mode (with RT-Desk). Had some problems setting up SDL, so instead I went for SFML for the graphics/input, and did the loop version today, totally playable (and boring).

During the development of Pong I kept on thinking on how to do it so that the messaging version for later on required the minimum number of changes. And I stumbled across my first problem:

Problem 1

How to make one object “observe” another in messaging mode.
Elaborating this means that even though communicating things to other objects is fine, when you actually need to query something (the ball needs to know the position of the paddle every update step, to know if it’s collided or not), we would need to send a message, and wait for a reply… and by the time we get the information, it might be outdated. This would lead to very serious synchronization problems between the entities in the game, and while “hacking” a solution for the pong game would be fairly easy, it defeats the purpose.

Solution? Investigate. Tomorrow I’ll head to the game-development section of the library and see if there is any literature on the subject. The Sims series for example use a complex messaging system and I remember some article on the subject in one of the Gems books.

Monday, February 13, 2012

State Machines By Example: A Useful FSM

Introduction

A finite state machine is a highly useful tool for programmers in general and for video game programmers in particular. If you’re not familiar with the notion, think about the Finite State Machine (FSM) as a GameBoy, and the States as different cartridges or games.

The GameBoy can only have one game running at any time (or no game at all, in which case it’s not very useful). Obviously, all cartridges share some characteristics (shape, connection pins, etc.…) that allow the GameBoy to interact with any game without knowing or caring what it actually does, just plug it in and it works.

There is one last, important, characteristic that defines this system. Each “game” or state has the rules to decide when to change to another different game (this kind of fucks up the metaphor, but I could not find any better).

So, code-wise, this would be a system as follows:  

FSM

The FSM has one state active, which it updates every cycle. At any moment, the FSM can be told to change to a different state. All states inherit from the State class, and have a common interface so the FSM doesn’t need to know what they do internally, just call the appropriate functions.

FSM

A classic FSM pseudo-code has a structure as follows:

Code Snippet
  1. class FSM
  2. {
  3.     // Current state the FSM uses
  4.     State* currentState;
  5.  
  6.     // Calls the Update function of
  7.     // the currentState
  8.     Update();
  9.  
  10.     // Calls exit of the currentState
  11.     // sets newState as currentState
  12.     // call enter of currentState
  13.     ChangeState(State * newState);
  14. };

 

State

And a base state pseudo-code has the following structure:

Code Snippet
  1. class State
  2. {
  3.     // Pointer to the parent FSM
  4.     FSM* fsmReference;
  5.  
  6.     // Called when the state is initialized
  7.     // by the FSM
  8.     public virtual void Enter();
  9.  
  10.     // Called when the state is ended by the
  11.     // FSM
  12.     public virtual void Exit();
  13.  
  14.     // Called every update cycle by the FSM
  15.     protected virtual void Update();
  16. }

Actual states are not instantiated, only derived states (in our example ShootEnemy, Defend, etc. )

Making it Useful

This basic FSM has several problems or shortcomings that limit it’s use, so let’s have a look at some of them.

Changing State at the Proper Time

Problem

The main flaw the basic FSM pattern has is the fact that at any moment, the current state can request the FSM to change to a different state. When this happens, the following steps take place:

  • CurrentState->Exit();
  • CurrentState = NewState;
  • CurrentState->Enter() // This is the new state

If the fsmReference->ChangeState() call was in the middle of the the Update function, this can leave the state in an undefined state, and propagate errors later on.

Solution

We shall make a request mechanism in the FSM, instead of changing the state, we will request the FSM to change to a state, and the FSM after the state update will change to a different state. For this we replace the ChangeState function for a RequestoReplaceState, and a DoStateReplacement.

Check this pseudo-code for a clearer idea:

Code Snippet
  1. class FSM // With delay state change
  2. {
  3. private:
  4.     // Current state the FSM uses
  5.     State* currentState;
  6.  
  7.     // Temporal pointer to the new state
  8.     State* newState;
  9.  
  10.     // Flag indicating wheter to change state
  11.     bool requestedStateChange;
  12.  
  13.     // Calls the Update function of
  14.     // the currentState
  15.     void Update();
  16.  
  17.     // If a requested state pending,
  18.     // change to new state
  19.     void DoStateReplacement();
  20.  
  21.     // Calls exit of the currentState
  22.     // sets newState as currentState
  23.     // call enter of currentState
  24.     void RequestReplaceState(State * newState);
  25. };
  26.  
  27. void FSM::Update()
  28. {
  29.     if(requestedStateChange)
  30.     {
  31.         DoStateReplacement();
  32.     }
  33.     else if(this.currentState != null)
  34.     {
  35.         currentState->Update();
  36.     }
  37. }
  38.  
  39. void FSM::RequestReplaceState(SinState newState)
  40. {
  41.     nextState = newState;
  42.     requestedStateChange = true;
  43. }
  44.  
  45. void FSM::DoStateReplacement()
  46. {
  47.     if(nextState == null)
  48.     { return; }
  49.     
  50.     requestedStateChange = false;
  51.  
  52.     if(currentState != null)
  53.     { currentState->Exit();    }
  54.     
  55.     currentState = this.nextState;
  56.     nextState = null;
  57.     
  58.     currentState->Enter();
  59. }

 

Push & Pop

Problem

Now we have a FSM that won’t inadvertently introduce subtle ninja bugs when we’re not looking, and can replace the current state for another. But we want to add to the FSM the ability of when we change to a state, to push the current state back into memory, to be popped later on. This might be useful for example in this scenario:

  • Guard.state = patrolling –> Hears sound
    • Guard.state = goSeeDisturbance , PushBack( patrolling )
    • Guard –> Doesn’t find anything in sound source. Pop ( goSeeDisturbance )
  • Guard.state = patrolling

Instead of destroying the patrolling state and then having to create it again, we just push it back, store it, and once the temporal state (goSeeDisturbance) is over, we resume patrolling.

Solution

To properly do this we need to add a pause functionality to our states. Notice a very important detail that is that the Pause / Update / Resume functions, overloaded in the base classes, are no longer called by the FSM but instead we have Manager functions (ManagerUpdate, ManagerPause, ManagerResume) that are called by the FMS, while derived classes (from State) just override the same version without the “Manager” part. This allows us to add some extra functionality to all Update / Pause / Resume calls of all derived classes. With this, we can implement pause / resume, by letting the user specify what is going to happen in his state when it pauses / resumes, while doing the maintenance work (setting flags and safety checks) in the manager version. Check the code for a clearer idea:

 

Code Snippet
  1. class State
  2. {
  3.     // Pointer to the parent FSM
  4.     FSM* fsmReference;
  5.  
  6.     // Indicates whether the state is paused
  7.     bool isPaused;
  8.  
  9.     // Overriden in base clases to put pause
  10.     // logic
  11.     protected virtual void Pause();
  12.  
  13.     // Overriden in base clases to put
  14.     // resume logic
  15.     protected virtual void Resume();
  16.  
  17.     // Called when the state is initialized
  18.     // by the FSM
  19.     public virtual void Enter();
  20.  
  21.     // Called when the state is ended by the
  22.     // FSM
  23.     public virtual void Exit();
  24.  
  25.     // NOT CALLED BY FSM ANYMORE
  26.     protected virtual void Update();
  27.  
  28.     // Called by the FSM every update
  29.     // cycle
  30.     public void ManagerUpdate();
  31.     
  32.     // CAlled by FSM on pause
  33.     public void ManagerPause();
  34.  
  35.     // Called by FSM on resume
  36.     public void ManagerResume();    
  37. }
  38.  
  39.  
  40. void State::ManagerUpdate()
  41. {
  42.     if(!this.isPaused)
  43.     { this.Update(); }
  44. }
  45.     
  46. void State::ManagerPause()
  47. {
  48.     this.isPaused = true;
  49.     this.Pause();
  50. }
  51.     
  52. void State::ManagerResume()
  53. {
  54.     this.isPaused = false;
  55.     this.Resume();
  56. }

And add a push & pop mechanism to the FSM, very similar to the replace mechanism, but we store the pushed state in a variable, to restore it later. This is only an example, so it’s not very useful. For it to be useful we would need a list of pushed states, because that would allow us to push and pop as much as we wanted.

Code Snippet
  1. class FSM
  2. {
  3.     // Current state the FSM uses
  4.     State* currentState;
  5.  
  6.     // Calls the Update function of
  7.     // the currentState
  8.     Update();
  9.  
  10.     // Calls exit of the currentState
  11.     // sets newState as currentState
  12.     // call enter of currentState
  13.     ChangeState(State * newState);
  14.  
  15.     
  16.     // Stores a pushed state.
  17.     // Make this->a list to store a pile of states.
  18.     private State pushedState = null;
  19.     
  20.     
  21.     // Indicates whether a new state push
  22.     // has been requested.
  23.     private bool requestedStatePush
  24.     
  25.     
  26.     // Indicates whether a new state pop has
  27.     // been requested.
  28.     private bool requestedStatePop;
  29.  
  30.     void DoStatePop();
  31.  
  32.     void RequestStatePop();
  33.  
  34.     void DoStatePush();
  35.  
  36.     void RequestPushState(State newState);
  37. };
  38.  
  39. void FSM::Update()
  40. {
  41.     if(this->requestedStateChange)
  42.     {
  43.         this->DoStateReplacement();
  44.     }
  45.     else if(this->requestedStatePush)
  46.     {
  47.         this->DoStatePush();
  48.     }
  49.     else if(this->requestedStatePop)
  50.     {
  51.         this->DoStatePop();
  52.     }
  53.     else if(this->currentState != null)
  54.     {
  55.         this->currentState.ManagerUpdate();
  56.     }
  57. }
  58.  
  59. void FSM::RequestPushState(State newState)
  60. {
  61.     this->nextState = newState;
  62.     this->requestedStatePush = true;
  63. }
  64.  
  65. void FSM::DoStatePush()
  66. {
  67.     if(this->nextState == null)
  68.     {
  69.         Log.Write("ERROR! Attempting state push in null state");
  70.         return;
  71.     }
  72.  
  73.     if(this->currentState == null)
  74.     {
  75.         Log.Write("ERROR! Attempting state push back null state");
  76.         return;
  77.     }
  78.     
  79.     this->requestedStatePush = false;
  80.     this->pushedState = this->currentState;
  81.     
  82.     this->pushedState.ManagerPause();
  83.     
  84.     this->currentState = this->nextState;
  85.     this->nextState = null;
  86.     
  87.     this->currentState.SetWasPushed(true);
  88.     this->currentState.Enter();
  89. }
  90.  
  91. void FSM::RequestStatePop()
  92. {
  93.     this->requestedStatePop = true;
  94. }
  95.  
  96. void FSM::DoStatePop()
  97. {
  98.     if(this->pushedState == null)
  99.     {
  100.         Log.Write("ERROR! Attempting state pop null state");
  101.         return;
  102.     }
  103.     
  104.     if(this->currentState != null)
  105.     {
  106.         this->currentState.Exit();
  107.     }
  108.     
  109.     this->requestedStatePop = false;
  110.     this->currentState = this->pushedState;
  111.     this->pushedState = null;
  112.     
  113.     assert this->currentState != null;
  114.     this->currentState.ManagerResume();
  115. }

 

Timed Update

Last improvement we can add is a timed update, by simply passing a “update time” to each state constructor and making the State::ManagerUpdate keep track of it:

Code Snippet
  1. public void ManagerUpdate()
  2. {
  3.     if(!this->isPaused)
  4.     {
  5.         if(this->updatePeriod == 0 ||
  6.                 CurrentTime() - this->lastUpdateTime >=
  7.                 this->updatePeriod)
  8.         {
  9.             this->Update();
  10.             this->lastUpdateTime = CurrentTime();
  11.         }
  12.     }
  13. }

 

The Code

It’s not “by example” if it doesn’t have an example, so here is a complete example in Java.

Finite State Machine

Code Snippet
  1. /**
  2. * State machine behavior to provided
  3. * different decision states.
  4. *
  5. * Supports push/pop and replace
  6. * mechanisms. (Stack of only 1 stored state.)
  7. *
  8. * Supports safe-state switch via request.
  9. * @author Ying
  10. *
  11. */
  12. public class FSM
  13. {    
  14.     /**
  15.      * Reference to current state.
  16.      */
  17.     private SinState currentState = null;
  18.     
  19.     /**
  20.      * Reference to next state requested.
  21.      */
  22.     private SinState nextState = null;
  23.     
  24.     /**
  25.      * Indicates whether a new
  26.      * state replace has been requested.
  27.      */
  28.     private boolean requestedStateChange = false;
  29.     
  30.     /**
  31.      * Stores a pushed state.
  32.      * Make this a list to store a pile of states.
  33.      */
  34.     private SinState pushedState = null;
  35.     
  36.     /**
  37.      * Indicates whether a new state push
  38.      * has been requested.
  39.      */
  40.     private boolean requestedStatePush = false;
  41.     
  42.     /**
  43.      * Indicates whether a new state pop has
  44.      * been requested.
  45.      */
  46.     private boolean requestedStatePop = false;
  47.  
  48.     /**
  49.      * Initializes a new instance of the StateMachine
  50.      * class.
  51.      */
  52.     public FSM() {}
  53.  
  54.     /**
  55.      * Update the FSM, and the current state if any.
  56.      */
  57.     @Override
  58.     public void action()
  59.     {
  60.         if(this.requestedStateChange)
  61.         {
  62.             this.DoStateReplacement();
  63.         }
  64.         else if(this.requestedStatePush)
  65.         {
  66.             this.DoStatePush();
  67.         }
  68.         else if(this.requestedStatePop)
  69.         {
  70.             this.DoStatePop();
  71.         }
  72.         else if(this.currentState != null)
  73.         {
  74.             this.currentState.ManagerUpdate();
  75.         }
  76.     }
  77.     
  78.     /**
  79.      * Request to change the current state to a new one.
  80.      * Request will be stored till FSM update.
  81.      * @param newState New state to change to.
  82.      */
  83.     public void RequestReplaceState(SinState newState)
  84.     {
  85.         this.nextState = newState;
  86.         this.requestedStateChange = true;
  87.     }
  88.  
  89.     /**
  90.      * Do the actual state replace.
  91.      */
  92.     private void DoStateReplacement()
  93.     {
  94.         String prev = "Null";
  95.         String next = "Null";
  96.         if(this.nextState == null)
  97.         {
  98.             Log.Write("ERROR! Attempting state replacement to null state");
  99.             return;
  100.         }
  101.         
  102.         next = this.nextState.name;
  103.         this.requestedStateChange = false;
  104.         if(this.currentState != null)
  105.         {
  106.             this.currentState.Exit();
  107.             prev = this.currentState.name;
  108.         }
  109.         
  110.         this.currentState = this.nextState;
  111.         this.nextState = null;
  112.         
  113.         assert this.currentState != null;
  114.         this.currentState.SetWasPushed(false);
  115.         this.currentState.Enter();
  116.         Log.Write("STATE CHANGE: " + prev + " --> " + next);
  117.     }
  118.     
  119.     /**
  120.      * Request to push the current state to
  121.      * storage and run another one.
  122.      * @param newState New state to run.
  123.      */
  124.     public void RequestPushState(SinState newState)
  125.     {
  126.         this.nextState = newState;
  127.         this.requestedStatePush = true;
  128.     }
  129.     
  130.     /**
  131.      * Do the actual state push.
  132.      */
  133.     private void DoStatePush()
  134.     {
  135.         String prev = "Null";
  136.         String next = "Null";
  137.         if(this.nextState == null)
  138.         {
  139.             Log.Write("ERROR! Attempting state push in null state");
  140.             return;
  141.         }
  142.         
  143.         next = this.nextState.name;
  144.         
  145.         if(this.currentState == null)
  146.         {
  147.             Log.Write("ERROR! Attempting state push back null state");
  148.             return;
  149.         }
  150.         
  151.         prev = this.currentState.name;
  152.         this.requestedStatePush = false;
  153.         this.pushedState = this.currentState;
  154.         
  155.         this.pushedState.ManagerPause();
  156.         
  157.         this.currentState = this.nextState;
  158.         this.nextState = null;
  159.         
  160.         assert this.currentState != null;
  161.         this.currentState.SetWasPushed(true);
  162.         this.currentState.Enter();
  163.         Log.Write("STATE PUSH: " + prev + " --> "
  164.                 + next + " [Pushed state: "+
  165.                 this.pushedState.name +"]");
  166.     }
  167.     
  168.     /**
  169.      * Request pop of current state and
  170.      * restoring of the pushed one.
  171.      */
  172.     public void RequestStatePop()
  173.     {
  174.         this.requestedStatePop = true;
  175.     }
  176.     
  177.     /**
  178.      * Does the actual pop.
  179.      */
  180.     private void DoStatePop()
  181.     {
  182.         String prev = "Null";
  183.         String next = "Null";
  184.         if(this.pushedState == null)
  185.         {
  186.             Log.Write("ERROR! Attempting state pop null state");
  187.             return;
  188.         }
  189.         
  190.         next = this.pushedState.name;
  191.         
  192.         if(this.currentState != null)
  193.         {
  194.             this.currentState.Exit();
  195.             prev = this.currentState.name;
  196.         }
  197.         
  198.         this.requestedStatePop = false;
  199.         this.currentState = this.pushedState;
  200.         this.pushedState = null;
  201.         
  202.         assert this.currentState != null;
  203.         this.currentState.ManagerResume();
  204.         Log.Write("STATE POP: " + prev + " --> " + next);
  205.     }
  206. }

 

State

Code Snippet
  1. /**
  2. * Base class for states.
  3. * Supports state pause.
  4. * @author Ying
  5. *
  6. */
  7. public abstract class SinState
  8. {
  9.     /**
  10.      * Whether the state is paused.
  11.      */
  12.     protected boolean isPaused;
  13.     
  14.     /**
  15.      * Update period of the state.
  16.      */
  17.     protected int updatePeriod;
  18.     
  19.     /**
  20.      * Last update period.
  21.      */
  22.     private long lastUpdateTime;
  23.     
  24.     /**
  25.      * Reference to the FSM
  26.      */
  27.     protected StateMachine FSM;
  28.     
  29.     /**
  30.      * State name.
  31.      */
  32.     public String name;
  33.     
  34.     /**
  35.      * Whether the state was pushed.
  36.      */
  37.     private boolean wasPushed;
  38.     
  39.     /**
  40.      * Initializes an instance of the SinState class.
  41.      * @param updatePeriod The time (in ms) between
  42.      *  each update. Set 0 for going as fast as possible.
  43.      */
  44.     public SinState(int updatePeriod, StateMachine FSM, String name)
  45.     {
  46.         this.isPaused = false;
  47.         this.updatePeriod = updatePeriod;
  48.         this.lastUpdateTime = System.currentTimeMillis();
  49.         this.FSM = FSM;
  50.         this.name = name;
  51.     }
  52.     
  53.     // Override functions
  54.     public abstract void Enter();
  55.     public abstract void Exit();
  56.     protected abstract void Update();
  57.     protected abstract void Pause();
  58.     protected abstract void Resume();
  59.  
  60.     // Manager functions
  61.     public void ManagerUpdate()
  62.     {
  63.         if(!this.isPaused)
  64.         {
  65.             if(this.updatePeriod == 0 ||
  66.                     System.currentTimeMillis() - this.lastUpdateTime >=
  67.                     this.updatePeriod)
  68.             {
  69.                 this.Update();
  70.                 this.lastUpdateTime = System.currentTimeMillis();
  71.             }
  72.         }
  73.     }
  74.     
  75.     public void ManagerPause()
  76.     {
  77.         this.isPaused = true;
  78.         this.Pause();
  79.     }
  80.     
  81.     public void ManagerResume()
  82.     {
  83.         this.isPaused = false;
  84.         this.Resume();
  85.         this.lastUpdateTime = System.currentTimeMillis();
  86.     }
  87.     
  88.     public void SetWasPushed(boolean pushed)
  89.     { this.wasPushed = pushed; }
  90.     
  91.     public boolean WasPushed()
  92.     { return this.wasPushed; }
  93. }

 

Conclusion

Finite states machines are a very useful construct for controlling the flow of a game, how your game scene updates in different situations, how your character acts… It’s not a holly grail, all purpose solution, but it works surprisingly well for many scenarios.

Enjoy.

Saturday, February 4, 2012

More advanced concepts of getting cocos2dx working on Android from Windows 7


NOTE: This tutorial was done with cocos2d-1.0.1-x-0.9.1 and cocos2d-1.0.1-x-0.11.0, and so may not be 100% accurate for either version, or newer [Had to change version in the middle of development], but will serve as a general guideline for anyone using similar versions.

First Part: Quick and dirty guide to getting cocos2dx working on Android from Windows 7

Introduction

Working from the files we obtained in the first part, in this tutorial we shall cover:

  • Moving android-generated folder away from the cocos2d-x folder.
  • Add an extra library ( Chipmunk ).
  • Not having to use the Classes & Resources folders.

It’s important to use the proper editing tool for the files generated by the “create-android-project.bat”, because regular windows editors add extra symbols like “\r” that will confuse your Cygwin. I recommend Notepad++.  A great editor that has the invaluable property of showing hidden symbols by doing: View -> Show symbol -> Show all characters.

Moving The Folder

I generated a new project FOLLOWING THE STEPS IN THE PART ONE OF THE TUTORIAL, let’s call it FVZ, using the following specs:

  • Package: com.companyname.fvz
  • Name: FVZ_2_3
  • Target ID: 13 (Android 2.3.3)

And copied it from the cocos2d-x folder where it’s generated by default, to the folder where my Visual Studio solution held all my code of the project I was working on. To make this work, I had to modify:

  • android/build_native.sh
    • GAME_ROOT=/cygdrive/d/All/Proyects/FVZ/Android/FVZ_2_3
      ( Set the path to where we have copied the project folder, and add the /cygdrive/ in front so Cygwin can use the path ).
  • android/jni/Android.mk
    • Modify project path: addprefix $(LOCAL_PATH)/../../../../FvZv2/ to point to the root folder of the cocos2dx instaltion (where you have all the cocos2dx code, ej: cocos2dx, CocosDenshion, tests, tools…

      What this does is search for all the Android.mk (makefiles) of the libraries you are going to use. (Notice the addprefix & addsufix functions, to generate the full paths).

      # Try to use LOCALPATH, otherwise you’ll have to play a bit with the path till you get it to Cygwin’s liking.
  • android/jni/helloworld
    • LOCAL_SRC_FILES: Add RELATIVE path to each code file (cpp / h) in your Visual Studio project folder. The start of my list is, for example:
      • LOCAL_SRC_FILES := main.cpp \
        ../../../../../FvZv2/FvZ/Classes/AppDelegate.cpp \
        ../../../../../FvZv2/FvZ/Classes/AppDelegate.h \
        ../../../../../FvZv2/FvZ/Classes/HelloWorldScene.cpp …

    • LOCAL_C_INCLLUDES: Change Classes path to the folder where you keep all your code, and set the paths for the different cocos folders so they point to the required folders.
    • LOCAL_LDLIBS: Point the $(LOCAL_PATH)/../../libs/$(TARGET_ARCH_ABI)) to the proper location (TARGET_ARCH_ABI is usually armeabi).
  • andoid/build_native.sh
    • Change GAME_ROOT so it points to the root of your game folder, in my case:
      GAME_ROOT=/cygdrive/d/All/Proyects/FVZ/Android/FVZ_2_1

With all that your project should compile with no problems using Cygwin. As a special note, I made a java script to parse my Classes folder, to generate my LOCAL_SRC_FILES paths, as there where hundreds of files, in nested folders and so on. Sharing it here:

Code Snippet
  1. import java.io.File;
  2.  
  3.  
  4. public class ListFiles
  5. {
  6.     static String initialPath = "D:\\All\\Proyects\\FvZ\\FvZv2\\FvZ\\Classes";
  7.  
  8.     public static void main(String[] args)
  9.     {
  10.         FileTreePrint("");
  11.     }
  12.     
  13.     private static void FileTreePrint(String path)
  14.     {
  15.         String files;
  16.         File folder = new File(initialPath + path);
  17.         File[] listOfFiles = folder.listFiles();
  18.  
  19.         for (int i = 0; i < listOfFiles.length; i++)
  20.         {
  21.             if (listOfFiles[i].isFile())
  22.             {
  23.                 files = listOfFiles[i].getName();
  24.                 System.out.println("../../../../../FvZv2/FvZ/Classes"+ path.replace("\\", "/") + "/" +files+ " \\");
  25.             }
  26.         }
  27.         
  28.         for (int i = 0; i < listOfFiles.length; i++)
  29.         {
  30.             if (listOfFiles[i].isDirectory())
  31.             {
  32.                 FileTreePrint(path + "\\" +listOfFiles[i].getName());
  33.             }
  34.         }
  35.     }
  36. }

 

Adding Chipmunk to the Compilation

We need to modify some files, but it’s a straightforward process if we take another library (CocosDenshion) as a guideline.

  • android/jni/Android.mk
    • Add “chipmunk \” in the line under CocosDenshion/android.
  • android/jni/Application.mk
    • My APP_MODULES looks like:
      APP_MODULES := cocos2d cocosdenshion chipmunk game
  • android/jni/helloworld
    • LOCAL_C_INCLLUDES: Add the path to the chipmunk folder that holds all the files, in my case:
      $(LOCAL_PATH)/../../../../../FvZv2/chipmunk/include/chipmunk \
    • In LOCAL_LDLIBS add –lchipmunk

Lastly, there is one extra modification to be done, that took me quite a while. In the main java file of the .java files generated for your project (in my case FVZ_2_3.java) we need to search for where it does System.loadLibrary(), and add:

  • System.loadLibrary("chipmunk");

Automating the Process

The first thing you will notice with this system is that it’s SLOW. We have have to use the command line every time we want to compile, not to mention that this method copies all the resources of the game from the Resources folder to the assets one each time, which can be very time consuming.

So let’s optimize it a bit.

Making the resource load faster

Grab your build_native.sh and clean out all the logic for cleaning the resource folder, leaving it like this:

Code Snippet
  1. # set params
  2. ANDROID_NDK_ROOT=/cygdrive/c/eclipse/android/android-ndk-r6b
  3. GAME_ROOT=/cygdrive/d/All/Proyects/FVZ/Android/FVZ_2_1
  4. GAME_ANDROID_ROOT=$GAME_ROOT/android
  5.  
  6. # build
  7. $ANDROID_NDK_ROOT/ndk-build -C $GAME_ANDROID_ROOT $*

What is going to happen now is that you’re going to have to remember to manually copy each modified asset from your MVS project to the assets folder of the java project. A small price to pay for compiling in 10 seconds instead of 1 minute.

So go ahead and copy all your resources to the assets folder. Once you’re done…

One Click Process

I created a batch file to be called with a simple double click, that calls cygwin and gets the whole compilation process done. After double clicking on it you just need to refresh the java project in eclipse (F5) and hit “run” to have the game showing in your android. Here is the magical .bat:

Code Snippet
  1. C:\cygwin\bin\bash.exe -l '/cygdrive/d/All/Proyects/FvZ/Android/FVZ_2_1/android/build_native.sh'
  2. pause

Created this Compile.bat thanks to http://forums.techguy.org/windows-xp/424616-calling-unix-scripts-dos-script.html and http://old.nabble.com/Cygwin---batch-file-td15088393.html .

Conclusion

Now you should be able to put your folder wherever you damn well please, add other libraries to it and compile by:

  • Compiling in MVS by hitting F5 (to check it works)
  • Compiling in native code by double clicking Compile.bat
  • Running the game in android by hitting F5 in eclipse, and then “run”.

Tell me if it worked for you!

Friday, September 30, 2011

Quick and dirty guide to getting cocos2dx working on Android from Windows 7

Second Part: More advanced concepts of getting cocos2dx working on Android from Windows 7

This guide builds on the official guide for setting up Cocos2d-x on the Android Phone with additional explanations in the sections where the original one is outdated, incomplete or ambiguous, so hopefully no one else has to make the same mistakes I did.

First a general overview of what has to happen to see your precious game on the android phone. You create a Visual Studio project from a cocos2dx template and set it up to work with cocos2dx. Once you've got your game running and ready to test on the phone, you use a .bat file provided in the cocos2dx download to create a default android project from the "HelloWorld" project it comes with. In this new folder it creates in the android root, you override the existing classes and resources with the ones from your project, and you make sure they are in the makefile. Then you use Cygwin to compile everything into native code, and finally you create a new android project in eclipse, import the code you compiled and hopefully have it work in the phone.

It's a non-trivial process, but not that hard either, and the people at Cocos2dx have made quite an effort to get this working as it is. So, step by step.

Step by Step

Step 1: Get all the android material

Download android sdk, install it and test it in eclipse. This is a well-documented process in the android sdk website.
If you have an Android phone to test on, set it up for development and try a test application in it.
Download the android ndk and extract it to a folder with no spaces in the path.

Step 2: Get all the cocos2dx material

Download the latest version of cocos2d-x and set it up for win32 development as stated here. Download Cygwin and make sure you mark the "Devel" branch as "Install" when you download it.

Step 3: Get the create-android-project.bat working

From the original tutorial:

To adapt to my environment, I change the settings in create-android-project.bat.
set _CYGBIN=C:\cygwin\bin
The path of cygwin bin
set _ANDROIDTOOLS=D:\anroid\android-sdk-windows\tools
The path of android sdk tools
set _NDKROOT=D:\anroid\android-ndk-r5b
The root of ndk

Step 4: Creating the project

Now we create our Cocos2d-win Application form the MVS templates. If this template is not available, go back and check you did step 2 correctly. You can create this project wherever you want. For the sake of brevity, let’s assume you are creating a Pong game, and aptly name your project “Pong”. While following the cocos2dx creation template unmark every cocos2d library except Simple Audio Engine in Cocos Denshion.


Next up we need to add 3 things to make the Pong project reach the cocos2dx files it needs. Include the source files, link the library files, and copy the dll files. To make this process easier create an environment variable with the root of your cocos2dx installation. I call mine COCOS2DX and it’s defined as C:\eclipse\android\cocos2d-1.0.1-x-0.9.1\cocos2d-1.0.1-x-0.9.1.

NOTE: If you modify this variable, or any other, and want to use it from visual studio, you need to restart visual studio.

Step 4.1: Include the source files

Inside Visual Studio, with your Pong project open, right click on the project and select Properties. At the top make sure you select “Configuration: All Configurations”, otherwise you’ll have to repeat the whole process for the each configuration you’ve got (usually just debug and release).
Go to C/C++ / General /Additional Include Directories, there your template should have 9 includes already. Something like this:

  • .;
  • .\win32;
  • .\Classes;
  • ..\cocos2dx;
  • ..\cocos2dx\include;
  • ..\cocos2dx\platform;
  • ..\cocos2dx\platform\third_party\win32\OGLES;
  • ..\CocosDenshion\Include;
  • %(AdditionalIncludeDirectories)


The first 3 you can leave as-is, because they reference the project locally (including what’s in the project folder and in the win32 and classes folders. As you need these files, all is good. The next 5 however, all the ones that start with “..\cocos2dx”, assume you’re in the root cocos2dx folder. So we just correct this using our COCOS2DX environment variable.

  • .;
  • .\win32;
  • .\Classes;
  • $(COCOS2DX)\cocos2dx;
  • $(COCOS2DX)\cocos2dx\include;
  • $(COCOS2DX)\cocos2dx\platform;
  • $(COCOS2DX)\cocos2dx\platform\third_party\win32\OGLES;
  • $(COCOS2DX)\CocosDenshion\Include;
  • %(AdditionalIncludeDirectories)


To be honest, I don’t quite know what the AdditionalIncludeDirectories are, so I just leave it there.
With this however, your project knows where the cocos2dx files it needs are.

Step 4.2 : Adding the libraries

You need the .lib files that where created by compiling the cocos2d-win32.vc2010.sln, all the way back at step 2. We are going to store them locally for clarity, though you could just modify the linker path using our COCOS2DX variable.

In the Pong folder, next to the Classes and Resource folders, we create a Libs folder, and inside put two subfolders, Debug and Release.
Next we copy all the .lib files from our COCOS2DX/Debug.win32 and COCOS2DX/Release.win32 folders to the Debug and Release folders respectively.


Inside Visual Studio, with your Pong project open, right click on the project and select Properties. At the top make sure you select “Configuration: All Configurations”, otherwise you’ll have to repeat the whole process for the each configuration you’ve got (usually just debug and release).
Go to Linker / General / Additional Library Directories and you should find something like:

  • $(OutDir);
  • %(AdditionalLibraryDirectories)

We need to add the library path, so we make it:

  • $(OutDir);
  • $(SolutionDir)\Pong\Libs\$(Configuration);
  • %(AdditionalLibraryDirectories)

As long as you only have Debug and Release configurations this should work fine. Visual will go to Pong/Libs/Debug or Pong/Libs/Release and get the .lib files from there when needed. If you add more configurations, make sure to add the appropriate folder to Libs. If your project is not named Pong, modify the path accordingly.
Right now it should let you compile the project without errors but not run it. We’re missing the dlls.

Step 4.3: Adding dlls

First build your application both in release and in debug. This should create in your visual studio project debug and release folders with an executable called Pong.exe, and maybe a few other things.

Go back to the COCOS2DX/Debug.win32 and COCOS2DX/Release.win32 folders and fish out all the .dll files copying them to the Debug and Release folders in your Pong project folder respectively.
There. You should be able to build and run, seeing your project on a small window.

Step 5: Use the .bat to create an android project

This is pretty well covered in the original tutorial. Click the create-android-project.bat and fill out the package path (org.cocos2dx.Pong in our case) and the name (Pong) and finally the version to compile to (a list of versions should appear in screen).


NOTE: This step is irrelevant of your visual studio project, you don’t need to copy your Pong visual studio project to the cocos2dx root or anything. The .bat creates a folder all by itself.

Step 6: Fill in the meat

This is the step that really had me stumped until I asked in the forums. The .bat creates a new project based on the HelloWorld example in the root directory, so if you just run the bat and continue to the next step, in the end you’ll have the HelloWorld project in your phone instead of the Pong game.


Once you have the Pong folder created by the .bat in the root cocos2dx folder, you need to copy the content of your Classes folder in your visual studio Pong project to the cocos2dx Pong Classes folder, substituting the contents, and do the same with the Resources folder.


Now the files are in the appropriate place, but we still need to tell tel the makefile to take them into consideration when compiling, so we go to COCOS2DX\Pong\android\jni\helloworld\Android.mk and modify the makefile. You’ll notice that near the top of the file there is a LOCAL_SRC_FILES that already includes the path of the main.cpp and the 2 HelloWorld project files. Leave the main but override the rest so it has the paths of the files you added.

In my case:
LOCAL_SRC_FILES := main.cpp \
../../../Classes/AppDelegate.cpp \
../../../Classes/Elements/Ball.cpp \
../../../Classes/Elements/Stick.cpp \
../../../Classes/Scenes/PlayScene.cpp \
../../../Classes/Scenes/TitleScreen.cpp

Step 6: Run Cygwin to compile

Just like the original tutorial explains

Step 7: Create a project in eclipse and import the Pong project

Just like the original tutorial explains.

Second Part: More advanced concepts of getting cocos2dx working on Android from Windows 7

Saturday, August 27, 2011

Baddies 4–Saving

Introduction

Objective

The objective of the saving system is, given a node, any node, serialize it completely and automatically without having to go through the mistake prone method of each time we add a member, having to remember to update the load and save functions.

To this aim, we will use the IntermediateSerializer class, with a few auxiliary classes to handle logical exceptions in our design and in the IntermediateSerializer class.

Considered options

There are several options when saving the game in XNA, the 3 more common ones are serializing using the XmlSerializer class, serializing using the IntermediateSerializer class, and finally, saving with a BinaryWriter class.

The reasons why I won’t use the XmlSerializer are explained in the conclusion in this post, so I won’t expand on it. The BinaryWriter, on the other hand, requires knowing the data you are going to read beforehand, as it’s in binary format and you need to select “chunks” of specific lengths to be interpreted as variables. This does not work well with the initial objective of the saving being automatic or not having to make custom save / load functions for each class. This leaves us with the IntermediateSerializer.

Serialization

Serializing with the IntermediateSerializer

The use of the IntermediateSerializer is best documented in these 2 articles by Shawn Hargraves: Teaching a man to fish, and Everything you ever wanted to know about IntermediateSerializer.

On the positive side, it’s simple (doesn’t require the multithreading gymnastics for the container that the XmlSerializer needs), and highly customizable (adding private members, excluding public members, setting members as references, dealing with collections, etc…). On the negative side, it only works on windows, but that’s an acceptable inconvenient, and it needs the full .Net Framework 4.0 instead of the client version (explanation).

Working with the Node

For our specific situation, we want to serialize a subtree of nodes, this nodes being any class that might derive from node. For example, we might have a situation like this:

Saving1

This diagram represents that there is a root node “Scene” with two added child nodes “Camera” and “Map” (ignore the UML notation, it was the only editor at hand). We want to serialize Scene without caring about what hangs from it and have everything serialized to XML.

The first attempt at serializing this launched an error of cyclic reference, as each Node has a pointer to it’s parent. To solve this we declared the parent member of a node as a ContentSerializerAttribute.SharedResource so instead of storing the parent, it just stored a reference to this. This serialized, but upon closer investigation of the XML code it became apparent that this generated “shadow” parents, as we had both the original parent that called the serialization, and the one each child was referencing, resulting in something like this:

Ssaving2

That’s because the children of each node are not references themselves, if they were we’d just have a very slim XML tree with just references, no content, and then the references at the bottom. Something like this:

Code Snippet
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <XnaContent xmlns:Utils="Baddies.Utils"
  3.             xmlns:Scenes="Baddies.Scenes"
  4.             xmlns:Nodes="Baddies.Nodes">
  5.   
  6.   <!-- Root of the tree-->
  7.   <Asset Type="Utils:NodeSerializer">
  8.     <root>#Resource1</root>
  9.   </Asset>
  10.  
  11.   <!-- References-->
  12.   <Resources>
  13.  
  14.     <!-- Scene node-->
  15.     <Resource ID="#Resource1" Type="Scenes:Scene">
  16.       <Name>Node</Name>
  17.       <ParentRelativePos>false</ParentRelativePos>
  18.       <Children Type="Utils:SharedResourceDictionary[int,Nodes:Node]">
  19.         <Item>
  20.           <Key>0</Key>
  21.           <Value>#Resource2</Value>
  22.         </Item>
  23.         <Item>
  24.           <Key>1</Key>
  25.           <Value>#Resource3</Value>
  26.         </Item>
  27.       </Children>
  28.       <Visible>true</Visible>
  29.       <Position>-0 -0 -0</Position>
  30.       <Parent />
  31.     </Resource>
  32.  
  33.     <!-- Camera node -->
  34.     <Resource ID="#Resource2" Type="Baddies.Camera">
  35.       <Name>Cam</Name>
  36.       <ParentRelativePos>false</ParentRelativePos>
  37.       <Children Type="Utils:SharedResourceDictionary[int,Nodes:Node]" />
  38.       <Visible>true</Visible>
  39.       <Position>0 0 0</Position>
  40.       <Parent>#Resource1</Parent>
  41.       <W>673</W>
  42.       <H>442</H>
  43.       <DisplayBorder>true</DisplayBorder>
  44.     </Resource>
  45.  
  46.     <!-- Map node -->
  47.     <Resource ID="#Resource3" Type="Baddies.Map.MapGrid">
  48.       <Name>Map</Name>
  49.       <ParentRelativePos>true</ParentRelativePos>
  50.       <Children Type="Utils:SharedResourceDictionary[int,Nodes:Node]" />
  51.       <Visible>true</Visible>
  52.       <Position>0 0 0</Position>
  53.       <Parent>#Resource1</Parent>
  54.       <DisplayTerrain>true</DisplayTerrain>
  55.       <DisplayGrid>true</DisplayGrid>
  56.       <DisplayCollisionMap>false</DisplayCollisionMap>
  57.       <MapWidth>16</MapWidth>
  58.       <MapHeight>16</MapHeight>
  59.       <TileSize>16</TileSize>
  60.       <Tiles>
  61.         <!-- Map tiles excuded for brevity -->
  62.       </Tiles>
  63.       <tileSetTex>
  64.         <Name>TileMap/tileset1</Name>
  65.         <contentRef>#Resource3</contentRef>
  66.       </tileSetTex>
  67.     </Resource>
  68.     
  69.   </Resources>
  70. </XnaContent>

To achieve that structure we need to set the children of the Node as references as well. The children of each node are kept in a dictionary, so to solve this “dictionary of shared resources” dilemma, I wrote a class to handle it, explained in this article. This is one of the few exceptions to the “not writing custom code for saving different data” but only because the IntermediateSerializer doesn’t support these type of dictionaries out of the box.

Another exception is that even if we mark everything as references, the first node to be serialized is not considered a reference because it’s the starting point of the serializer. To solve this I made a wrapper class to serialize that only contains the root node, as a reference.

Code Snippet
  1. /// <summary>
  2. /// Auxiliary class that takes care of
  3. /// the serialization of a Node tree.
  4. /// <remarks>
  5. /// Works by having a reference to the
  6. /// node and serializing itself, so the root
  7. /// node is also regarded as a reference.
  8. /// </remarks>
  9. /// </summary>
  10. public class NodeSerializer
  11. {
  12.     /// <summary>
  13.     /// Root node to serialize.
  14.     /// </summary>
  15.     [ContentSerializerAttribute(SharedResource = true)]
  16.     private Node root;
  17.  
  18.     /// <summary>
  19.     /// Serializes a node to XML.
  20.     /// </summary>
  21.     /// <param name="node">Node to
  22.     /// serialize.</param>
  23.     /// <param name="name">Name of the
  24.     /// file to serialize to.</param>
  25.     public void Serialize(Node node, string name)
  26.     {
  27.         this.root = node;
  28.  
  29.         XmlWriterSettings settings =
  30.             new XmlWriterSettings();
  31.         settings.Indent = true;
  32.  
  33.         using (XmlWriter writer =
  34.             XmlWriter.Create(name, settings))
  35.         {
  36.             IntermediateSerializer.
  37.                 Serialize(writer, this, null);
  38.         }
  39.     }
  40.  
  41.     /// <summary>
  42.     /// Deserializes the XML file provided
  43.     /// and returns the created node.
  44.     /// </summary>
  45.     /// <param name="name">Name of the xml file.</param>
  46.     /// <returns>Node serialized in that file.</returns>
  47.     public Node Deserialize(string name)
  48.     {
  49.         Node node = null;
  50.         XmlReaderSettings settings =
  51.             new XmlReaderSettings();
  52.  
  53.         using (XmlReader reader =
  54.             XmlReader.Create(name, settings))
  55.         {
  56.             NodeSerializer serial =
  57.                 IntermediateSerializer.
  58.                 Deserialize<NodeSerializer>(reader, null);
  59.             node = serial.root;
  60.         }
  61.  
  62.         return node;
  63.     }
  64. }

The last exception comes with the Texture2D class. I wanted that the serializing of a tree included the actual textures used, as not to have to do a “second” step when loading. This has 2 problems. First, the texture is binary data, so kind of difficult to serialize in xml. Second, the texture has a reference to the ContentManager that loaded it, so it creates a circular dependency that there is no way to solve, short of dumping the use of the ContentManager all together.

To work around these 2 issues I created a Texture2D proxy class, as shown here:

Code Snippet
  1. public class Texture2DProxy
  2. {
  3.     /// <summary>
  4.     /// Reference to the the parent class
  5.     /// that holds a ContentManager to load
  6.     /// this texture.
  7.     /// </summary>
  8.     [ContentSerializerAttribute(SharedResource = true)]
  9.     private IContentHolder contentRef;
  10.  
  11.     /// <summary>
  12.     /// Texture we wrap.
  13.     /// </summary>
  14.     private Texture2D texture;
  15.  
  16.     /// <summary>
  17.     /// Name of the texture in the
  18.     /// ContentManager.
  19.     /// </summary>
  20.     private string name;
  21.  
  22.     /// <summary>
  23.     /// Initializes a new instance of
  24.     /// the Texture2DProxy class.
  25.     /// </summary>
  26.     /// <param name="contentRef">
  27.     /// Content manager that will be
  28.     /// used for loading.</param>
  29.     public Texture2DProxy(IContentHolder contentRef)
  30.     {
  31.         this.contentRef = contentRef;
  32.         this.name = string.Empty;
  33.         this.texture = null;
  34.     }
  35.  
  36.     /// <summary>
  37.     /// Initializes a new instance of
  38.     /// the Texture2DProxy class.
  39.     /// </summary>
  40.     public Texture2DProxy()
  41.     {
  42.         this.contentRef = null;
  43.         this.name = string.Empty;
  44.         this.texture = null;
  45.     }
  46.  
  47.     /// <summary>
  48.     /// Gets or sets the name of the texture.
  49.     /// </summary>
  50.     /// <value>Name of the texture.</value>
  51.     public string Name
  52.     {
  53.         set { this.name = value; }
  54.         get { return this.name; }
  55.     }
  56.  
  57.     /// <summary>
  58.     /// Gets or sets the texture of the proxy.
  59.     /// <remarks>
  60.     /// The Get method has lazy
  61.     /// initialization of the texture,
  62.     /// in the sense that if we have the
  63.     /// texture name and not the texture,
  64.     /// it loads it when we request the
  65.     /// texture. This is useful for when
  66.     /// we load a texture via serialization.
  67.     /// </remarks>
  68.     /// </summary>
  69.     /// <value>Texture that we wrap.</value>
  70.     [ContentSerializerIgnore]
  71.     public Texture2D Texture
  72.     {
  73.         get
  74.         {
  75.             if (this.texture == null &&
  76.                 this.name != string.Empty)
  77.             {
  78.                 ContentManager man =
  79.                     this.contentRef.GetContent();
  80.  
  81.                 this.texture =
  82.                     this.contentRef.GetContent().
  83.                     Load<Texture2D>(this.name);
  84.                 
  85.             }
  86.  
  87.             return this.texture;
  88.         }
  89.  
  90.         set
  91.         {
  92.             this.texture = value;
  93.         }
  94.     }
  95.  
  96.     /// <summary>
  97.     /// Loads the selected texture.
  98.     /// </summary>
  99.     /// <param name="name">
  100.     /// Name of the texture to
  101.     /// load.</param>
  102.     public void Load(string name)
  103.     {
  104.         this.name = name;
  105.  
  106.         this.texture =
  107.             this.contentRef.GetContent().
  108.             Load<Texture2D>(name);
  109.     }
  110. }

What is serialized in the texture is the actual name of the texture, so afterwards we can load the name, and load the actual texture by request in the “get” field.  This makes for a simple method of loading the textures from xml, the only problem is a project can have many ContentManagers running, and we have no way of knowing which one is the one the texture is associated to. To get around this we create a IContentHolder interface.

Code Snippet
  1. /// <summary>
  2. /// Class that has a content manager.
  3. /// </summary>
  4. public interface IContentHolder
  5. {
  6.     /// <summary>
  7.     /// Returns the ContentManager
  8.     /// associated to this class.
  9.     /// </summary>
  10.     /// <returns>A ContentManager object.</returns>
  11.     ContentManager GetContent();
  12. }

The parent class that owns the texture implements this interface, and is required to pass itself to the texture as a reference upon creation. That way the steps when deserializing are as follows:

  1. When the serializer creates the parent class, the parent class creates the Texture2DProxy object and assigns itself as the ContentHolder.
  2. The deserializer fills the serialized data of the Texture2DProxy (the name of the texture),
  3. At some point, the game requests the texture for the first time, in the “get” field we see it’s not loaded yet, so we create it using the ContentManager of our parent, and we’re ready to go.