Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Guess My Drawing!

0.00/5 (No votes)
9 Jan 2013 4  
A Windows Forms application to share a whiteboard with many clients with only one drawer, in a gamy way.

Introduction

This piece of code represents a windows application, it is basically a whiteboard sharing service between users using another code as a server; it consists of a whiteboard that’s shared between many people, one as a drawer and the others as guessers. The drawer is the guy who can draw on the white board, while the guessers are the people who receive the drawings and try to guess it. The first one, the drawer, writes a word describes what he’s drawing, without the guessers knowing it, then he starts to draw and the guessers try to guess the drawing, and the games goes on. The code is coded using C# and data are transferred using UDP.

Clients can log in by choosing any name they like and the server's IP. 

Using the code 

There're two code files, the server and the client one.

The Server:

It's a console application that adds clients to its list, and receives UDP messages from clients analyse them and forward/unforward them to other clients. For example, if a guesser guessed a word, other guessers will be notified of this in a text box, another example is the secret word of the drawing, it will not be forwarded to other clients but kept in the server to be checked with each guess.

The Client: 

This solution has two classes, the windows from class, and the panel class.

The windows form class is called Form1, a silly name! But it kinda meant something as it was my first C# project.

Anyway, the class consists of four methods to capture the clicks of the four buttons in the interface.

And it has two background threads, read() and DrawOnPanel().

First the read() method, it is for reading from the UPD connection after the user joins as a drawer or guesser.

public void read()
{
    Thread t = new Thread(new ThreadStart(delegate
    {
        while(!abortThreads)
        {
            IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
            byte[] data = {0};
            try
            {
                data = client.Receive(ref remoteEP);
                msg = Encoding.ASCII.GetString(data, 0, data.Length);

            }
            catch (SocketException e)
            {
                abortThreads = true;
            }

            if (msg.StartsWith("draw"))
            {
                msg = msg.Substring(5);
                int xVal = 0, yVal = 0;
                for (int i = 0; msg.Length - 1 > 0; i++)
                {
                    if (msg.Substring(i, 1) == "y")
                    {
                        xVal = Int32.Parse(msg.Substring(0, i));
                        msg = msg.Substring(i + 1);
                        i = 0;
                    }

                    if (msg.Substring(i, 1) == "x")
                    {
                        yVal = Int32.Parse(msg.Substring(0, i));
                        msg = msg.Substring(i + 1);
                        toDraw.Add(new Point(xVal, yVal));
                        i = 0;
                    }
                }
                startDrawing = true;
            }

            else if (msg.StartsWith("accept"))
                SetText(Encoding.ASCII.GetString(data, 0, data.Length));

            else if (msg.StartsWith("gues"))
            {
                if (msg.EndsWith("true"))
                    SetText(msg.Substring(5, msg.Length - 9) + " which was RIGHT! ");
                if (msg.EndsWith("false"))
                    SetText(msg.Substring(5, msg.Length - 10) + " which was WRONG! ");
            }

            else if (msg.StartsWith("quit"))
            {
                msg = "quit";
                data = Encoding.ASCII.GetBytes(msg);
                client.Send(data, data.Length);
                client.Close();
                SetText("The drawer quitted, the game is finished! ");
                abortThreads = true;
                Thread.CurrentThread.Abort();
            }
            else
            {
                if(msg.Length > 5) 
                    SetText(msgList.Text + Environment.NewLine + 
                      Encoding.ASCII.GetString(data, 4, data.Length - 4));
            }
        }
    }));
    t.IsBackground = true;
    t.Start();
}

It basically waits for a message using the receive method for the UDP, and then encode it to a string, msg, and then goes and checks for its content in a series of an if-else statements.

The second thread, DrawOnPanel(), draws whenever there's a draw message, and it's controlled by a boolean variable in the read() thread named startDrawing

private void DrawOnPanel()
{
    hwnd = thePanel.Handle;
    Thread t0 = new Thread(new ThreadStart(delegate
        {
            using (Graphics graphics = Graphics.FromHwnd(hwnd))
            {
                while (!abortThreads)
                {
                    if(startDrawing)
                    if (toDraw.Count > 0)
                    {
                        object holder = toDraw[0];
                        Point now = (Point)holder, previous = (Point)holder;
                        for (int i = 0; i < toDraw.Count; i++)
                        {
                            holder = toDraw[i];
                            now = (Point)holder;
                            graphics.DrawLine(MyPanel.p, now, previous);
                            previous = now;
                        }
                        Console.WriteLine(now + "  last  " + previous);
                        startDrawing = false;
                        toDraw.Clear();
                    }
                }
            }
        }));

    t0.IsBackground = true;
    t0.Start();
} 

.. 

And that's it for the Form1 class, other methods can be found in the source code. 

The panel class is called MyPanel and  it overrides the Panel class.

public class MyPanel : Panel and it overrides three mouse events methods, OnMouseDown()OnMouseUp(), and OnMouseMove() methods.

I'll go through them one by one. 

The first method, OnMouseDown()  has only one line, just to set a boolean value to true to indicate that we can start taking the points and store them in case of a drawer. 

protected override void OnMouseDown(MouseEventArgs e)
{
    mouse_down = true;
}

and the third method, OnMouseMove(), stores the points in an arraylist to be sent. 

protected override void OnMouseMove(MouseEventArgs e)
{
    if (Form1.isDrawer)
    {
        if (last_point.Equals(Point.Empty))
            last_point = new Point(e.X, e.Y);
        if (mouse_down)
        {

            IntPtr hwnd = this.Handle;

            using (Graphics graphics = Graphics.FromHwnd(hwnd))
            {
                Point pMousePos = new Point(e.X, e.Y);
                graphics.DrawLine(p, pMousePos, last_point);
                Console.WriteLine(pMousePos + "  last  " + last_point);
                pointss.Add(pMousePos);
            }
        }
        last_point = new Point(e.X, e.Y);
    }
} 

And the second method, OnMouseUp(), will convert the arraylist into a string and then into bytes and send them via the established UPD connection.

protected override void OnMouseUp(MouseEventArgs e)
{
    mouse_down = false;
    if (Form1.isDrawer)
    {
        string msg = "draw";
        for (int i = 0; i < pointss.Count; i++)
        {
            Point poi = (Point)pointss[i];
            msg += ("x" + poi.X + "y" + poi.Y);
        }
        msg += "x";
        pointss.Clear();
        byte[] data = Encoding.ASCII.GetBytes(msg);
        if (client != null)
            client.Send(data, data.Length);
    }
}

That sums up the main ideas of the tool, any questions about the code are welcomed. 

Points of Interest 

Some things I did in a strange way to get with my tool, you may think they are fun or creative, but eventually they worked stunningly! Here are some: 

- There's no free drawing capability in C#, so my trick was to draw small lines to make it look like a free drawing style.

- I convert the line points in the arraylist into a string to send them via the UDP connection easily.

Drawing on the panel was a headache without calling the Paint() method! I was only drawing in a small portion of the panel, so I used the tricky way in the DrawOnPanel() method that I developed to get rid of the problem, with the help of this question thread in Stackoverflow website:

The Reference.

 

 Conclusion

And by this I conclude my very first online article, if you have any feedback, questions, ideas or any comments, please do speak, it'd be my pleasure to hear all what is going on in your creative minds. 

History 

null; 

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