Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WinForms

Simon: memory game from the eighties

4.36/5 (8 votes)
11 May 20073 min read 1   1.5K  
Simple memory game that uses shaped buttons
Screenshot - simon_game.jpg

Introduction

I wanted to be able to create non-rectangular buttons, just out of interest more than anything else. I had seen several complex versions on the web, but I thought I could come up with something simpler. Whilst trawling the web, I came across a flash version of Simon, which I enjoyed playing, so here is a recreation of it with my shaped buttons.

There is no sound, but if someone wants to add it, then please send me a copy of the updated code.

Shaped Button

This was achieved using the following steps:

  1. Add a new UserControl to your application.
  2. View the code and change the inherited type from UserControl to Button.
    C#
    public partial class simonButton : Button
    {
    public simonButton()
    {
    InitializeComponent();
    }
    } 
  3. The shape of the button is achieved through the use of two GraphicsPath objects. Declare these in the top of the button class.
    C#
    public partial class simonButton : Button
    {
    private GraphicsPath path;
    private GraphicsPath innerPath;
    
    ...
    The path denotes the outline of the button, while the innerPath denotes the shape of the flat surface of the button.
  4. Now override the OnPaint method of the button, to take care of the drawing, so that is looks like the following code.
    C#
    protected override void OnPaint(PaintEventArgs pevent)
    {
    Graphics g = pevent.Graphics;
    g.SmoothingMode = SmoothingMode.AntiAlias;
    }
    So that we do not get jagged curves, set the SmoothingMode to AntiAlias.
  5. The path object is filled with a LinearGradientBrush. This is simple to achieve by supplying a rectangle and a new LinearGradientBrush.
    C#
    // Create Rectangle To Limit brush area.
    Rectangle rect = new Rectangle(0, 0, 150, 150);
    
    LinearGradientBrush linearBrush =
    new LinearGradientBrush(rect,
    Color.FromArgb(40,40,40),
    this.ForeColor,
    225);
    Next we instantiate the path object.
    C#
    path = new GraphicsPath();
    Add items to the path object to create the required shape.
    C#
    path.AddArc(0, 0, 270, 270, 180, 90);
    path.AddArc(120, 0, 30, 30, 270, 90);
    path.AddLine(150, 0, 150, 85);
    path.AddArc(100, 100, 100, 100, -90, -90);
    path.AddLine(100, 150, 0, 150);
    path.AddArc(0, 120, 30, 30, 90, 90);
    path.AddArc(0, 0, 270, 270, 180, 90);
    Fill the path.
    C#
    g.FillPath(linearBrush, path);
    Finally, dispose of the brush to free memory.
    C#
    linearBrush.Dispose();
  6. The innerPath object is filled with a SolidBrush.
    C#
    Brush b = new SolidBrush(this.ForeColor);
    Next we instantiate the innerPath object.
    C#
    innerPath = new GraphicsPath();
    Add items to the innerPath object to create the required shape.
    C#
    innerPath.AddArc(10, 10, 250, 250, 180, 90);
    innerPath.AddArc(130, 10, 10, 10, 270, 90);
    innerPath.AddLine(140, 0, 140, 90);
    innerPath.AddArc(90, 90, 100, 100, -90, -90);
    innerPath.AddLine(90, 140, 10, 140);
    innerPath.AddArc(10, 130, 10, 10, 90, 90);
    Fill the innerPath.
    C#
    g.FillPath(b, innerPath);
    Finally, dispose of the brush to free memory.
    C#
    b.Dispose();
  7. So far, this draws our shaped button, but you can click anywhere in the associated rectangle, so to stop this, simply set the Region property of the button to path.
    C#
    this.Region = new Region(path);
    The button will now only accept clicks within the region of the shape.
  8. So that the user has some feedback that they are over a button, changing the cursor is a simple thing to do. Override the OnMouseEnter and OnMouseLeave methods and change the cursor within them.
    C#
    protected override void OnMouseEnter(EventArgs e)
    {
    this.Cursor = Cursors.Hand;
    base.OnMouseEnter(e);
    }
    
    protected override void OnMouseLeave(EventArgs e)
    {
    this.Cursor = Cursors.Arrow;
    base.OnMouseLeave(e);
    }
  9. The button also needs visual feedback that it has been pressed. In this case, the button wants to appear as if a light has come on behind it. This requires several new items and some changes to the code. First off, a boolean value is required to store if the click has happened so that it can be drawn in the correct state.
    C#
    private bool _clicked = false;
    public bool Clicked
    {
    get { return _clicked; }
    set
    {
    _clicked = value;
    Invalidate();
    }
    }
    Now override the OnMouseDown and OnMouseUp to set the Clicked state accordingly.
    C#
    protected override void OnMouseDown(MouseEventArgs mevent)
    {
    _clicked = true;
    base.OnMouseDown(mevent);
    }
    
    protected override void OnMouseUp(MouseEventArgs mevent)
    {
    _clicked = false;
    base.OnMouseUp(mevent);
    }
    Add a new brush.
    C#
    PathGradientBrush pgbrush = new PathGradientBrush(innerPath);
    pgbrush.CenterPoint = new Point(75, 75);
    pgbrush.CenterColor = Color.White;
    pgbrush.SurroundColors = new Color[] { this.ForeColor };
    Redraw the button according to the Clicked state.
    C#
    if (_clicked == false)
    {
    g.FillPath(linearBrush, path);
    g.FillPath(b, innerPath);
    }
    else
    {
    g.FillPath(linearBrush, path);
    g.FillPath(pgbrush, innerPath);
    }
    Remember to dispose of the brush correctly.

Using the code

Once you have built the application, just drop the control on a form. The buttons are a fixed size, so they are not scaleable. Again, if someone wants to improve on this please send me a copy of the code.

Game Logic

The game logic is fairly simple, so I will not write about that here, except to say that only sequences of 1000 are generated. My best score so far is 18, so I think 1000 is reasonable.

Have fun.

History

  • May 11, 2007 - Original version posted

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here