ASP.NET Naughts and Crosses

GCGameWin.jpg

Article description

This article demonstrates the basic techniques used to build "ASP.net Noughts & Crosses" (tic tac toe to our American friends). The game uses the native imaging and drawing features of the .net Framework to dynamically generate a JPEG image which displays the game board to the user. Players can take turns to click on the area of the image where they wish to make a move, their move is then submitted to the web server where, if legal, it is drawn onto the board. The application consists of two aspx web pages which each have an associated code behind page, the source code for the game can be found here

Dynamically generating Images in ASP.net

One of the more impressive features of ASP.net is the ability to dynamically generate images that can be viewed in a standard web browser, something that was not easy to achieve using previous versions of ASP. We'll start with an example which draws the four lines of the game grid and sends the output to the user as an image. The two main .net base classes used to create and edit images both belong to the System.Drawing namespace, these are:

  • System.Drawing.Bitmap - This class is used to create the image that we will send to the users browser.
  • System.Drawing.Graphics - This class is used to draw onto our image

We will be creating a true colour JPEG, therefore the following code can be used to create a 24bit color Bitmap object 300 pixels wide and 300 high that will represent our image.

Bitmap objGridBitmap = new Bitmap(300, 300, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

Next we need to create a Graphics object which will be used to draw onto our bitmap. This can be done using the static method FromImage() of the Graphics Class, the method has one parameter which is a reference to our bitmap.

Graphics objGraphicsGrid = Graphics.FromImage(objGridBitmap);

After clearing the surface with a white fill we can now use the draw methods of the Graphics object to draw onto the bitmap. To Begin with we'll draw a single horizontal black line 100 pixels from the top of our bitmap; this is the first line of the grid. We can draw a line using the DrawLine method of the Graphics Class, we will be passing three parameters into the method:

  • the Pen we wish to draw the line with
  • the Point on the image where we want the line to start
  • the point where the line will end

Since we are drawing four lines we'll create a single Black pen object three pixels think which can be used to draw all the lines. As each line uses different points we will create two new points for each method call, these two points represent x and y coordinates from the top left corner of the bitmap.

//Clear Graphics Object with white brush
objGraphicsGrid.Clear(Color.White);
//Create a black Pen
Pen objBlackPen = new Pen(Color.Black, 3);
//Draw a Line
objGraphicsGrid.DrawLine(objBlackPen, new Point(0, 100), new Point(300, 100));

We can now draw the remaining three lines in the same fashion.

//Draw three more lines
objGraphicsGrid .DrawLine(objBlackPen, new Point(0, 200), new Point(300, 200));
objGraphicsGrid .DrawLine(objBlackPen,
new Point(100, 0), new Point(100, 300));
objGraphicsGrid .DrawLine(objBlackPen,
new Point(200, 0), new Point(200, 300));

With the game grid complete we are ready to send the result to the users browser, this is achieved with just two more lines of code. We will use the Response object of the page to first set the content type of the page to image/JPEG and then stream our bitmap to the clients browser using the Save() method of the Bitmap class.

//Set the content type to Jpeg
Response.ContentType = "image/jpeg";
//Send image to users browser
objGridBitmap.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);

That's all there is to it, if all has gone well when we view this page in our web browser the result should be as below.

ncgrid.jpg

Viewing the image in a html page

It's important to realise that the aspx page which we've just created represents a single image and cannot contain any HTML. The reason for this is that when a browser displays a HTML page containing an image the browser actually makes two get requests to the web server, one for the HTML and another for the image. If we wish our dynamic image to appear in a HTML page we need to create a separate web page containing a HTML element that has our dynamic image aspx page as it's source. If we were to name our dynamic image page dynamicimage.aspx then the HTML tag could look like this:

<img border="0" name="image1" src ="dynamicimage.aspx">

Interpreting user input

To register user input the game uses a form input element of type 'image' which has the dynamic image aspx page as it's source. The reason for this is that when an image input is clicked in a browser the page's form is submitted and the x and y coordinates of where the user clicked on the image are sent to the server. We can then use this information to determine which part of the game grid we need to draw a move. Below is the HTML and the c# code needed to record the users mouse input:-

aspx HTML
<form name ="form1" action ="get" method ="#">
< input name ="gamegrid" type="image" src="dynamicimage.aspx">
</ form>

codebehind c# code

//Store the gamegrid.X querystring parameter in a local variable
int intMouseX = Int32.Parse(Request.QueryString["gamegrid.X"]);
//Store the gamegrid.Y querystring parameter in a local variable
int intMouseY = Int32.Parse(Request.QueryString["gamegrid.Y"]);

Passing information between pages using the Session Object

Since there are two aspx pages in the application, one which interprets user input and another to generate the game graphics, it needs the ability to pass data between the two pages. There are a number of ways this can be achieved, however when designing the game I decided to share data using the Session object. As an ASP developer I have previously been very reluctant to use the Session object, this was mainly due to the effect it has on the scalability of web applications. Using sessions effectively meant that an application would not be run correctly on a web farm due to the way session object data was stored. This problem has been overcome in ASP.net with the option of using 'out of process' session databases when the application is run on a web farm. Consequently the session object has once again become a convenient container for small amounts of session data.

Storing data in a session object is relatively straightforward, the following code will store an integer in a new session object called s_intMyData

Session["s_intMyData"] = 5;

Using the value in our new session object for comparison or assignment purposes will require the object being cast to the value it holds, in this case to int. The reason for this is that our session object is of type 'object' even though it is used to hold an int. The following code demonstrates using our session object

//store an integer in a session variable in a local integer variable
int intMyDataLocal = (int)Session["s_intMyData"];
//compare an integer in a session variable with a literal integer
if((int)Session["s_intMyData"] == 5)
{
//Do something

I used the Session object in the game to hold an array of integers, we can similarly cast the object to an array of type int, this is demonstrated in the following code

//Create new Session object which contains an array of integers
Session["s_intMyArray"] = new int[]{1, 2, 3} ;
//Store the session object in a local array
int[] intMyArrayLocal = (int[])Session["s_intMyArray"];

Conclusion

I've discussed most of the major elements that make up the game; the rest of the code is pretty self explanatory and extensively commented. I've only just touched upon the dynamic image generation abilities of ASP.net which offers incredibly feature rich graphics and imaging functionality, both programmatically and functionally, ASP.net is a huge leap forward from ASP 3.0.