Introduction

This is my contribution to the CodeProject compact framework contest. (and my first CodeProject article !)

I always loved the original Puzzle Bobble game. It's simple, yet addictive. Many variants are playable on many platforms, but the only clones I saw for Pocket Pc were not free. So why not create a free and open source .Net compact framework variant of this famous game ? I started this project from scratch at the beginning of April, when I saw that CodeProject organized a contest, but at the end of April, it wasn't finished. It was functional, but did not have any graphics, and only had a random level generator... Happily, they extended the deadline, so I had time to improve the whole thing :). Anyway, a lot of things could be enhanced further more:

Better graphics (the launcher is not really finished, the bubbles are not so nice, the background...)

Some sound

Score management

A level editor

More levels (the sample levels were created with Notepad... it will be much more easy once the level editor is finished !)

Add some special bubbles (exploding bubbles, multi-color bubble, and so on...)

Perhaps use GAPI to improve animation speed (I did not have this opportunity with the emulator ...)

A cool network multi-player variant... (perhaps for v2.0, or v3.0 ;))

It's worth to be noted that I currently do not own a Pocket PC, I borrowed my boss' ppc at the beginning of the project (thank Patrick !) just to see if the animation speed would be decent, but after that I only used the emulator, so I hope that it will perform nicely on a 'real' pocket pc ! In the 'Menu' button on the game screen, you'll find a 'Constant frame rate' entry, uncheck it if the game is too slow...

Game rules

The main idea is based on the famous Puzzle Bobble game: the goal of the game is to destroy every bubble on the board. You have a limited time to launch a colored bubble on the board. The bubble will 'stick' on the first encountered bubble. If there's more than three bubble of the same color on the board, they explore, and every bubble that's not attached will fall as well. The ceiling will get down every 8 launched bubbles. You lose a live when a bubble reach the deadline (the red line).

Using the code

There's a class for each important part of the game:

BubbleGame : This is the main class of the game, it contain all the high-level features and game logic (most of it in the 'Go ' method)

Bubble : This class represents a bubble on the in-memory game board, it hold some useful info like the kind of bubble (its color), the position of the bubble on the game board, and the rectangle of the bubble on the screen (the position of the bubble sprite on the screen)

BubbleImages : In this class, you'll find some static methods and fields that act like a Bitmap cache of the Bubble images.

LauncherImages : Just like the BubbleImages class, this class act as a Bitmap cache for the Launcher bitmaps.

BubbleSprite : Represents a moving bubble (player bubble, falling and exploding bubbles), this class keeps track of the direction and speed of each bubble, as well as its position on screen and on the game board.

MovingSprites : This class will hold all the destroyed and falling bubbles while they are moving on screen.

GameBoard : This class represents the in-memory game board. It has methods for loading a level in memory, for detecting Player bubble collisions, detecting bubble neighbors and falling bubbles, as well as detecting if a bubble has reached the deadline. It has a method called 'CreateBoardBitmap ' that will create a bitmap from the in-memory game board (with complete background, walls, ceiling, and fixed bubbles). This bitmap is cached and used during the game (by the BubbleGame class) as the background, so we only have to draw the moving bubbles, not the fixed ones.

AngleHelper : This helper class is used to calculate the movement of the player bubble sprite from its angle and distance.

GraphicsHelper : This helper class contains static members used by various GDI+ methods (some of them are only used for testing purpose...)

GXInput : This class come from a MSDN sample game project, and is very useful to register all the hardware keys of the pocket pc. Otherwise, when you press an hardware key, an application could be started and appears on top of the game window...

Points of Interest

One of the first problem I had on this project, was to handle the key presses more accurately than the key related events of the winforms...

Happily, there's a function in 'coredll.dll' that satisfied this need:

This technique was used at the very beginning of this project, but meanwhile, I read a series of excellent articles on MSDN that talked about game development on Pocket PC with the .Net Compact Framework, and the author addressed another issue: intercepting the hardware keys. Those keys are like hot keys: they launch or activate an application directly. The feature is useful in day-to-day use, but is very annoying for games, because sometimes we want to use those keys for specific tasks. But we can't without some cumbersome DllImport and P/Invoke ... That's where the GXInput is useful: it comes from the sample game of a MSDN article (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetcomp/html/WrapGAPI3.asp) , and enable us to register the hardware keys, and use them in our application ! In fact the GXInput do more than registering keys, but since I added this library very lately in my project I did not use any other feature...

Otherwise, I had to work around a strange problem: in the Main game form, I wanted a menu to appears at the bottom left corner. The form itself was configured to fill the whole screen (MinimizeBox=false, MaximizeBox= false, WindowState= Maximized). Without the menu, the form was displayed as expected, but as soon as I added a menu, the window was no longer in fullscreen mode (the top title, and the Start menu appeared, even if I set the ControlBox as false...) I worked around this problem by adding a Button at the bottom-left corner of the form and by assigning a context menu that is displayed when we click on the button...

Level Design

The level design is saved as plain text file (I created a 'codeproject.lvl' sample file with ten levels), you can create your own levels by editing the sample file, or by creating new files (those files must have a .LVL extension), and they must be copied in the game directory. After that you can select the level file on the main menu.

Each line can have up to 8 numbers, and each level can have up to 10 lines (such a level is hard to finish, because the last line is very near the deadline !!!). In future releases, there will be a level editor that will enable you to create levels more easily...

How is it done ?

The GameBoard class contains an array of Bubble:

private Bubble[][] gameBoard = new Bubble[GRID_X_SIZE][];

Each Bubble has a kind (a color) and a position on grid, those bubbles are created in the LoadLevel method of the GameBoard class.

Each time a bubble is created, its position on grid is specified in the constructor, as well as its kind. From its position on the grid (the GameBoard), we can calculate its position on screen (the Rectangle containing the bubble on the game screen). The UpdateBubbleRectangle method of the Bubble class update this Rectangle if needed:

The on-screen position of the bubble is stored in a Rectangle with the following bounds:

The X position is calculated by multiplying the X GridPosition of the bubble (gridX) by the Width of the bubble (bubbleBitmap.Width), then adding the GameBoard X offset (the position of the gameboard on the screen), and finally adding half the width of a bubble only if this bubble is on an odd row.

The Y position is calculated by multiplying the Y GridPosition of the bubble (gridY) by the Height of the Bubble divided by a constant factor (bubbleBitmap.Height*GameBoard.ROW_DIST), so each row 'overlaps' a little bit the preceding row, and finally adding the GameBoard Y offset (this offset will change each time the ceiling fall by one row - that is, every 8 fired bubbles).

The width and height of the rectangle is simply the width and height of the bubble bitmap.

After a level is loaded and the gameboard is initialized, the CreateBoardBitmap() of the GameBoard class is called and returns a Bitmap object. This Bitmap is used as the 'full background' of the game, since it's made up of the 'simple background' (the ceiling, floor, walls, and background image) plus the images of the remaining bubbles of the current level. This 'full background' will only be refreshed if the player bubble hit another bubble and stick on the board, or if, after a collision, some bubbles pops out or fall.

On this 'full background' the launcher and the player sprite are drawn (as well as falling and destroyed bubbles). The player sprite is managed by the BubbleSprite class. This class has a BubbleRectangle property that returns the rectangle containing the bubble on screen. (just like the Bubble class, this property is used to know where to paint the sprite on screen). It also has a PositionOnGrid property that returns a Point which represents the position of the sprite on the GameBoard. (it's the opposite of the UpdateBubbleRectangle method of the Bubble class, and is primarily used in the collision detection routine)

This detection occurs each time the player bubble moves, but is done in two phases:

First, we need to know if there's one or more bubbles near the player bubble. This is done by obtaining the neighbors of the on-board bubble. This is where the PositionOnGrid method is used, as well as an helper method named GetNeighbors, from the GameBoard class, which returns an ArrayList of the neighbors bubbles.

Secondly, if there's at least one neighbor near the player bubble, we need to do a more accurate hit test between the player bubble and its neighbors. This is the role of the CheckSpriteCollision method of the GameBoard class.

This test is done by calculating the distance between the player sprite and its neighbors:

If the distance is less than a specific amount, the player bubble must be added on the gameboard.

After the player bubble is added to the gameboard, we need to test if this bubble is surrounded by at least two bubble of the same kind, if it's the case those bubbles must be destroyed. This test is done by the GetSameKindNeighbors method of the GameBoard class, by calling the GetNeighbors method for each bubble of the same kind as the player sprite. Once all the same kind neighbors bubbles of the player bubble are found, they are removed from the GameBoard and added to the MovingSprites collection. This collection is used to keep track of the falling or exploded bubbles, and to animate them.

If some bubbles were destroyed, we need to test if they leaved some 'floating' bubbles on the GameBoard. The 'floating' bubbles are detected by recursively calling GetNeighbors for each bubble of the first row and marking them as 'FallChecked', so we know that they must remain on the GameBoard. This is the role of the GetFallingBubbles() method of the GameBoard class. Every other bubble is removed from the GameBoard, and added to the MovingSprites collection, for the falling animation effect.

Beside this, there's nothing really special: double-buffer was used to prevent flicker (there's a lot of articles that detail the use of double-buffering technique, so I won't dive into it...), and GDI+ was used to draw the sprites on screen...

Last words...

I hope that i will have some time to finish this game, and add some cool features, like network multiplayer mode, or special kind of bubbles... I don't know when the v2.0 version will be out, if there's any! I developed this game with the emulator, as i don't own a real Pocket PC. That's why i entered this contest, hoping i would have a chance to win... (Seeing the awesome work of some other competitors, it will be very hard !). That's why i created a GotDotNet workspace at http://workspaces.gotdotnet.com/bobblenet. If you are interested and you have cool ideas, some graphics or code that you think useful to this project, join me !

And please, give me some feedback if you tested this game on a real Pocket PC, so i can fine-tune the code... Thanks !

Nice thing is that with .net you can look at the apps source code pretty easily to tell if it truely is just your source that is being sold. Of course since they are not giving out a demo, you would have to buy it to determine if its your source. But even if he just took your imiages, that is not right either.

Yeah, it's just that this "company" has had a history of selling unauthorized software. It's probably a one-man operation. At one point, they even tried to sell a PocketQuake 3 (which doesn't even exist and if it did would be id software license restriction). In the end we found out it was just PocketQuake 1 with a link to download the Shareware Pak files right off the porter's homepage.

Anyway, I just want to make sure that benoit authorized this. And if not, he can easily email handango and PVG both. I could email Handango myself and I have in the past. But after getting 6 games removed, it's someone else's turn to battle these thieves. :P

Plus, benoit is in a position to email PocketVisualGames directly and complain.

I agree with you. I just hate seeing people take code from a nice site like this and then go and sell it as their own. I was thinking of writing a "review" of the games on handango and pocketgear and put a link in to this article and say that I really enjoyed the free game.

I actually wish you would. I know I would not be happy if someone were to rip off my games. So I felt obligated in coming here to let it be known. To those interested and the author. I sent an email through codeproject.com to benoit about this all.

I figured he had the right to know if it's possible to contact him. Some of those who've been ripped it wasn't this easy.

Well I think I will wait for benoit to reply because if he did sell it to that person to sell as a game, I would not want to hurt their sales. I sell shareware too and I would not want someone to do that to me if I had sold it to someone else.

I appologize as my understanding of free source code vs public domain source code was not educated enough to me. I admit my misunderstanding, and my account has been closed permantly. I hae chosen not to pursue with pocket pc's and offer you my sincere appology for a misunderstanding. No revenue was made off of the clone, and the clone was closed immedialty. Again, this has been a learning expierence for me, and I have learned the difference between what you can use, and what you can not use.

From reading your article, your a very intelligent individual, and I hope someday to learn the techniques you are teaching. Thank you for your time, and God bless. -----------------

Definately incredible.... but this person has done this before and had accounts closed on him because of it. If you go to google and seach for the support email address you will find a page talking about this.

It is interesting to see that there were 6 downloads/sales from PocketGear and 4 on Handango and yet he had no demo version at all.

Glad this all worked out in the end. CodeProject is a great resource to get code examples from. not a place to take everything and then sell them as your own. At the very least he should have asked you.

Thanks a lot for all who voted for me ! I will continue to develop this game, now i will have the opportunity to test it on a real device !

I will first complete the graphics, then add a level editor and enable the customization of the keys used to control the launcher. After that i will certainly add a networked-multiplayer variant of the game (depending on my free-time !)

Its a nice game but its unplayable on the 2210 because of its small 5 way directional pad, moving it from left to right sometimes causes it to fire and keep on firing untill you release it, I think making it fire just once each time the up button is pressed would be better, and let us choose our fire button maybe the action button would be better.

I only had the emulator to test the game , but i will enhance it as soon as i have some time.I will add an option to customize the keys used during the game, as well as a level editor and more levels . Later i plan to add a networked-multiplayer mode with a bonus/malus system !

I developped this game and tested it on an emulator, since i did not have any real device, that's why i did not think about it...But now i won an Ipaq (big thanks to all !!), i will test it on a real device and enhance the game, but i don't know if i will add support for the stylus, since it would be too easy to set the fire direction ... An option would be to add some 'hot region' on the screen that would act like 'soft buttons' to change to direction and fire the ball ...

Yes ! I'm actually creating a new version that will include a level editor, and some sound, as well as updated graphics !But having not received many feedback, i don't know how the game performs on a real pocket pc ...

Thanks for your feedback, i'll add a scoring system very soon, and i'm currently developping the Level Editor ! I'll try to make this game runnable on a Smartphone , and will give the option to customize the keys used to control the launcher, as well as a 'soft button' (using the stylus ) option to provide even easier control ...

Actually, I find that the control works pretty well on the X5, except for when I accidentally press "up" while trying to rotate. On second thought, being able to remap that probably is a good idea.

As for scoring, I had some thoughts on that. I have been playing Super Bubble Pop on a couple of consoles, and my idea for scoring is a bit different. Instead of a "time bonus", the bonus should be in the number of moves. In otherwords, if you can clear the field in 10 launches, you should get a lot more points than with 20. Perhaps bonuses in-game for eliminating as many at one time as possible. In Super Bubble Pop, the score seems to weigh very heavy on the time bonus; I guess they figure if you figure out the "trick" to finishing the level in a few seconds, that's the main way you deserve any points. I dunno, I think some levels are too much work to only get a handful of points, then you get an "easy" level and use a trick to clear the board and get a ton of points -- just seems imbalanced.