Sign in to follow this  
Nali

[.net] C# Windows Forms Memory game design questions.

Recommended Posts

Greetings all, I´m about to write a Memory game in C# with Windows forms but I need some guidance about code design choices. First, since I´m new with coding C# Window Forms programs .. what is the correct method of letting classes modify Windows objects (labels, buttons etc). Making a handle to the Form1 when creating the Game class should allow Game class to modify objects but is this the "right way"? Another issue I´m thinking about is where the Image/Bitmap objects should be created and maintained.. I´m using another custom game class that holds some variables (x/y position, state etc). Can Image/Bitmap objects within this Memory block class be written and updated on Form1 without too much hassle? Thanks in advance. [Edited by - Nali on March 29, 2010 2:27:02 PM]

Share this post


Link to post
Share on other sites
The short answer is you don't.

Now for the long answer. You create public methods on your form to do the actions you need to do.

public void Move_Image(int amount_x, int amount y, string image_name)

That would move the named image a certain amount along the x and y axis.

The method on the form would make sure they are not moved off the screen, and that the image is a valid image to move.

So that is what I would call the "right" way.

theTroll

Share this post


Link to post
Share on other sites
Some kind of custom event handler then :).

How about the second part?
I´m very unsure on how to approach this. Create the PictureBox/Image objects in form.cs and make a handle/id-tag them to the MemoryBlock objects? or create them in the objects (with a handle to form.cs so they can access surface to be drawn 2)?

Share this post


Link to post
Share on other sites
Regarding both of your problems: you should split the visuals from the logic. The rules of the game don't change, no matter if you're playing it as a win forms app or in a console window, right? Clearly, the logic and the visual representation are two concerns. As such, you should split them in your code as well.

As a general guideline: split your solution into two projects, let's say Memory.Rules (a DLL) and Memory.UI (a winforms app). Memory.Rules should not have to reference System.Windows.Forms or System.Drawing at all, because those are related to visuals. Memory.UI on the other hand should only contain code related to visuals, that is forms and controls etc.

Your Game certainly class goes into Memory.Rules. It could have methods such as void TurnOverCard(int x, int y) or bool IsTurnedOver(int x, int y) and these methods deal with all the rules related to memory as an abstract game concept. You could then add an event to Game such as

public event EventHandler StateChanged;

that you raise whenever something important changes (time, score, turned over cards etc.) Your win form (which is responsible for drawing the board) can subscribe to this event and react accordingly (redraw the affected parts etc.). This pattern is referred to as Observer Pattern. Of course, other ways of achieving this decoupling are possible, e.g. MVC

Likewise, managing the bitmaps belongs to the UI. Maybe you can create a class Card in your Memory.Rules project that holds information about a card (position and e.g. a name such as "Cat", "Dog"). In your UI project, you could create a user control that represents a card/buttom. When you create the form with all the card buttons, pass each card button the Card object that it represents and have it load the bitmap based on the name of the card ("Cat"=> "Cat.jpg" or so). Of course that would cause all bitmaps to be loaded twice. So you could go a step further and create a "BitmapManager" class. You pass it the name of a card and it returns the appropriate bitmap (that it loads once the first time it is requested). This can be as simple as this:

public class BitmapManager : IDisposable {
private Dictionary<string, Bitmap> images = new Dictionary<string, Bitmap>();

public Bitmap GetBitmap(string name){
Bitmap bitmap;
if(!images.TryGetValue(name, out bitmap)){
bitmap = LoadBitmap(name);
images.Add(name, bitmap);
}
return bitmap;
}

Bitmap LoadBitmap(string name)[
string fileName = Path.Combine("images", string.Format("{0}.jpg", name));
return new Bitmap(fileName);
}

public void Dispose(){
foreach(var bmp in images.Values){
bmp.Dispose();
}
images.Clear();
}
}



Now the BitmapManager is the owner of the bitmaps.

So, in general don't try to combine completely different concerns in the same class. Have a look at the Single Responsibility Principle (and the other OOP principles). Hope that helps :-)

Have fun!

Share this post


Link to post
Share on other sites
^^^ THIS. Totally this.
You can ignore that advice (and it is an AWESOME learning experience) but it will get painful to maintain in the long run.

For drawing in WinForm land I usually lay off the Controls (PictureBoxes, etc) and create a custom control where I draw everything via the GDI+ objects and an override of OnPaint and OnPaintBackground(){/*do nothing/*}.
This is probably because I like to have a bit more freedom in the long run.
However for something incredibly simple (like your memory game might be) just doing it all with WinForm controls might be the quickest option.

Share this post


Link to post
Share on other sites
I choosed to walk the right way :P , separating game code from gui code. In a small game like this it wont mather but its a good thing to learn how to do this early, might be good experience for bigger projects.

And I´m done with the game :), only have 1 strange issue now; Memory wont be released when creating new games (in the same session). The game consumes a little bit of RAM every new game that is run and I dont really know where the problem is. I´ve implemented IDisposable and calls it from my objects. =/

Share this post


Link to post
Share on other sites
Unless there is a "leak", is usually due to hanging events. Try constructing and disposing a bunch of game instances, then call GC.Collect(). If the memory usage continues to rise even after the GC runs, you probably have some references that need to be cleaned up.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this