Porting Match'em Poker's Qt version to Windows Phone 7 XNA
Match'em Poker XNA is a port from Match'em Poker that was implemented on top of the Qt GameEnabler. This page describes observations and issues faced during the port.
This is the second port done for Match'em Poker since it was originally written for iOS (iPhone) and the Qt version is ported from that one.
The aim was to copy the features and overall feeling of the application faithfully from the original version with a minimal amount of work, thereby studying XNA framework's possibilities.
Technologies used
XNA Framework, SpriteBatch
Porting
The project was started by getting the WP7 SDK. The installation didn't cause any problems with the already installed Visual Studio C++ express.
The Qt version of Match'em Poker doesn't have many game-specific source files.
In all phases, the code was compiled from time to time to make sure everything was working and the project was going forward.
Step by step
- A new XNA project was created with the Wizard's functionality.
- C++ header files were renamed to .cs and added into this new project.
- New .cs - files were edited from C++ to C#. At this phase, the .cs files didn't contain more than members of classes and empty implementations for all the methods. If a nontrivial error was discovered (for example, using a pointer), it was left to the todo phase and modified just a little bit to make the code compile.
- Piece by piece, without checking if the logic actually works, functionalities of methods were copied; method by method. The code was always modified as little as possible, just enough to make it compile again. This was definitely the most time-consuming part of the porting project.
- In Match'em Poker, 'platform-dependent' functionality (for example, rendering) is mapped through an interface called ITileRenderer. When the port from iOS to Qt was done, this was the most work-consuming part to rewrite. After that, most of the functionality worked as expected. iOS and Qt (with Qt GameEnabler) both use OpenGL ES 2.0, but in XNA this wasn't possible. The decision was made to use XNA's object SpriteBatch for OpenGL Es 2.0 replacement since the original idea of rendering 'tiles' is very similar to sprites.
- TileRendererXNA was derived from ITileRenderer and platform-dependent parts were implemented. Some platform-dependent method calls were added to the game itself to make SpriteBatch work (this required beginFrame and endFrame calls).
- Graphics were added to the project with SDK's own content system. The original Match'em Poker images are PNG files so this was very simple.
- New SpriteBatch -based rendering was tested with temporary code to make sure that the results are similar with OpenGL ES 2.0 rendering.
- When most of the code was in place and in a state where something might work, the debugging started. The flow of the program was followed to find places where logic failed because of the port. All of the parts left at unknown state were also fixed part by part when their functionality was required.
- The original space (window size) of the game was 65536x116508 since everything was done with fixed points. The scale was changed to 1x1.66 since fixed points were removed and replaced with floats. This was initially done by 'just' dividing all of the constants with 65536 and adding typecasts to floats when required.
- Constants divided by 65536 were calculated open to make the code cleaner. At the same time, lots of constants were added to give these 'hat values' more meaning.
- Sounds were added to the project and the platform-dependent method EffectNotify was overridden from TileRendererXNA to play sounds when something happends.
- Next, the working game was tested over and over again. Encountered bugs were fixed and code cleaned when something messy was found.
- When the project was in good enough shape, a package was built and published.
Loading and saving
The original code used FILE* handles for loading and saving the files since they are supported in all of the C/C++ environments. The actual storing was done (quite messily) by storing 11*4 bytes from the beginning of the first member to be saved. All of the members to be saved were ordered after the first one.
In XNA, IsolatedStorage was used and the overall system became quite similar with the difference that each member is stored separately using BinaryWriter for the file stream:
Original code:
int CTileNpc::save() {
FILE *file = fopen(SAVE_FILE, "wb" );
if (!file) return 0;
fwrite( &m_difficulty, 1,11*sizeof(int), file );
if (m_gameIsOn==1) m_level->saveToFile( file );
fclose(file);
return 1;
}
XNA code:
public override bool Save()
{
IsolatedStorageFile IS = IsolatedStorageFile.GetUserStoreForApplication();
try
{
using (IsolatedStorageFileStream IS_FS = IS.CreateFile("mpok.dat"))
{
using (BinaryWriter bw = new BinaryWriter(IS_FS))
{
bw.Write(m_difficulty);
bw.Write(m_blockTimerEffect);
bw.Write(m_timeTimerEffect);
bw.Write(m_currentLevel);
bw.Write(m_targetTimer);
bw.Write(m_timer);
bw.Write(m_score);
bw.Write(m_displayScore);
bw.Write(m_highScore);
bw.Write(m_gameIsOn);
bw.Write(m_waitBeforeTimerStartsTime);
if (m_gameIsOn == 1)
{
m_level.SaveToFile(bw);
}
}
}
}
catch (IsolatedStorageException e)
{
return false;
}
return true;
}
The level loading and saving is done accordingly, storing each index of the grid into the file stream:
public void saveToFile( BinaryWriter bw )
{
for (int i = 0; i < m_gridWidth * m_gridHeight; i++)
{
bw.Write(m_grid[i].index);
}
}
Rendering
Since everything was rendered with !OpenGL's triangle-fans forming single quads, it was relatively easy to switch the rendering to a SpriteBatch-based solution. The only modification to the interface was that SpriteBatch required start and end calls which were done by the runner framework in the original application. !OpenGL rendering allowed the user to choose if blending should be additive or alpha. This option was removed from the SpriteBatch version since only one type can exist in a single begin/end pair. The original images were slightly modified to give an 'additive blending'-type look to the sprites which were meant to be rendered that way.
Content
Both the graphics and the sounds were automatically processed by XNA's content pipeline. After adding, the contents were accessible with XNA's own loading functions for both items. This was the easiest system to use I've ever encountered.
Conclusion
This was my first C# project, as well as my first project using XNA. There might have been better ways to do the porting, but I didn't have very much time and just had to start working without thinking too much. In my opinion, overall, the porting was very successful: I even managed to clean the code and add comments while porting. I found C# to be very easy for a C++ developer. One only needs to 'adjust' a couple of hardwired habits and then just code.
Working with XNA framework for Windows Phone 7 is easy and straightforward. Everything that this project used worked nicely in the emulator and in the actual device. Debugging was surprisingly easy and worked well. C# was so similar to C++ that the differences are almost unnoticeable after using C# for a while.
For me personally, the most difficult thing was to trust the underlying framework without knowing exactly what it is doing. Also, I found the idea of being placed in a 'sandbox' somehow limiting even though the limits weren't reached in this project.

