Click here to Skip to main content
15,885,278 members
Articles / .NET / .NET4

'XNA Sample Game' for Beginners

Rate me:
Please Sign up or sign in to vote.
4.75/5 (4 votes)
17 Jan 2016CPOL3 min read 13.7K   6   2
Sample Game using XNA

Introduction

C#.NET/XNA is a technology which is descending yet supports basically the XBox 360.

This Sample game Annie's Laundry in this article was developed by me several month ago using XNA, Just to refresh understanding about Game Development Fundamentals and I thought to provide hte same benefits to the multitudes.

Background

In this article, I've provided the source code for the Game and also detailed description of the Object Movement, Collision, Scores, User Controls and Start/End of the Game. The article provides detailed description about the coding and performing the above mentioned objectives.

 

The 'Annie's Laundry' is a 2D Game developed using XNA for single player. The objective of the Game is for the player is to score marks as much as he/she could by catching the falling clothes of Annie's Laundry due to bad weather. The types of Clothes falling are handkerchief and Shirts. The problems that the player has to deal with are Monkey Poo falling from the ropes and Bombs thrown by haters. So, when catching the Clothes, player has to avoid Poo and Bombs hitting the two baskets which user gets to play with using different controls of the Keyboard simultaneously. When Baskets are getting heavier it becomes difficult to move them and also when any of the clothes fall down without being caught the health level of Old Annie goes down by single Point. Player do need to keep Annie's health at a good rate, avoid Poo and Bombs and score Marks.

 

Code Explanations

The XNA Game starts execution with Program.cs  which includes the Main method and within the method an object for the game class is created. Run() method is used to initilize the game.

C#
using System;

namespace WindowsGame2
{
#if WINDOWS || XBOX
    static class Program
    {
        static void Main(string[] args)
        {
            using (AnnieLaundary game = new AnnieLaundary())
            {
                game.Run();
            }
        }
    }
#endif
}

 

The game class which is AnnieLaundary extends Microsoft.Xna.Framework.Game. The necessary resources such as sound effects, sound effect instances, sprite fonts, 2D Textures and Object initialization of class types are there with in the class.

C#
 public class AnnieLaundary : Microsoft.Xna.Framework.Game
 {

   SoundEffect background_sound;
   SoundEffectInstance intro_sound_instance;           
   SpriteFont font;        
   Bucket bucketObj;        
   Rectangle screenRectangle;        
   Texture2D shirt; // shortened code as for the example
}

 

LoadContent() method loads each and every texture and sound files within the WindowsGame2Content Directory of the Game's root directory into the Game Class. This is an important coding section where you've to closely look at each and every .wav,.png and .jpeg resources and their names precisely.

 

C#
 protected override void LoadContent()
 {
     bomb_sound = Content.Load<SoundEffect>("Audio\\Waves\\bomb");            
     bomb_sound_instance = bomb_sound.CreateInstance();
     mainMenu = Content.Load<Texture2D>("mainbkg");
     help = Content.Load<Texture2D>("selectamapwithbckgrnd");
     shirt = Content.Load<Texture2D>("shirt");
     poo = Content.Load<Texture2D>("poo");
     Mybombimg = Content.Load<Texture2D>("bomb");
     monkey = Content.Load<Texture2D>("monkey");
     shirtObj = new Shirt(shirt,screenRectangle);
     bombObj = new Bomb(Mybombimg, screenRectangle);
     pooObj = new Poo(poo, screenRectangle);
     monkeyObj = new Monkey(monkey, screenRectangle, this.Content);
     pheObj = new PlayHelpExitBtns
     (playNorm, playNeon, helpNorm, helpNeon, 
           exitNorm, exitNeon, help, mainMenu, screenRectangle, this.Content);
     spriteBatch = new SpriteBatch(GraphicsDevice); 
     font = Content.Load<SpriteFont>("SpriteFont1");
     serviet = Content.Load<Texture2D>("serviet"); //shortened code as for example
}

 

update(GameTime gametime) method is an important method with in the main class because it contantly updates the game logic. The time since the last update call is passed as parameters to the method.

The screen state enumeration list includes two constants namely controllerDetect and title among which for the controllerDetect, updateControllerDetectScreen() method looks for the 'Enter' key down to set the currentScreenState to title. This relates to the Splash Screen of the game in which you've to 'Enter' to continue.

 

C#
enum screenState
{
    controllerDetect,
    title
}
screenState currentScreenState;
C#
private void updateControllerDetectScreen()
{
    if (Keyboard.GetState().IsKeyDown(Keys.Enter) == true)
        currentScreenState = screenState.title;
}

 

Image 1

 

C#
protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
    {
        this.Exit();
    }

    switch (currentScreenState)
    {
        case screenState.controllerDetect:
        {
            updateControllerDetectScreen();
            break;
        }
        case screenState.title:
        {
            if (PlayHelpExitBtns.selectedKeyState == "play" && playState == false)
            {
                StartGame();
                playState = true;
                intro_sound_instance.Stop();
                /* stops the intro sound play when the playe begins */
            }

            if (PlayHelpExitBtns.selectedKeyState == "play" && !Serviet.gameover)
            {
                intro_sound_instance.Stop();
                /* stops the intro sound play when the playe begins */
                background_sound_instance.Play();
                /* starts background music */

                if (Serviet.level >= 2) /* level static variable is declared in serviet */
                {
                    shirtObj.Updateshirt();
                }
                if (Serviet.level >= 3)
                {
                    secondbucketObj.UpdateSecondBucket();
                }
                if (Serviet.level >= 4)
                {
                    pooObj.UpdatePoo();
                }
                if (Serviet.level >= 5)
                {
                    bombObj.UpdateBomb();
                }

                servietObj.UpdateServiet();

                monkeyObj.UpdateMonkey();

                bucketObj.UpdateBucket();
            }
            else
            {
                pheObj.update();
                if (pheObj.exitGame())
                {
                    this.Exit();
                }
            }
            break;
        }
    }

    /* serviet collision with bucket */
    if (servietObj.Collision(bucketObj.GetBounds()))
    {
        if (clothfall_sound_instance.State == SoundState.Stopped)
        {
            clothfall_sound_instance.Volume = 0.75f; /* Play sounds */
            clothfall_sound_instance.Play();
        }
    }

    /* second bucket comes after level 3 */

    if (Serviet.level >= 3)
    {
        if (servietObj.Collision(secondbucketObj.GetBounds()))
        {
            if (clothfall_sound_instance.State == SoundState.Stopped)
            {
                clothfall_sound_instance.Volume = 0.75f /* Play Sounds */
                clothfall_sound_instance.Play();
            }
        }
    }

    if (shirtObj.Collision(bucketObj.GetBounds()))
    {
        if (clothfall_sound_instance.State == SoundState.Stopped)
        {
            clothfall_sound_instance.Volume = 0.75f; /* Play Sounds */
            clothfall_sound_instance.Play();
        }
    }

    if (Serviet.level >= 3) // second bucket comes after level 3
    {
        if (shirtObj.Collision(secondbucketObj.GetBounds()))
        {
            if (clothfall_sound_instance.State == SoundState.Stopped)
            {
                clothfall_sound_instance.Volume = 0.75f;
                clothfall_sound_instance.Play();
            }
        }
    }

    /* second bucket comes after level 3  but poop comes after 4 */

    if (Serviet.level >= 4)
    {
        if (pooObj.Collision(bucketObj.GetBounds())) /* collision with first bucket*/
        {
            if (poop_sound_instance.State == SoundState.Stopped)
            {
                poop_sound_instance.Volume = 0.75f;
                poop_sound_instance.Play();
            }
        }
        if (pooObj.Collision(secondbucketObj.GetBounds())) /* collision with second */
        {
            if (poop_sound_instance.State == SoundState.Stopped)
            {
                poop_sound_instance.Volume = 0.75f;
                poop_sound_instance.Play();
            }
        }
    }
    if (Serviet.level >= 5) // second bucket comes after level 3  but bomb comes after 5
    {
        /* checks the collision of first bucket with bomb */
        if (bombObj.Collision(bucketObj.GetBounds()))
        {
            if (bomb_sound_instance.State == SoundState.Stopped)
            {
                bomb_sound_instance.Volume = 0.75f;
                bomb_sound_instance.Play();
                crying_sound_instance.Play();
            }
        }

       /* checks the collision of second bucket with bomb */
       if (bombObj.Collision(secondbucketObj.GetBounds()))
       {
            if (bomb_sound_instance.State == SoundState.Stopped)
            {
                bomb_sound_instance.Volume = 0.50f;
                bomb_sound_instance.Play();
                crying_sound_instance.Play();
            }
        }
    }

    base.Update(gameTime);
}


Levels of the game are declared as static variable in Serviet class and they're used in the update() method.

C#
/* second bucket comes after level 3  but bomb comes after 5 */

if (Serviet.level >= 5)
{
     // collision conditions
}

Collision() method is in each of the Classes like Serviet, Shirt, Poo & Bomb  which checks for the collision among objects.

C#
/* checks the collision of second bucket with bomb */

if (bombObj.Collision(secondbucketObj.GetBounds()))
{
   // sounds files
}

Draw() method draws all the sprites as spritebatches. Sprites in general are used to render objects into the game screen. 

PlayHelpExitBtns class provides the Menu screen to the Game, where the player is able to choose either Play, Help or Exit. 

C#
protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.Black);
    spriteBatch.Begin();

    if (currentScreenState == screenState.controllerDetect)
    {
        spriteBatch.Draw(splashScreen, Vector2.Zero, Color.White);
    }

    if (PlayHelpExitBtns.selectedKeyState == "play")
    {
        // if the game overs with the annies low health the condition is passed here
        if (Serviet.gameover && Serviet.anniesmiles == 0)
        {
            spriteBatch.Draw(Gameover, gameoverposition, Color.White);
            spriteBatch.Draw(levelimage, leveluppossition, Color.White);
            spriteBatch.DrawString
            (font, "Score : " + Serviet.final_score,
                  new Vector2(1050, 20), Color.Chocolate);
            crying_sound_instance.Play();
            bomb_sound_instance.Stop();
            background_sound_instance.Stop();
            clothfall_sound_instance.Stop();
            poop_sound_instance.Stop();
        }

        if (Serviet.gameover)
        {
            // if the game overs with the hitting of a bomb then it is passed here
            spriteBatch.Draw(Gameover, gameoverposition, Color.White);
            spriteBatch.Draw(levelimage, leveluppossition, Color.White);
            spriteBatch.DrawString
            (font, "Score : " + Serviet.final_score,
                  new Vector2(1050, 20), Color.Chocolate);
            poop_sound_instance.Stop();
            clothfall_sound_instance.Stop();
            background_sound_instance.Stop();
            levelup_sound_instance.Stop();
        }
        else
        {
            spriteBatch.Draw(background, backgrounposition, Color.White);
            bucketObj.Draw(spriteBatch);
            servietObj.Draw(spriteBatch);
            monkeyObj.DrawMonkey(spriteBatch);
            DrawText();
            spriteBatch.Draw(myTexture, spritePosition, Color.White);

            spriteBatch.Draw
            (annhealth_icon, new Rectangle
                             (530 , 15, annhealth_icon.Width, 44),
                                      new Rectangle
                                         (0, 0, annhealth_icon.Width, 44),
                                                Color.White); // health bag icon

            if(Serviet.anniesmiles < 7)
            {
                healthbar_color = Color.Yellow;
            }

            if (Serviet.anniesmiles < 4)
            {
                healthbar_color = Color.Red;
            }

            spriteBatch.Draw(healthbar,
                   new Rectangle(600, 25,
                       (int)(healthbar.Width * ((double)Serviet.anniesmiles / 10)),
                            44), new Rectangle
                                 (0, 45, healthbar.Width, 44), healthbar_color);
                                 // draw red line indicating health
            spriteBatch.Draw(healthbar,
                     new Rectangle(600, 10, healthbar.Width, 44),
                        new Rectangle(0, 0, healthbar.Width, 44), Color.White);

            if (Serviet.level >= 2) // shirt on and after the level 2
            {
                shirtObj.DrawShirt(spriteBatch);
            }

            if (Serviet.level >= 3)
            {
                secondbucketObj.DrawSecondBucket(spriteBatch);
            }

            if (Serviet.level >= 4)
            {
                pooObj.DrawPoo(spriteBatch);
            }

            if (Serviet.level >= 5)
            {
                bombObj.DrawBomb(spriteBatch);
            }
        }

        if ((Serviet.total >= 100 && Serviet.total <= 120)
             || (Serviet.total >= 200 && Serviet.total <= 220)
             || (Serviet.total >= 300 && Serviet.total <= 320)
             || (Serviet.total >= 400 && Serviet.total <= 420)
             || (Serviet.total >= 500 && Serviet.total <= 520))
        {
            spriteBatch.Draw(Levelup, leveluppossition, Color.White);
            if (Serviet.total == 100
                 || Serviet.total == 200
                 || Serviet.total == 300
                 || Serviet.total == 400
                 || Serviet.total == 500)
            {
                levelup_sound_instance.Play();
            }
        }
    }

    else if (currentScreenState == screenState.title)
    {
        pheObj.draw(spriteBatch);
    }

    spriteBatch.End();
    base.Draw(gameTime);
}

selectedKeyState static string variable is called within the Draw() method to check the selection of the Player from the Menu.

C#
if (PlayHelpExitBtns.selectedKeyState == "play")
{
        // code
}

anniesmiles static int variable in Serviet class which is initialized to 10 is used to calculate the health of Annie's at any given point. This values is reduced by one when clothes hit the ground.

The following figure shows the game play screen. You can see the Score, Level & Health Indicators in the play area.

Image 2

 

The Game Over screen is shown with the Final Score.

 

Image 3

 

Download the Source Code From here.

 

License

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


Written By
Sri Lanka Sri Lanka
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionSoundEffect ?? Pin
Thornik4-Aug-22 11:10
Thornik4-Aug-22 11:10 
Hi! From where you get class SoundEffect ?

QuestionLink broken Pin
Lucio Flavio25-May-18 3:35
Lucio Flavio25-May-18 3:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.