Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / multimedia / GDI+

Chess Piece Design In F#

4.18/5 (4 votes)
23 Oct 2015CPOL7 min read 15.5K   193  
This article describes the use of GDI+ in F# to design chess game pieces.

Image 1

Introduction

Usually, we use various graphics software to design game character or resources. But in this article, we will design Chess game pieces using F# language and GDI+ graphics library. Since F# is a .Net language, we can easily access the fantastic graphics library GDI+. GDI+ library has lots of classes and methods which are can be used to work with complex Vector and Raster graphics.

Main Window

Let's start with creating our MainWindow class that will represent the main window of our project. 

In F#, class definition begins with type keyword - 

F#
type MainWindow() = 
    inherit Form()

The MainWindow class inherits the System.Windows.Forms.Form class. So don't forget to open the following namespaces at the beginning of the program - 

F#
open System;
open System.Windows;
open System.Windows.Forms;

And these namespaces for using the GDI+ - 

F#
open System.Drawing;
open System.Drawing.Drawing2D;

We also have to add all the references for those namespaces through the Reference Manager of Visual Studio - 

Image 2

The Reference Manager of Visual Studio - 

Image 3

Then we create a initializer function in the MainWindow class and we set-up some property of the window - 

F#
member this.Init() = 
    this.Text <- "ChessPiece Design In F#"
    this.Size <- new System.Drawing.Size(550, 575)
            this.StartPosition <- FormStartPosition.CenterScreen
            //this.FormBorderStyle <- FormBorderStyle.Fixed3D
            this.MaximizeBox <- false
            this.BackColor <- System.Drawing.Color.FromArgb(255, 225, 235)

After initializing those properties, we will set the DoubleBuffer control style true to prevent flickering on repaint - 

F#
this.SetStyle(ControlStyles.DoubleBuffer, true)
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true)
this.SetStyle(ControlStyles.UserPaint, true)

// . . . . . . . 

Add a paint event handler for the window - 

F#
this.Paint.AddHandler(new Windows.Forms.PaintEventHandler(fun s pe -> this.Event_Paint(s, pe)))

Our paint event handler will be look like this - 

F#
member this.Event_Paint(sender : System.Object, e : PaintEventArgs) = 
    e.Graphics.SmoothingMode <- SmoothingMode.HighQuality
            e.Graphics.CompositingQuality <- CompositingQuality.HighQuality

          // Drawing codes . . . . .

Inside the program entry point function, we will create the window in this way - 

F#
let mainWindow = new MainWindow()

// Here we initialize our main window through calling this member function.
mainWindow.Init()

// Lets run our application
Application.Run(mainWindow)

The Application.Run method will run a standard application message loop until we wish to exit our program via the Close button.

Image 4

Now, we will load a chess board image file and we will draw it as a background of our main window. Just for making our project good looking. 

In the MainWindow class, we create a variable called board and we use null as its initial value - 

F#
let mutable board = null

Then inside the initializer function of the class, we load our chess board image by calling a static method called FromFile of GDI+ Image class and we assign the image into the board variable - 

F#
board <- Image.FromFile(".\ChessBoard.bmp")

And in the paint event handler, we draw the image using DrawImage method of Graphics class - 

F#
e.Graphics.DrawImage(board, 0, 0)

Image 5

Designing Chess Pieces

In chess game, there is six different type of pieces. King, Queen, Knight, Bishop, Rook and Pawn. 

We will use the Object-Oriented technique of F# for that purpose. That means we will create a class for each kind of pieces. class PieceRook, class PieceKing,  class PiecePawn etc. All the piece classes will inherit a class called ChessPiece

Let's see the definition of ChessPiece class - 

F#
type ChessPiece() = 

Using the let binding, we create private fields in a class. 

F#
let mutable bitmap = null
let mutable ofg = null

The bitmap and ofg are such private fields. We use null as their initial value cause we will initialize them through a member function call init

F#
member this.init() = 
        bitmap <- new Bitmap(100, 100)

We initialize the bitmap variable as a GDI+ Bitmap class object. We will use this Bitmap object to do off-screen drawing. 

In order to draw chess piece in the off-screen bitmap, we have to create a GDI+ Graphics object from the bitmap. We can do it via using a static member function called FromImage of Graphics class - 

F#
ofg <- Graphics.FromImage(bitmap) 

Actually, instead of drawing directly into the main window, we create a 100x100 off-screen Bitmap object for every pieces and we draw our chess pieces in the bitmap through the ofg Graphics object. Then we will draw all the bitmaps to the main window graphics. 

You may wonder that why we will use such technique?

Well, since we will draw our pieces through GDI+ lines, curve, ellipse etc objects. It will be very difficult for us to resize or move the pieces in later. So in this case, drawing into a bitmap has some advantage - 

  • We can easily resize our pieces through stretching the bitmap. 
  • We can also move pieces very easily. 

Let's see how - 

F#
member this.draw(g :System.Drawing.Graphics, x :int, y :int) = 

        let dest = new Rectangle(x, y, 82, 82) // x, y are position

        // Set the streching quality to high
        g.InterpolationMode <- InterpolationMode.HighQualityBicubic
        g.DrawImage(bitmap, dest, 0, 0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel)

The dest rectangle holds the value for the bitmap position and size. The original size of the bitmap was 100x100. But we stretched it to 82x82 to fit in the chess board image. We also set the InterpolationMode property to HighQualityBicubic so that our scaled image will be high quality. We will call the draw member function inside our main window paint event handler. 

Now, we have the ChessPiece class that will be inherited by our other piece classes. 

Let's implement the RookPiece class first - 

In F#, we inherit a class via the inherit keyword.

F#
type PieceRook() = 
    inherit ChessPiece() 

Then we implement a init member function inside the class in this way - 

F#
member this.init() = 
        base.init()

We call the init function of ChessPiece class to initialize the off-screen bitmap and the off-screen graphics through the base keyword. 

Now, we will draw our Rook piece in the off-screen graphics of ChessPiece class. Since the ofg field of ChessPiece class is private, we cannot access it in this way - 

F#
let g = base.ofg

So, we need a property called getGraphics inside the ChessPiece class to get access to the off-screen graphics object - 

F#
member this.getGraphics = ofg

Now we can use the property to get access to the off-screen graphics - 

F#
let g = base.getGraphics

We will use the GraphicsPath class of GDI+ to make the drawing easy - 

F#
let path = new GraphicsPath()

The GraphicsPath class is very helpful to draw series of connected lines and curves. We start drawing our rook by calling the GraphicsPath.StartFigure method - 

F#
path.StartFigure()

We will draw the Rook by adding lines and curves to the path - 

F#
path.AddCurve(ptsRookTop)
path.AddLines(ptsRook)

According to MSDN:

A figure that consists of a sequence of connected lines and curves (whose starting and ending points may be coincident) is an open figure, unless it is closed explicitly. A figure can be closed explicitly, by using the CloseFigure method, which closes the current figure by connecting a line from the ending point to the starting point. A figure that consists of a geometric shape primitive is a closed figure.

So, we close our figure explicitly by calling the GraphicsPath.CloseFigure method - 

F#
path.CloseFigure()

Since, our Rook figure is a closed shape, so we can easily fill it with LightGray color using Graphics.FillPath method - 

F#
g.FillPath(Brushes.LightGray, path)

We also draw border of the path to make the Rook nice. 

F#
g.DrawPath(Pens.Brown, path)

The pstRookTop and the ptsRook represents array of PointF structures declared inside the PieceRook class. The ptsRook points will make our Rook body and the pstRookTop points will make the top curve of the Rook piece. 

F#
// Points for rook body
let ptsRook = 
            [|
            PointF(20.0f, 23.0f)
            PointF(20.0f, 50.0f)
            PointF(32.0f, 50.0f)

            PointF(32.0f, 85.0f)
            PointF(15.0f, 85.0f)
            PointF(15.0f, 95.0f)
            PointF(80.0f, 95.0f)
            PointF(80.0f, 85.0f)
            PointF(63.0f, 85.0f)

            PointF(63.0f, 50.0f)
            PointF(75.0f, 50.0f)
            PointF(75.0f, 23.0f)
            |]

// Points for rook top curve
let ptsRookTop = 
            [|
            PointF(75.0f, 23.0f)
            PointF(57.0f, 27.0f)
            PointF(35.0f, 27.0f)
            PointF(20.0f, 23.0f)
            |]

In F#, we can create arrays in several ways. But in the above codes, we use the easiest array creation technique of F# language. Note that we use the 'f' suffix in every PointF construction argument value, since the PointF uses the floating type for X and Y fields. 

Now, for drawing the Knight piece, we will use lines and ellipse - 

Our KnightPiece class - 

F#
type PieceKnight() = 
    inherit ChessPiece()

The following PointF array represents our Knight piece body - 

F#
let ptsKnight =
        [|
        PointF(72.0f, 95.0f)
        PointF(15.0f, 95.0f)
        PointF(15.0f, 80.0f)
        PointF(30.0f, 80.0f)

        PointF(38.0f, 60.0f)
        PointF(20.0f, 62.0f)
        PointF(16.0f, 58.0f)
        PointF(23.0f, 53.0f)
        PointF(14.0f, 56.0f)
        PointF(14.0f, 50.0f)
        PointF(35.0f, 32.0f)
        PointF(34.0f, 26.0f)
        PointF(39.0f, 23.0f)

        PointF(58.0f, 27.0f)
        PointF(58.0f, 80.0f)
        PointF(72.0f, 80.0f)
        |]

Then we add all the points to a GraphicsPath object and we fill and draw the path with LightGray and Brown color - 

F#
member this.init() =
    base.init()

    let g = base.getGraphics

    let path = new GraphicsPath()

    path.StartFigure()

    path.AddLines(ptsKnight)

    path.CloseFigure()

    g.FillPath(Brushes.LightGray, path)
    g.DrawPath(Pens.Brown, path)

We add a simple eye to our Knight piece - 

F#
g.FillEllipse(Brushes.White, 35, 37, 7, 7)
g.DrawEllipse(Pens.Brown, 35, 37, 7, 7)

g.FillEllipse(Brushes.Black, 35, 39, 4, 4)

To draw Bishop, we use 4 PointF array which represent the Bishop body - 

F#
type PieceBishop() = 
    inherit ChessPiece()

    let ptsBishop = 
            [|
            PointF(51.0f, 64.0f)
            PointF(53.0f, 80.0f)

            PointF(67.0f, 80.0f)

            PointF(67.0f, 95.0f)

            PointF(20.0f, 95.0f)
            PointF(20.0f, 80.0f)
            PointF(36.0f, 80.0f)
            PointF(38.0f, 64.0f)
            |]

    let ptsBishop2 = 
        [|
        PointF(38.0f, 64.0f)
        PointF(26.0f, 56.0f)
        PointF(28.0f, 44.0f)
        |]

    let ptsBishop3 = 
        [|
        PointF(28.0f, 44.0f)
        PointF(42.0f, 53.0f)
        PointF(42.0f, 47.0f)
        PointF(30.0f, 40.0f)
        PointF(42.0f, 22.0f)
        |]

    let ptsBishop4 = 
        [|
        PointF(42.0f, 22.0f)
        PointF(60.0f, 46.0f)
        PointF(51.0f, 64.0f)
        |]

    member this.init() = 
        base.init()

        let g = base.getGraphics

        let mutable path = new GraphicsPath()

        path.StartFigure()

        path.AddLines(ptsBishop)
        path.AddCurve(ptsBishop2)
        path.AddLines(ptsBishop3)
        path.AddCurve(ptsBishop4)

        path.CloseFigure()

        g.FillPath(Brushes.LightGray, path)
        g.DrawPath(Pens.Brown, path)

        g.FillEllipse(Brushes.Red, 38, 20, 8, 8)
        g.DrawEllipse(Pens.Blue, 38, 20, 8, 8)

We draw the King piece by adding lines to two GraphicsPath object - 

F#
type PieceKing() = 
    inherit ChessPiece()

This points represents the top Cross of King piece - 

F#
let ptsKingTop =
         [|
         PointF(45.0f, 30.0f)
         PointF(45.0f, 24.0f)
         PointF(39.0f, 24.0f)
         PointF(39.0f, 19.0f)
         PointF(45.0f, 19.0f)
         PointF(45.0f, 14.0f)
         PointF(51.0f, 14.0f)
         PointF(51.0f, 19.0f)
         PointF(57.0f, 19.0f)
         PointF(57.0f, 24.0f)
         PointF(51.0f, 24.0f)
         PointF(51.0f, 30.0f)
         |]

And the following points represents the body of King - 

F#
let ptsKing =
        [|
        PointF(15.0f, 30.0f)

        PointF(20.0f, 55.0f)
        PointF(40.0f, 55.0f)

        PointF(30.0f, 80.0f)
        PointF(15.0f, 80.0f)

        PointF(15.0f, 95.0f)
        PointF(80.0f, 95.0f)

        PointF(80.0f, 80.0f)
        PointF(65.0f, 80.0f)

        PointF(55.0f, 55.0f)
        PointF(75.0f, 55.0f)

        PointF(80.0f, 30.0f)
        |]

member this.init() =
    base.init()

    let g = base.getGraphics

Since we need two GraphicsPath object, so better we create mutable object - 

F#
let mutable path = new GraphicsPath()

Add the top shape to the path - 

F#
path.StartFigure()
path.AddLines(ptsKingTop)
path.CloseFigure()

Draw it to the off-screen graphics - 

F#
g.FillPath(Brushes.Blue, path)
g.DrawPath(Pens.Yellow, path)

Create a new GraphicsPath object and add the body shape points to the new path -

F#
path <- new GraphicsPath()

path.StartFigure()
path.AddLines(ptsKing)
path.CloseFigure()

Then draw it to the off-screen graphics - 

F#
g.FillPath(Brushes.LightGray, path)
g.DrawPath(Pens.Brown, path)

The following class represents our Queen piece - 

F#
type PieceQueen() = 
    inherit ChessPiece()

The following PointF array builds our Queen piece - 

F#
let ptsQueen =
        [|
        PointF(23.0f, 30.0f)

        PointF(23.0f, 55.0f)
        PointF(40.0f, 55.0f)

        PointF(35.0f, 80.0f)
        PointF(15.0f, 80.0f)

        PointF(15.0f, 95.0f)
        PointF(80.0f, 95.0f)

        PointF(80.0f, 80.0f)
        PointF(60.0f, 80.0f)

        PointF(55.0f, 55.0f)
        PointF(73.0f, 55.0f)

        PointF(73.0f, 30.0f)
        |]

Then we implement the init function to add the PointF array to a GraphicsPath object and we fill the path with LightGray color and we also draw its border by calling DrawPath method of GraphicsPath class - 

F#
member this.init() =
    base.init()

    let g = base.getGraphics

    let path = new GraphicsPath()

    path.StartFigure()
    path.AddLines(ptsQueen)
    path.CloseFigure()

    g.FillPath(Brushes.LightGray, path)
    g.DrawPath(Pens.Brown, path)

    g.FillEllipse(Brushes.Orange, 24, 22, 8, 8)
    g.DrawEllipse(Pens.Brown, 24, 22, 8, 8)

    g.FillEllipse(Brushes.Orange, 40, 22, 6, 6)
    g.DrawEllipse(Pens.Yellow, 40, 22, 6, 6)

    g.FillEllipse(Brushes.Orange, 50, 22, 6, 6)
    g.DrawEllipse(Pens.Yellow, 50, 22, 6, 6)

    g.FillEllipse(Brushes.Orange, 65, 22, 8, 8)
    g.DrawEllipse(Pens.Brown, 65, 22, 8, 8)

    g.FillEllipse(Brushes.Red, 43, 12, 10, 10)
    g.DrawEllipse(Pens.Blue, 43, 12, 10, 10)

Here is our PiecePawn class implemention. We draw the Pawn by adding lines to a GraphicsPath object and drawing rectangles and ellipses  - 

F#
type PiecePawn() = 
    inherit ChessPiece()

The following PointF array represents the triangle shape of our Pawn - 

F#
let ptsPawn = 
                [|
                PointF(68.0f, 80.0f)
                PointF(30.0f, 80.0f)
                PointF(48.0f, 30.0f)
                |]

Then we draw the triangle by adding the points array to a GraphicsPath obejct - 

F#
let g = base.getGraphics
let mutable path = new GraphicsPath()

path.StartFigure()
path.AddLines(ptsPawn)
path.CloseFigure()

g.FillPath(Brushes.LightGray, path)
g.DrawPath(Pens.Brown, path)

g.FillRectangle(Brushes.LightGray, 18, 80, 62, 15)
g.DrawRectangle(Pens.Brown, 18, 80, 62, 15)

g.FillEllipse(Brushes.Yellow, 36, 22, 26, 26)
g.DrawEllipse(Pens.DarkOrange, 36, 22, 26, 26)

// Left eye

g.DrawLine(Pens.Brown, 42, 26, 47, 29)

g.FillEllipse(Brushes.LightGreen, 42, 30, 6, 6)
g.FillEllipse(Brushes.Black, 43, 32, 4, 4)
g.DrawEllipse(Pens.Pink, 42, 30, 6, 6)

// Right eye

g.DrawLine(Pens.Brown, 57, 26, 51, 29)

g.FillEllipse(Brushes.LightGreen, 50, 30, 6, 6)
g.FillEllipse(Brushes.Black, 51, 32, 4, 4)
g.DrawEllipse(Pens.Pink, 50, 30, 6, 6)

path <- new GraphicsPath()

let ptsMouth =
        [|
        PointF(45.0f, 41.0f)
        PointF(47.0f, 39.0f)
        PointF(53.0f, 41.0f)
        |]

path.AddLines(ptsMouth)

g.DrawPath(Pens.Brown, path)

After creating all the pieces, we create objects for each class in our main window class - 

F#
type MainWindow() = 
    inherit Form()

    let rook = new PieceRook()
    let knight = new PieceKnight()
    let bishop = new PieceBishop()
    let king = new PieceKing()
    let queen = new PieceQueen()
    let pawn = new PiecePawn() 

In the main window init member function, we call the init member function of every ChessPiece object - 

F#
rook.init()
knight.init()
bishop.init()
king.init()
queen.init()
pawn.init()

And finally, we draw our pieces in the main window paint event handler by calling the draw member function of ChessPiece class - 

F#
member this.Event_Paint(sender : System.Object, e : PaintEventArgs) = 

        e.Graphics.SmoothingMode <- SmoothingMode.HighQuality
        e.Graphics.CompositingQuality <- CompositingQuality.HighQuality

        rook.draw(e.Graphics, 135, 125)
        knight.draw(e.Graphics, 265, 125)
        bishop.draw(e.Graphics, 197, 187)
        king.draw(e.Graphics, 135, 247)
        queen.draw(e.Graphics, 260, 247)
        pawn.draw(e.Graphics, 194, 310)

Points of Interest

I think this article would be a good practice for us to learn both GDI+ and F# language. 

Conclusion

In conclusion, I just want to say that, this article may not shows the best technique of designing chess game pieces through programming. But surely, you can learn the advance use of GDI+ in F# language. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)