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

Frog Go Hop

0.00/5 (No votes)
24 May 2004 1  
A Frogger clone written in C#. Using doublebuffering timers and other technics.

Sample Image - FrogGoHop.gif

Introduction

This is a clone of the Original Frogger by Atari. This is my first game using C#. I hope, after you read this article, you take with you some skills needed to make your own fun games. The clipart is believed to be of public domain taken off of free clipart sites. I have used timers and OnPaint events to draw the images using the GDI double-buffering to reduce flicker. I have used both Quartz.dll and my own personal class (tonysound.cs), which I wrote an article on, to play sound events and background music. Click on my articles link to find this article.

Variables

Speed variables

I have set up several variables for speed as you can see in the code #region titled variables. The speed variable is to control the increments of the Image object being drawn. For instance, if I want the object to move slow, you would have a low number increment so it does move across the screen as fast. For each level of the game, I will add one to the current speed. This will increase the object movement increments and make the object appear to be move faster.

X Coordinates The X coordinates like Lane1var1 and so on are for the X coordinate on the playfield. Each object has a location of its X,Y coordinate. So if we move the x, it will obviously go either left or right. This is how the frogs and cars move. I increment the x for the Image object inside the timer, for example:

if (long1varx<672)
    long1varx+=logset1speed;
else
    long1varx=-71;
if (long2varx<672)
    long2varx+=logset1speed;
else 
    long2varx=-71;
if (long3varx<672)
    long3varx+=logset1speed;
else
    long3varx=-71;

As you can see here, I check to see if the first log in the first row is less than 672. If it is, then I add the logset1speed to it causing it to change its x position. Otherwise, I reset it to its starting position as -71. I do the same for the other logs as well.

Now, the Frog I move get his x value inside the KeyEvent, and then when the timer1 calls the drawstuff(g) function, it will get the updated x value of the frog and plot the graphic accordingly.

public void OnKeyPress(object sender,System.Windows.Forms.KeyEventArgs e)
{
    ....
    
    if (e.KeyCode == System.Windows.Forms.Keys.Left)
    {        
                
        Frogx-=30;
        Sound.Play(hopsound, 
                   PlaySoundFlags.SND_FILENAME | PlaySoundFlags.SND_ASYNC | 
                   PlaySoundFlags.SND_NOSTOP);
        
    }
    .......

What happens above is the keypress event is fired with each key press. I then check to see if the left arrow is pressed, the right arrow and so on. I then move the frog's coordinates based on the arrow. If it's left, then I subtract its move increment from its original x location. If it's right, then I add.

Bool values for the Target Taken and Snake Taken.. I have bool values like bool Target1taken and bool Snake1Taken. What this does is sets a true or false to determine if the frog can enter the home base. If the target is taken, this means the frog has already made it here and can't reenter again. Now if a snake is there, well he kills the frog, so we test to see if he is there, so if the frog jumps in the space he dies.

Static variable for score and why... If you are wondering why I made the score variable static, here is why. If you are on another form that uses the same namespace, you can't use the variable from the other form without making an instance of an object. So I cheat a little and make the variable of type static, then all I have to do is type the formname.variablename; for example, Form1.Score, and I don't have to make an instance of the form, in say, Form4 at all.

WHAT'S THAT NOISE? Well, just like pretty much any game, you have sound events and you have background music. Well, here is no exception. If you read my article about adding sound to C#, you will get an idea of what I have done. I used my class tonysound.cs that uses the winmm.dll to play my sound events, like the frog hopping and dying. Now, the background is a little different. You see, winmm.dll doesn't support sounds being played in parallel. So I had to come up with something a little different for the background. I hear you over there asking how, so let's dive into it.

Quartz.dll

In order to use Quartz.dll, we have to add it to the references of our project. To do this, we go to the main project name in Source Explorer and hit Add reference. When the dialog box pops up, we then hit the Browse button and go to windows\system32 directory and find the quartz.dll. Once it's added, then hit OK. You will then see QuartzTypeLib has been added. Now we are ready to get busy with making some sound play with this cool DLL. Well, like pretty much everything else, we need an object, so let's make one.

public QuartzTypeLib.FilgraphManagerClass mc;
//quartz object needed to play background

Now that we have the object, we need to do a few more things before we actually get the sound playing.

QuartzTypeLib.FilgraphManager graphManager = 
                       new QuartzTypeLib.FilgraphManager();
            
// QueryInterface for the IMediaControl interface:

            
mc =(QuartzTypeLib.FilgraphManagerClass)graphManager;

What we have done above is made a Graphmanager needed for playing the sound. You will notice, I assign mc the value of graphManager which has been recast to the type of filgraphManagerClass. Now that this is done, we are ready to rock and roll with the mc object that's going to play our sound for us. So we have to make thread that calls soundbackground to play our sound.

backgroundplay = new Thread (new ThreadStart(soundbackground));
// start thread to play music

Before calling this thread, we want to make it run in the background. So, when we close our program, we do not get processes not closing. So, to do this, we do the following before starting the thread:

backgroundplay.IsBackground=true;    // make the thread a background thread

backgroundplay.Start(); //start the music playing thread
void soundbackground()
{
    
    while(true)
    {
                    
        // Call some methods on a COM interface

        // Pass in file to RenderFile method on COM object.

                    
        mc.RenderFile("backmusic.mp3"); // loads the file in

        mc.Run(); // starts the playing

        if (mc.CurrentPosition==mc.Duration) // checks if ended

        {                            
            mc.CurrentPosition=0; // if we have ended we wanna start over

        }
                                    
         // -1 blocks this event infinately and the soundvar is an 

         // eventcode that gets triggered after time out                

         mc.WaitForCompletion(-1, out soundvar); 
    }            
}

Image Object and Checking Their Bounds

If you look under the #region section called Images, you will see where I have made some image objects. These are the images which you see on the screen. To test the bounds, we have to make image in the form of a rectangle. Look at the #region Bounds and you see the declarations.

public System.Drawing.Rectangle RectangleFrog;
public System.Drawing.Rectangle RectangleCar3;
public System.Drawing.Rectangle RectangleCar2;
public System.Drawing.Rectangle RectangleCar1;
public System.Drawing.Rectangle RectangleFastCar;
public System.Drawing.Rectangle RectangleTractor;
public System.Drawing.Rectangle RectangleCow;

Now that we have declared the object, we need to define it. So, we do the following. You will see this in the tickme sections. I could have placed it elsewhere, but I didn't.

RectangleCar1 = new Rectangle( Lane1var1, 312, Jeep1_Lane1.Width, 
                               Jeep1_Lane1.Height );
RectangleCar2 = new Rectangle( Lane1var2, 312, Jeep2_Lane1.Width, 
                               Jeep2_Lane1.Height );
RectangleCar3 = new Rectangle( Lane1var3, 312, Jeep2_Lane1.Width, 
                               Jeep2_Lane1.Height );
RectangleFastCar = new Rectangle(Lane2var,350,FastCar.Width,FastCar.Height);
RectangleTractor = new Rectangle(Lane3var,370,Tracter.Width,Tracter.Height);
RectangleCow = new Rectangle(Lane3var2,370,Cow.Width-10,Cow.Height-10);

Now that we have our rectangle bounds defined for our objects, we can test to see if they intersect with other objects. This is useful because, if say the frog intersects with the car, then we obviously want the frog to die. So C# makes this easy for us by allowing us to use a function called IntersectsWith. If you look in the tickme function, you will see where I check to see if the frog is hit by cars on logs etc.

if (RectangleFrog.IntersectsWith(RectangleCar2)||
    RectangleFrog.IntersectsWith(RectangleCar1)||
    RectangleFrog.IntersectsWith(RectangleCar3)||
    RectangleFrog.IntersectsWith(RectangleFastCar)|| 
    RectangleFrog.IntersectsWith(RectangleTractor)||
    RectangleFrog.IntersectsWith(RectangleCow))
{
    lives--;
    livesfunction();
}

What the above does is it checks to see if the frog image touches one of the cars or the cow or the tractor. If it does, then we are going to reduce our lives by one and then call the lives function to see if we are out of lives.

Double Buffering for Graphics

I will not go into great detail on this because I wrote an article on it already. Please look at the AntiFlicker Graphics article here. After reading the aforementioned article, you will see you have to enable double buffering because it is off by default. Also, you have to make an onpaint event and then call the DrawStuff function from a timer to get the graphics to move without flicker and lag.

Keeping Score in a text file:Reading Method

The high-score is read in line for line from a simple text file. I thought about using a database but scratched the idea simply because I didn't see the need. I also thought about making the file binary which I may still do in future versions of this. Yeah, I know you're saying stop rambling. I want to see how this is done, so here we go...

try
{
    StreamReader s = File.OpenText("Score.txt");            
            
    line1=s.ReadLine();
    line2=s.ReadLine();
    scorecompare= Convert.ToInt32(line2);
    label4.Text=line1;
    label5.Text=line2;
            
    s.Close();
}
catch
{
    MessageBox.Show("Can't find Score.txt");
}

So, let's take a look at what is going on here. First, we make our try and catch so if the score.txt file is missing, then we want to tell the user the reason the program has crashed. We then make sure up top we have using System.IO;, so we can use the StreamReader. So, we make a variable of type StreamReader and link it to the path of score.txt. Once this is done, we then assign line1 the value of the first read, which is line one. Then do the same for line2. Then I take and convert line2 which contains the score to an integer and store it in the scorecompair, so we can compare the high-score to the current score later. Then, I simply take and place the high-score name and the high-score score in their respective label text.

Keeping Score in a Text file: Write Method

Well, you are probably wondering how did we go about making this score.txt file? OK, if you look closely at the code, you will notice that if the scorecompare is less than the current score, then the current player has the highest score, so we simply display a form that gets the score; remember, we made it static so we could use it? Well, after we have the score, we want the user's name. After all this is in place, we have a submit button that does the following:

private void button1_Click(object sender, System.EventArgs e)
{
    FileInfo f = new FileInfo("Score.txt");
    StreamWriter w = f.CreateText();
    w.WriteLine(textBox1.Text.ToString());
    w.WriteLine(Form1.score.ToString());
    w.Close();
    Close();
}

Note from Author

The Quartz.dll is pretty interesting to mess with. I realized, with it, I could easily make a media player. I thought about making one of my dogs wag his tail as the music plays. This project was pretty fun for me and a great learning experience. I always wanted to learn C# and make a game. With the help of Code Project's members, you know who you are, I was able to put that dream into reality. One thing that still puzzles me is winmm.dll. I have heard that it will play two sounds in parallel from individuals on IRC but I have never seen any working code on how it is done. Because, from what I see, it doesn't have a blocking method, so when another event fires, the one that was last called takes priority. Another thing that kills me. I wanted to do Direct X and still will. I might have to get the newest version of Visual Studio though, but anyway, here is the deal. I have tried every method I know of to get DirectX to install correctly. It simply refuses to do so. I followed several methods like registering the DLLs, copying the DLLs, and so forth. So after I get a little less busy, I'm going to uninstall VS and reinstall it all and see if that works. One other thing. I am now a big fan of timers. They made my life a lot easier. Oh, I did learn one interesting thing. If you include using System.Diagnostics;, you can then call process.Start("a url"); and it will let your users email you or go to your website or whatever.

Summary

Hopefully after reading this article, you will have taken with you some ideas to make some fantastic games for your family and even yourself. I always wanted the old style frogger and sure I could have bought it, but I figured why don't I learn how to make it, so there you have it. My version of Frogger. I'm sure there are bugs in this software and they will be corrected as I find them. If you like this code, do me a favor. Send me an email to Junkmail4tony@comcast.net and let me know how you like it.

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