Home
Search
 
What's New
Index
Books
Links
Q & A
Newsletter
Banners
 
Feedback
Tip Jar
 
C# Helper...
 
XML RSS Feed
Follow VBHelper on Twitter Follow VBHelper on Twitter
 
 
 
MSDN Visual Basic Community
 
 
 
 
 
TitleMake a picture tiles jigsaw game in Visual Basic .NET
DescriptionThis example shows how to make a picture tiles jigsaw game in Visual Basic .NET.
Keywordsgraphics, algorithms, games, picture, tiles, image, DrawImage, jigsaw, puzzle, game, Visual Basic .NET, VB.NET
CategoriesGraphics, Graphics, VB.NET
 

This example is a game sort of like a jigsaw puzzle. You load a picture, which is broken into tiles. You need to put the tiles in their proper positions to rebuild the image.

The program draws a grid on the background showing where the tiles belong. It outlines unpositioned tiles in black. Once you place a tile in its correct position, it is locked in that position, moved to the back, and outlined in white.

The program is simpler than you might imagine. It uses a Piece class to represent the current and "home" location of each piece. The program keeps the pieces in a List(Of Piece) named Pieces.

To draw the board, the program draws the background grid and then just loops through the pieces drawing them.

Unfortunately drawing images seems to be relatively slow so the program didn't redraw fast enough when the user was moving a piece and there were a large number of pieces. Each time the mouse moved, the program needed to redraw every piece and it was taking too long.

To avoid this problem, the new design uses a background image. When you start moving a piece, the program makes an image of the background without the piece that you are moving. Then instead of redrawing every piece, it only needs to redisplay this background and then draw the piece you are moving in its current position.

Even that causes some delay building the background image when you first click on a piece and when you drop the piece. To fix that problem, the program makes an initial background image that contains all of the pieces. When you click on a piece, the program fixes the background by redrawing the pieces that overlap that piece's area.

That may seem difficult but it's actually pretty simple. The code just calls SetClip to set the Graphics object's clipping region and then redraws everything. SetClip only allows drawing within the region to appear. The code still "draws" everything but the graphics system can clip off parts that lie outside of the clipping region much faster than it can actually redraw the whole background image.

The following code shows the MakeBackground subroutine that updates the background image in the Rectangle rect.

 
' Make the background image without MovingPiece
' confined to the rectangle rect.
Private Sub MakeBackground(ByVal rect As Rectangle)
    Using gr As Graphics = Graphics.FromImage(Background)
        gr.SetClip(rect)
        MakeBackgroundOnGraphics(gr)
    End Using
End Sub
 
The code creates a Graphics object for the background image and uses SetClip to restrict drawing to the target area. It then calls MakeBackgroundOnGraphics to redraw everything.

The following code shows the MakeBackgroundonGraphics subroutine.

 
' Make the background image without MovingPiece.
Private Sub MakeBackgroundOnGraphics(ByVal gr As Graphics)
    ' Clear.
    gr.Clear(picPuzzle.BackColor)

    ' Draw a grid on the background.
    Using thick_pen As New Pen(Color.DarkGray, 4)
        For y As Integer = 0 To FullPicture.Height Step _
            RowHgt
            gr.DrawLine(thick_pen, 0, y, FullPicture.Width, _
                y)
        Next y
        gr.DrawLine(thick_pen, 0, FullPicture.Height, _
            FullPicture.Width, FullPicture.Height)

        For x As Integer = 0 To FullPicture.Width Step _
            ColWid
            gr.DrawLine(thick_pen, x, 0, x, _
                FullPicture.Height)
        Next x
        gr.DrawLine(thick_pen, FullPicture.Width, 0, _
            FullPicture.Width, FullPicture.Height)
    End Using

    ' Draw the pieces.
    Using white_pen As New Pen(Color.White, 3)
        Using black_pen As New Pen(Color.Black, 3)
            For Each a_piece As Piece In Pieces
                ' Don't draw the piece we are moving.
                If (a_piece IsNot MovingPiece) Then
                    gr.DrawImage(FullPicture, _
                        a_piece.CurrentLocation, _
                        a_piece.HomeLocation, _
                        GraphicsUnit.Pixel)
                    If (Not GameOver) Then
                        If (a_piece.IsHome()) Then
                            ' Draw locked pieces with a
                            ' white border.
                            gr.DrawRectangle(white_pen, _
                                a_piece.CurrentLocation)
                        Else
                            ' Draw locked pieces with a
                            ' black border.
                            gr.DrawRectangle(black_pen, _
                                a_piece.CurrentLocation)
                        End If
                    End If
                End If
            Next a_piece
        End Using
    End Using

    picPuzzle.Visible = True
    picPuzzle.Refresh()
End Sub
 
This code draws the grid on the background. It then loops through the pieces drawing each in its current position. How a piece is outlined depends on whether that piece is locked and whether the game is over.

The moral of the story is that SetClip can sometimes speed up drawing if you need to redraw a small part of a complex picture.

See the code for additional details.

There's still room for improvement.

  • Pieces with jigsaw-style edges rather than rectangles. That would let you fit pieces by shape and find the picture's edges.
  • Rotating pieces. That would be very advanced.
  • Pieces that stick together. When you join two pieces that belong together, it would be nice if they stuck so you could move them as a unit.
 
 
Copyright © 1997-2010 Rocky Mountain Computer Consulting, Inc.   All rights reserved.
  Updated