Make the basis for a card game in C#

[card game]

The goal of this example is to provide some support for building a card game. It shows how to make a class to represent cards and to to tell what card is displayed in a PictureBox. It’s actually relatively straightforward.


The following code shows the Card class.

public class Card
{
    public int Rank, Suit;
    public Bitmap Picture;

    public Card(int rank, int suit, Bitmap picture)
    {
        Rank = rank;
        Suit = suit;
        Picture = picture;
    }
}

The class first defines the Rank and Suit properties. For this example I’ve made them numeric. Rank will be between 0 (Ace) and 12 (King).

Suit will be 0 and 4 and will represent hearts, diamonds, clubs, spades, and other. The suits are in that order because that’s the order in which they appear in the image file cards.png. You could rearrange them if you like.

The last Suit value holds the card backs and other miscellaneous images that might be used by a card game. The cards.png image doesn’t include jokers, but this is where you would put them if you wanted them.

The following code shows the variables that the program uses to store card information.

// Basic deck information.
// The 5th suite is for the back, jokers, etc.
private const int NumSuits = 5;
private const int NumRanks = 13;
private int CardWidth, CardHeight;

// The suits in their order in the file.
private enum Suits
{
    Hearts,
    Diamonds,
    Clubs,
    Spades,
    Misc,
}

// PictureBoxes holding card images.
private PictureBox[,] Pics = null;

The values NumSuits and NumRanks hold the numbers of suits and ranks. The fields CardWidth and CardHeight will later hold the dimensions of the card images.

The Suits enumeration makes it easier to map indexes to suits.

The Pics array will hold PictureBox controls holding the cards.

When the program starts, the following Load event handler loads the card data.

// Load the cards.
private void Form1_Load(object sender, EventArgs e)
{
    // Load the card images.
    LoadCardImages();

    // Arrange the card PictureBoxes.
    ArrangeCards();
}

This code simply calls the LoadCardImages and ArrangeCards methods. The following code shows LoadCardImages.

// Load the card PictureBoxes.
private void LoadCardImages()
{
    CardWidth = Properties.Resources.cards.Width / NumRanks;
    CardHeight = Properties.Resources.cards.Height / NumSuits;
    int x0 = 0;
    int y0 = 0;
    int dx = CardWidth;
    int dy = CardHeight;
    Pics = new PictureBox[NumRanks, NumSuits];
    int y = y0;
    for (int suit = 0; suit < NumSuits; suit++)
    {
        int x = x0;
        for (int rank = 0; rank < NumRanks; rank++)
        {
            Pics[rank, suit] = LoadCard(rank, suit, x, y);
            x += dx;
        }
        y += dy;
    }
}

The resource Properties.Resources.cards holds the image of all of the cards. This method uses it to get the cards’ widths and heights. It then allocates the Pics array and loops through the image to get the individual card images.

As it moves through the rows and columns of card images, the code keeps track of its position in the main image and calls the LoadCard method to load each of the cards.

The following code shows the LoadCard method.

// Load a single card from the deck.
private PictureBox LoadCard(int rank, int suit, int x, int y)
{
    // Get the image.
    PictureBox pic = new PictureBox();
    Bitmap bm = LoadCardImage(rank, suit, x, y);

    // Make the PictureBox.
    pic.Image = bm;
    pic.SizeMode = PictureBoxSizeMode.AutoSize;
    pic.BorderStyle = BorderStyle.Fixed3D;
    pic.Parent = panCards;
    pic.MouseEnter += pic_MouseEnter;
    pic.MouseLeave += pic_MouseLeave;

    // Give the PictureBox a Card object so
    // we can tell what card it is.
    pic.Tag = new Card(rank, suit, bm);

    return pic;
}

This method creates a new PictureBox to hold the card. Depending on what your card game is going to do, you may not want to create a PictureBox for each card. For example, you might want to just create Card objects to represent the cards. Then you can display them in PictureBoxes later. This example just loads the images and displays them in separate PictureBox controls so it’s not really a card game at all.

After it creates the PictureBox, the method calls LoadCardImage to load the image for the card. It then sets various PictureBox properties including its Image, SizeMode, and BorderStyle. It sets the Parent to the Panel control named panCards. That control has AutoScroll = True so it displays scroll bars if the PictureBox controls inside it don’t fit in its visible area.

Finally the method sets the PictureBox control’s Tag property equal to a Card object that holds the card’s information. Later the program can use the Tag object to see what card the PictureBox represents.

The following code shows the LoadCardImage method.

// Return the image for a card.
private Bitmap LoadCardImage(int rank, int suit, int x, int y)
{
    Bitmap bm = new Bitmap(CardWidth, CardHeight);
    using (Graphics gr = Graphics.FromImage(bm))
    {
        Rectangle dest_rect =
            new Rectangle(0, 0, CardWidth, CardHeight);
        Rectangle src_rect =
            new Rectangle(x, y, CardWidth, CardHeight);
        gr.DrawImage(Properties.Resources.cards,
            dest_rect, src_rect, GraphicsUnit.Pixel);
    }

    return bm;
}

This method creates a Bitmap to hold the card’s image and makes an associated Graphics object. Next it makes a rectangle that fills the new bitmap.
It also makes rectangles that identifies the location where the image should be copied from the big bitmap containing all of the card images. Finally the code copies the card’s image from the big bitmap into the new bitmap and returns it.

The following code shows the ArrangeCards method.

// Arrange the card PictureBoxes.
private void ArrangeCards()
{
    // Display the deck.
    const int margin = 4;
    int y = margin;
    for (int suit = 0; suit < NumSuits; suit++)
    {
        int x = margin;
        for (int rank = 0; rank < NumRanks; rank++)
        {
            Pics[rank, suit].Location = new Point(x, y);
            x += Pics[0, 0].Width + margin;
        }
        y += Pics[0, 0].Height + margin;
    }
}

This method simply loops through the PictureBox controls in the Pics array and positions the controls in rows and columns within the Panel.

The final pieces of the program include the following event handlers, which execute when the mouse enters or leaves a PictureBox.

// Display the card's information.
private void pic_MouseEnter(object sender, EventArgs e)
{
    // Get the card information.
    PictureBox pic = sender as PictureBox;
    Card card = pic.Tag as Card;
    Suits suit = (Suits)card.Suit;
    int rank = card.Rank + 1;
    Text = rank.ToString() + " of " + suit.ToString();
}

// Clear the cardf information.
private void pic_MouseLeave(object sender, EventArgs e)
{
    Text = "howto_playing_cards";
}

The pic_MouseEnter event handler converts the sender object into the PictureBox that raised the event. It then gets the control's Tag property and converts it into a Card object. The event handler finishes by displaying the Card object's rank (plus 1) and suit in the form's title bar.

The pic_MouseLeave property simply resets the form's title bar so it displays the program's name instead of whatever card the mouse last passed over.

The Card class and the technique of storing Card objects in a PictureBox control's Tag property should help you get started making a card game.


Download Example   Follow me on Twitter   RSS feed   Donate




About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.
This entry was posted in games, graphics, image processing, puzzles and tagged , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *