WPF C# Tutorial – Create a space battle shooter game in Visual Studio

The games engine event for the space shooter game

Below is the main game engine source code for this game. This will be largest event for this game as it holds all of the logic and rules for this game. This event is linked to the gameTimer dispatcher timer we created earlier in the game; each time it ticks this event will be triggered. It has to run this event every 20 milliseconds so the game will run at a smoother frame rate.

The full source code is below, as before all of the code is commented but we will break down the code as well to make sure we provide all the help and not just let you copy and paste the code without understanding what is going on in here. But just don’t copy and paste them please, take some time to see how it works and it will mean the world to us.

The games engine code –

  private void gameEngine(object sender, EventArgs e)
        {
            // link the player hit box to the player rectangle
            playerHitBox = new Rect(Canvas.GetLeft(player), Canvas.GetTop(player), player.Width, player.Height);

            // reduce one from the enemy counter integer
            enemyCounter--;

            scoreText.Content = "Score: " + score; // link the score text to score integer
            damageText.Content = "Damaged " + damage; // link the damage text to damage integer

            // if enemy counter is less than 0
            if (enemyCounter < 0)
            {
                makeEnemies(); // run the make enemies function
                enemyCounter = limit; //reset the enemy counter to the limit integer
            }

            // player movement begins

            if (moveLeft && Canvas.GetLeft(player) > 0)
            {
                // if move left is true AND player is inside the boundary then move player to the left
                Canvas.SetLeft(player, Canvas.GetLeft(player) - playerSpeed);
            }
            if (moveRight && Canvas.GetLeft(player) + 90 < Application.Current.MainWindow.Width)
            {
                // if move right is true AND player left + 90 is less than the width of the form
                // then move the player to the right
                Canvas.SetLeft(player, Canvas.GetLeft(player) + playerSpeed);
            }

            // player movement ends

            // search for bullets, enemies and collision begins

            foreach (var x in MyCanvas.Children.OfType<Rectangle>())
            {
                // if any rectangle has the tag bullet in it
                if (x is Rectangle && (string)x.Tag == "bullet")
                {
                    // move the bullet rectangle towards top of the screen
                    Canvas.SetTop(x, Canvas.GetTop(x) - 20);

                    // make a rect class with the bullet rectangles properties
                    Rect bullet = new Rect(Canvas.GetLeft(x), Canvas.GetTop(x), x.Width, x.Height);

                    // check if bullet has reached top part of the screen
                    if (Canvas.GetTop(x) < 10)
                    {
                        // if it has then add it to the item to remove list
                        itemstoremove.Add(x);
                    }

                    // run another for each loop inside of the main loop this one has a local variable called y
                    foreach (var y in MyCanvas.Children.OfType<Rectangle>())
                    {
                        // if y is a rectangle and it has a tag called enemy
                        if (y is Rectangle && (string)y.Tag == "enemy")
                        {
                            // make a local rect called enemy and put the enemies properties into it
                            Rect enemy = new Rect(Canvas.GetLeft(y), Canvas.GetTop(y), y.Width, y.Height);


                            // now check if bullet and enemy is colliding or not
                            // if the bullet is colliding with the enemy rectangle
                            if (bullet.IntersectsWith(enemy))
                            {

                                itemstoremove.Add(x); // remove bullet
                                itemstoremove.Add(y); // remove enemy
                                score++; // add one to the score
                            }
                        }

                    }
                }

                // outside the second loop lets check for the enemy again
                if (x is Rectangle && (string)x.Tag == "enemy")
                {
                    // if we find a rectangle with the enemy tag

                    Canvas.SetTop(x, Canvas.GetTop(x) + 10); // move the enemy downwards

                    // make a new enemy rect for enemy hit box
                    Rect enemy = new Rect(Canvas.GetLeft(x), Canvas.GetTop(x), x.Width, x.Height);

                    // first check if the enemy object has gone passed the player meaning
                    // its gone passed 700 pixels from the top
                    if (Canvas.GetTop(x) + 150 > 700)
                    {
                        // if so first remove the enemy object
                        itemstoremove.Add(x);
                        damage += 10; // add 10 to the damage
                    }

                    // if the player hit box and the enemy is colliding 
                    if (playerHitBox.IntersectsWith(enemy))
                    {
                        damage += 5; // add 5 to the damage
                        itemstoremove.Add(x); // remove the enemy object
                    }
                }


            }

            // search for bullets, enemies and collision ENDs

            // if the score is greater than 5
            if (score > 5)
            {
                limit = 20; // reduce the limit to 20
                // now the enemies will spawn faster
            }

            // if the damage integer is greater than 99
            if (damage > 99)
            {
                gameTimer.Stop(); // stop the main timer
                damageText.Content = "Damaged: 100"; // show this on the damaged text
                damageText.Foreground = Brushes.Red; // change the text colour to 100
                MessageBox.Show("Well Done Star Captain!" + Environment.NewLine + "You have destroyed " + score + " Alien ships");
                // show the message box with the message inside of it
            }

            // removing the rectangles

            // check how many rectangles are inside of the item to remove list
            foreach (Rectangle y in itemstoremove)
            {
                // remove them permanently from the canvas
                MyCanvas.Children.Remove(y);
            }


        }

The break down

playerHitBox = new Rect(Canvas.GetLeft(player), Canvas.GetTop(player), player.Width, player.Height); this line is linking the player object to the player hit box rect object. We can use this hit box to determine weather the player hit an enemy in the game.

enemyCounter–; this line is reducing 1 from the enemy counter integer, the idea is we want to spawn enemies in spaces and we don’t want to overwhelm the player straight away so having a counter helps keep that in order. Follow along and you will see how this gets used in the game

scoreText.Content = “Score: ” + score; link the score text label to the score integer

damageText.Content = “Damaged ” + damage; link the damage text label to the damage integer for this game. Since both of them are inside the timer meaning they will be updated very frequently so we can see the up to date information on the HUD (head over display).

            // if enemy counter is less than 0
            if (enemyCounter < 0)
            {
                makeEnemies(); // run the make enemies function
                enemyCounter = limit; //reset the enemy counter to the limit integer
            }

The box above is checking if enemy counter is less than 0 meaning when the enemy counter integer goes below 0 since we are taking 1 out of it every frame then we can run the make enemies function to make new enemies on the screen and reset the counter to the limit which at the beginning is set to 50.

            // player movement begins

            if (moveLeft && Canvas.GetLeft(player) > 0)
            {
                // if move left is true AND player is inside the boundary then move player to the left
                Canvas.SetLeft(player, Canvas.GetLeft(player) - playerSpeed);
            }
            if (moveRight && Canvas.GetLeft(player) + 90 < Application.Current.MainWindow.Width)
            {
                // if move right is true AND player left + 90 is less than the width of the form
                // then move the player to the right
                Canvas.SetLeft(player, Canvas.GetLeft(player) + playerSpeed);
            }

            // player movement ends

Above is the player movement script, we are checking if the player can move left or right with in the screen. This script will also stop the player from moving out of the boundary.

There are two if statements here. In the first one we are checking if the move left Boolean is true AND player is still in the boundary from the left position, if so we use the CANVAS SET LEFT function to get the players current left position and deduct player speed value of 10 from that position. Every time we deduct from player left position it will move further left because left position value is always lower than the right position value.

Second if statement is checking for the right move Boolean to be true AND get the left position of the player and add 90 to it, if all those values are still less than the width of the window then move right.

Because all of these calculations are being done inside the games timer event it will look and feel fluent when it runs.

Below is the for each loop which has another for loop inside of it and it has 7 different if statements. The purpose of this for loop is to identify the enemy and the bullets rectangles inside of the canvas. Once we identify them, we can then move them accordingly so enemies only move downwards so we add to the top or Y location and bullets move upwards so we deduct from their top or Y location.

In here we also need to check collision between the enemy and the bullet rectangle. This is why we have an extra for each loop inside of the main for each loop. To explain this in simple terms a foreach loop uses a variable to identify the object. In the first one we are using the X variable and checking all of the rectangles available in the current state inside MyCanvas object. So, when we have two different objects such as an enemy object and a bullet object, we can’t check if X is equals to X, this value will always be true and it won’t be able to identify if they are overlapping. So, we use another for each loop and check for the enemy object inside of it so we can check if X is equal to Y this way we can effectively check if those two objects are overlapping each other.

Lets take a look at this part by part

            foreach (var x in MyCanvas.Children.OfType<Rectangle>())
            {
                // if any rectangle has the tag bullet in it
                if (x is Rectangle && (string)x.Tag == "bullet")
                {
                    // move the bullet rectangle towards top of the screen
                    Canvas.SetTop(x, Canvas.GetTop(x) - 20);

                    // make a rect class with the bullet rectangles properties
                    Rect bullet = new Rect(Canvas.GetLeft(x), Canvas.GetTop(x), x.Width, x.Height);

                    // check if bullet has reached top part of the screen
                    if (Canvas.GetTop(x) < 10)
                    {
                        // if it has then add it to the item to remove list
                        itemstoremove.Add(x);
                    }

Above is the fist part of the for each loop, inside of this first for each loop we are checking if x is a rectangle and it has a TAG which is a type of string(text) equals to bullet then we will deduct 20 from its top position. So with each frame the bullet will move up 20 pixels at a time. This is the line Canvas.SetTop(x, Canvas.GetCanvas(x) – 20); is doing.

Rect bullet = new Rect(Canvas.GetLeft(x), Canvas.GetTop(x), x.Width, x.Height); this line is creating an empty rect or hit box around the bullet so we can calculate if the bullet hits any other object in the game.

The last if statement is checking if the bullet has made it to top of the screen if so then we will add that bullet to the item to remove list. This list will used a lot in the coming code so be patient to see how we remove them permanently from the game later on.

Reminder – we are still inside the first loop and inside the first if statement that’s identifying the bullet. We will make another for each loop to identify the enemy to check for collision between the enemy and bullet.

                    // run another for each loop inside of the main loop this one has a local variable called y
                    foreach (var y in MyCanvas.Children.OfType<Rectangle>())
                    {
                        // if y is a rectangle and it has a tag called enemy
                        if (y is Rectangle && (string)y.Tag == "enemy")
                        {
                            // make a local rect called enemy and put the enemies properties into it
                            Rect enemy = new Rect(Canvas.GetLeft(y), Canvas.GetTop(y), y.Width, y.Height);

                            // now check if bullet and enemy is colliding or not
                            // if the bullet is colliding with the enemy rectangle
                            if (bullet.IntersectsWith(enemy))
                            {

                                itemstoremove.Add(x); // remove bullet
                                itemstoremove.Add(y); // remove enemy
                                score++; // add one to the score
                            }
                        }

                    }
                }

We run another for each loop this type we call the variable y instead of x. inside this for each loop we make a if statement that checks if y is a rectangle and y has a tag of enemy. If both of these statements are true then we will create a rect called enemy and link it to the enemy objects in the game. We did this the same way we did the bullet object.

After that we check if bullet rect interests or HITS the enemy rect created in the loops. If this statement is true then we will add both the X (bullet) and y (enemy) to the item to remove list and add one to the score by 1 (score++;).

Notice the extra end curly brackets end of the code above, we are ending the if statements, for loop and the other if statement. We are still inside the main for each loop. Now lets go outside the second for each loop and write the following.

                // outside the second loop lets check for the enemy again
                if (x is Rectangle && (string)x.Tag == "enemy")
                {
                    // if we find a rectangle with the enemy tag

                    Canvas.SetTop(x, Canvas.GetTop(x) + 10); // move the enemy downwards

                    // make a new enemy rect for enemy hit box
                    Rect enemy = new Rect(Canvas.GetLeft(x), Canvas.GetTop(x), x.Width, x.Height);

                    // first check if the enemy object has gone passed the player meaning
                    // its gone passed 700 pixels from the top
                    if (Canvas.GetTop(x) + 150 > 700)
                    {
                        // if so first remove the enemy object
                        itemstoremove.Add(x);
                        damage += 10; // add 10 to the damage
                    }

                    // if the player hit box and the enemy is colliding 
                    if (playerHitBox.IntersectsWith(enemy))
                    {
                        damage += 5; // add 5 to the damage
                        itemstoremove.Add(x); // remove the enemy object
                    }
                }

            }

In this one we are checking if x is a rectangle and x has a tag of enemy. You might be wondering why are we doing this when we have done that already inside the second foreach loop. When testing this app we found that animating the enemies object in the second for each loop made them faster then anticipated and it was glitchy so we are doing this outside the second loop and making sure that we are working efficiently on programming and from the system performance side.

Canvas.SetTop(x, Canvas.GetTop(x) + 10); This line is moving the enemy object down 10 pixels every frame so they will spawn off screen and move downwards to the player.

Rect enemy = new Rect(Canvas.GetLeft(x), Canvas.GetTop(x), x.Width, x.Height); This line is making a another rect called enemy which will help us calculate the collision between this object and the player object.

In the first if statement in this section we are checking if the enemy has left the screen below the player. The aim for this game is to protect your base as long as you can so if the enemy object has made it passed the player then we can add 10 damage to the damage integer and then add that enemy object to the item to remove list.

The second if statement from above is checking if the player hit box interests with or HIT the enemy object then add 5 to the damage integer and remove that enemy to the item to remove list.

Now we exit the if statement and for each loop.

            // if the score is greater than 5
            if (score > 5)
            {
                limit = 20; // reduce the limit to 20
                // now the enemies will spawn faster
            }

In this section above we are checking if the score is greater than 5 then we will reduce the limit integer to 20. This will make the enemies spawn faster on the screen thus making this game slightly challenging.

            // if the damage integer is greater than 99
            if (damage > 99)
            {
                gameTimer.Stop(); // stop the main timer
                damageText.Content = "Damaged: 100"; // show this on the damaged text
                damageText.Foreground = Brushes.Red; // change the text colour to 100
                MessageBox.Show("Well Done Star Captain!" + Environment.NewLine + "You have destroyed " + score + " Alien ships");
                // show the message box with the message inside of it
            }

In the if statement above we are checking if the damage integer has gone above 99 then we will stop the game timer, change the text on damage text label to damaged 100 and also change the label text colour to red. Lastly it will show a message box stating well done and how many alien ships you destroyed.

Now we finally come to the item to remove list part, see told you to be patient. In any game as important it is to know how to add objects its also important to know how to remove said objects when they are no longer necessary. If we did not do this then this game will slow down over time due to too many unused resources in the program. So we created this item to remove list with a type of rectangle and now we will run another for each loop here to check what’s inside of it.

            // check how many rectangles are inside of the item to remove list
            foreach (Rectangle y in itemstoremove)
            {
                // remove them permanently from the canvas
                MyCanvas.Children.Remove(y);
            }

In the for each loop above we are checking for rectangles inside the items to remove list and when we find them we will remove each of those items from the MyCanvas by using MyCanvas.Children.Remove(y);

Congratulations on following this tutorial so far. I know these are getting bigger and bigger each time but long as we get to do these together its fun for me to do them and I hope its fun for you too. The full C# code for this space shooter game is available on the next. Use it as a reference for your project just in case you have missed something or just want to see the source code.

Click on the debug button to start the game –

click the debug button to run the space shooter game

Now you should be able to move the player left to right and shoot bullets. The enemy objects should spawn and come down towards the player below are some screen caps of the game play

final space shooter game screen shots showing the functionalities

Noice work so far. Have fun playing the game.




7 responses to “WPF C# Tutorial – Create a space battle shooter game in Visual Studio”

  1. Daniel Rymes says:

    Having difficulties with URI definition. The original version failed during the build. Code compiled fine after replacing with relative version: `new Uri(@”../images/player.png”, UriKind.Relative)`. However, app is breaking, because it can’t find the image in …\bin\Debug\images\purple.png.

    Wondering if the issue could be related to URI syntax of if something’s wrong with the build process (e.g. missing/wrong item csproj). Any fix suggestions?

  2. Anhar Ali says:

    Hi Daniel, you made the images folder inside the debug folder. This folder needs to be in the main application directory. In page 1 of the tutorial it shows how to make the folder inside the solutions explorer, and then you can import the images into it.

  3. David Macák says:

    Thank you for this tutorial. I am new to C# and WPF and just found your fantastic web and your tutorials. I like this style of tutorials where you actually make something useful and fun. I made this and learned a lot by writing the code myself rather than ctrl+v.

    Also after limit = 20; it gets much harder 😀

  4. Hi Mr. Moo says:

    Well done thank you for all the education to the internet!!!!!!!!!!!! <3

  5. Matthew Marse says:

    a fun tutorial to do because we are in space shooting alien space *suits* I mean if that’s not fun

  6. Davor Kreß says:

    Your sites are very helpful and cool. Thank you very much.

  7. Anhar Ali says:

    Thank You. 🙂