DEFCOM1  
 

 

XNA Level 1 Lesson 8

Simple Menu and Game States

  1. Create a gamestate variable
  2. Create 2 new Update functions
  3. Use a switch case statement in the Update Function
  4. Use a switch case statement in the Draw Function

 

Create a gameState Variable

We need to create a variable called gameState at the start of the program just before we create our textures and positions

add the line public int gameState = 0;

 

public int screenHeight;
public int screenWidth;

public int gameState = 0;

// This is a texture we can render.
Texture2D ufoTex;
Texture2D asteroidTex;

 

Create 2 new Update functions

TO keep our code tidy we are going to create 2 new update functions, 1 to handle our menu screen, the other to handle our main game. Later on will create another to handle our end of game screen.

Underneath your update function add the following

public void UpdateMenu(GameTime gameTime)
{

}

public void UpdateGame(GameTime gameTime)
{

}

 

Now very carefully cut all the code from inside you update code and paste in into your updateGame function

 

Your update function should now look like this

protected override void Update(GameTime gameTime)
{

}

 

Use a switch case statement in the Update Function

A case switch is a selection statement just like 'IF' but is the better option than writing lots of if statements.

The switch will look at the current value of gameState and then choose the correct option

protected override void Update(GameTime gameTime)
{

    //gameState Menu
    switch (gameState)
    {
        case 0:
            UpdateMenu(gameTime);   //intro screen
            break;

        case 1:
            UpdateGame(gameTime);   //main game
            break;
        
         default:
            /*error*/
            break;
    };

 

All Switch case statements should end with 'break' statement or the next case will automatically run. C# does not like this!

The default is there just incase it does not receive a number it expects

 

Use a switch case statement in the Draw Function

We should now add another switch case statement in the draw function, we could and probably should move each draw option to a seperate function just like the update function, but I haven't.

protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.Black);


    switch(gameState)
    {
        // Draw Menu
        case 0:
            spriteBatch.Begin();                
            spriteBatch.DrawString(font, "Asteroid Field\nArrows to Move\nPress Space to Play ", 
                                        new Vector2(100, 10), Color.White);
            spriteBatch.End();
        break;


            // Draw Main Game
        case 1: 
            
            spriteBatch.Begin();
            spriteBatch.Draw(ufoTex, ufoPos, Color.White);

            //draw all asteroids
            for (int i = 0; i < numberOfAsteroids; i++)
            {
                spriteBatch.Draw(asteroidTex, asteroid[i], Color.White);
            }

            spriteBatch.DrawString(font, "Score: " + score, new Vector2(20, 10), Color.White);

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

 

Challenge

Over to you... We really do need an end of game screen so you can see your final score

Your Task: Add this option.

Hint: Think update, think draw, think switch case

 

Complete Listings -- I have also added a ResetGame function!!!

public class Game1 : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;

    //screen size
    public int screenHeight;
    public int screenWidth;

    public int gameState = 0;

    // This is a texture we can render.
    Texture2D ufoTex;
    Texture2D asteroidTex;

    SpriteFont font;

    // Set the coordinates to draw the sprite at.
    Vector2 ufoPos = Vector2.Zero;

    //create an array of 10 asteroid coordinates (we will use the same image for each one)
    static int numberOfAsteroids = 25;
    Vector2[] asteroid = new Vector2[numberOfAsteroids];

    Random rand = new Random();

    int score = 0;


    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
    }


    protected override void Initialize()
    {
        //set Screen size
        screenWidth = 800;
        screenHeight = 500;

        graphics.PreferredBackBufferWidth = screenWidth;
        graphics.PreferredBackBufferHeight = screenHeight;

        graphics.IsFullScreen = true;
        graphics.ApplyChanges();

        resetGame();

        base.Initialize();
    }

    protected override void LoadContent()
    {
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);

        //load our graphic
        ufoTex = Content.Load<Texture2D>("ufo");
        asteroidTex = Content.Load<Texture2D>("asteroid");

        font = Content.Load<SpriteFont>("mainFont");

    }


    protected override void UnloadContent()
    {
        // TODO: Unload any non ContentManager content here
    }

    public void resetGame()
    {
        //reset game
        gameState = 0;
        score = 0;

        //ufo starting position
        ufoPos.Y = screenHeight - 128;    //height of screen - hieght of ufo


        //Starting Position of all asteroids
        for (int i = 0; i < numberOfAsteroids; i++)
        {
            asteroid[i].X = rand.Next(800 - 128); //position within screen width - ufo width
            asteroid[i].Y = 0 - ((i * 250) + 128);
            float y = asteroid[i].Y;
        }
    }

    protected override void Update(GameTime gameTime)
    {

        //gameState Menu
        switch (gameState)
        {
            case 0:
                UpdateMenu(gameTime);   //intro screen
                break;

            case 1:
                UpdateGame(gameTime);   //main game
                break;

            case 2:
                UpdateGameOver(gameTime); //End OF Game
                break;

            default:
                /*error*/
                break;
        };


        base.Update(gameTime);
    }

    public void UpdateMenu(GameTime gameTime)
    {

        KeyboardState key = Keyboard.GetState();

        if (key.IsKeyDown(Keys.Space))
        {
            gameState = 1;
        }            
    }

    public void UpdateGame(GameTime gameTime)
    {
        // Allows the game to exit
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            this.Exit();

        // TODO: Add your update logic here



        //update all asteroid positions
        for (int i = 0; i < numberOfAsteroids; i++)
        {
            asteroid[i].Y += 5;
            if (asteroid[i].Y > screenHeight)
            {
                Random rand = new Random();
                asteroid[i].X = rand.Next(screenWidth - asteroidTex.Width);
                asteroid[i].Y = 0 - (numberOfAsteroids * (250 - score / 10)) - 128;  //put to top
                score += 10;
            }
        }


        //Get Midpoint of ufo
        int x = (int)ufoPos.X + (ufoTex.Width / 2);
        int y = (int)ufoPos.Y + (ufoTex.Height / 2);

        //check if midpoint is inside each asteroid 
        for (int i = 0; i < numberOfAsteroids; i++)
        {
            if (x > asteroid[i].X && x < asteroid[i].X + asteroidTex.Width)
            {
                if (y > asteroid[i].Y && y < asteroid[i].Y + asteroidTex.Height)
                {
                    gameState = 2;//game over
                       
                }
            }
        }



        //update ufo
        KeyboardState key = Keyboard.GetState();

        if (key.IsKeyDown(Keys.Left) && ufoPos.X > 0)
        {
            ufoPos.X -= 5;
        }
        if (key.IsKeyDown(Keys.Right) && ufoPos.X < 800 - ufoTex.Width)
        {
            ufoPos.X += 5;
        }
        if (key.IsKeyDown(Keys.Up) && ufoPos.Y > 0)
        {
            ufoPos.Y -= 5;
        }
        if (key.IsKeyDown(Keys.Down) && ufoPos.Y < 600 - ufoTex.Height)
        {
            ufoPos.Y += 5;
        }
    }

    public void UpdateGameOver(GameTime gameTime)
    {
        KeyboardState key = Keyboard.GetState();

        if (key.IsKeyDown(Keys.Enter))
        {
            resetGame();
        }
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.Black);


        switch(gameState)
        {
            // Draw Menu
            case 0:
                spriteBatch.Begin();                
                spriteBatch.DrawString(font, "Asteroid Field\nArrows to Move\nPress Space to Play ", 
                                              new Vector2(100, 10), Color.White);
                spriteBatch.End();
            break;


                // Draw Main Game
            case 1: 
            
                spriteBatch.Begin();
                spriteBatch.Draw(ufoTex, ufoPos, Color.White);

                //draw all asteroids
                for (int i = 0; i < numberOfAsteroids; i++)
                {
                    spriteBatch.Draw(asteroidTex, asteroid[i], Color.White);
                }

                spriteBatch.DrawString(font, "Score: " + score, new Vector2(20, 10), Color.White);

                spriteBatch.End();
                break;

            

            // Draw END OF GAME
            case 2: 
            
                spriteBatch.Begin();

                spriteBatch.DrawString(font, "Asteroid Field\nFinal Score: " + score, 
                                             new Vector2(100, 10), Color.White);
                spriteBatch.DrawString(font, "Press Enter to Continue ", 
                                             new Vector2(100, 60), Color.White);
                spriteBatch.End();
                break;
        }
        base.Draw(gameTime);
    }
}