WPF C# Tutorial – Create a Space Invaders game in Visual Studio

The Game Engine Function –

Every game has its own rules and conditions so does this game. Except the other games we can pick up and play this we will need to apply the rules right inside of the source code. This will be a long one so as usual lets take a full look at the event and then we can start breaking it down and explaining some of the core functionalities to you.

private void gameEngine(object sender, EventArgs e)
        {
            // this is the game engine event, this event will trigger every 20 milliseconds with the timer tick

            // to begin we start with declaring a rect class linking it back to the player 1 rectangle we made in the canvas
            Rect player = new Rect(Canvas.GetLeft(player1), Canvas.GetTop(player1), player1.Width, player1.Height);
            // show the remaining space invader numbers on the screen with enemies left label
            enemiesLeft.Content = "Invaders Left: " + totalEnemeis;

            // below is the player movement script

            // in the if statement below we are checking if the player is still inside the boundary from the left position
            // if so then we can move the player to towards left of the screen
            if (goLeft && Canvas.GetLeft(player1) > 0)
            {
                Canvas.SetLeft(player1, Canvas.GetLeft(player1) - 10);
            }
            // in the if statement below we are checking if the players left position plus 65 pixels is still inside the main application window from the right
            // if so we can move the player towards the right of the screen
            else if (goRight && Canvas.GetLeft(player1) + 80 < Application.Current.MainWindow.Width)
            {
                Canvas.SetLeft(player1, Canvas.GetLeft(player1) + 10);
            }


            //decrease 3 from the bullet timer interger every 20 milliseconds
            bulletTimer -= 3;

            // when the bullet timer integer reaches below 0
            // run the enemy bullet maker function and tell it where to place the bullet on screen
            if (bulletTimer < 0)
            {
                // we want the enemy bullet to be placed directly above the player character
                // this is why we are passing the player left position + 20 pixels
                // and the top position will be 10
                enemyBulletMaker((Canvas.GetLeft(player1) + 20), 10);
                // reset the bullet timer back to bullet timer limit value
                bulletTimer = bulletTimerLimit;
            }

            // if the total enemies number goes below 10
            // set the enemy speed to 20
            if (totalEnemeis < 10)
            {
                enemySpeed = 20;
            }

            // below is the code for collision detection between enemy, bullets, player and enemy bullets

            // run the foreach loop make a local variable x and scan through all of the rectangles available in my canvas
            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 left 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))
                            {
                                // remove the bullet, remove the enemy and deduct 1 from the total enemies integer
                                itemstoremove.Add(x);
                                itemstoremove.Add(y);
                                totalEnemeis -= 1;
                            }
                        }


                    }

                }

                // we are back in the main loop again, this timer we need to animate the enemies
                // check again if the any rectangle has the tag enemy inside it
                if (x is Rectangle && (string)x.Tag == "enemy")
                {
                    // move it towards right side of the screen with the enemy speed integer
                    Canvas.SetLeft(x, Canvas.GetLeft(x) + enemySpeed);

                    // if the enemeies have left the screen from the right
                    if (Canvas.GetLeft(x) > 820)
                    {
                        // position it back in the left
                        Canvas.SetLeft(x, -80);
                        // move it down the screen by 20 pixels
                        Canvas.SetTop(x, Canvas.GetTop(x) + (x.Height + 10));
                    }

                    // make another local rect called enemy and put the new enemy properites into it
                    Rect enemy = new Rect(Canvas.GetLeft(x), Canvas.GetTop(x), x.Width, x.Height);

                    // check if the player character and the enemy are colliding
                    if (player.IntersectsWith(enemy))
                    {
                        // stop the timer and show a message that says you lose end game here
                        dispatcherTimer.Stop();
                        MessageBox.Show("you lose");
                    }
                }


                // back at the main game loop again we need to check for enemy bullets now
                // check if any rectangle has the enemyBullet tag inside of it
                if (x is Rectangle && (string)x.Tag == "enemyBullet")
                {
                    // if we have found it then we will drop it towards bottom of the screen
                    Canvas.SetTop(x, Canvas.GetTop(x) + 10);

                    // if the bullet has gone passed the screen then we can add it to the remove list
                    if (Canvas.GetTop(x) > 480)
                    {
                        itemstoremove.Add(x);

                    }

                    // make a new local rect called enemy bullets and put the enemy bullets properites into it
                    Rect enemyBullets = new Rect(Canvas.GetLeft(x), Canvas.GetTop(x), x.Width, x.Height);

                    // check if the enemy bullet or the player rectangle is colliding

                    if (enemyBullets.IntersectsWith(player))

                    {

                        // if so stop the timer and show you lose message
                        // game ends here
                        dispatcherTimer.Stop();
                        MessageBox.Show("you lose");
                    }

                }
            }

            // this is the garbage collection loop
            // check for every rectangle thats added to the itemstoremove list
            foreach (Rectangle y in itemstoremove)
            {
                // remove them permanently from the canvas
                myCanvas.Children.Remove(y);
            }

            // if total enemies is 0
            if (totalEnemeis < 1)
            {
                // stop the timer and show you win message
                dispatcherTimer.Stop();
                MessageBox.Show("you win");
            }
        }

Every line is already commented in the code for your understanding but we will go over it again in parts to make sure we don’t leave any confusion with this event.

Rect player = new Rect(Canvas.GetLeft(player1), Canvas.GetTop(player1), player1.Width, player1.Height);
// show the remaining space invader numbers on the screen with enemies left label
enemiesLeft.Content = "Invaders Left: " + totalEnemeis;

This part above is create a new rect class and linking that to the player 1 rectangle we created in the canvas. Imagine the rect class being used a boundary checker. We cannot check for collision with the rectangle alone so we are importing the rectangles setting into this Rect class to make it easier to check for collisions between the player and enemy, player and enemy bullet, enemy and player bullet and so on.

Enemies left is the label we added to the screen, so here we are linking that to the total enemy’s integer we created in the make enemies’ function. This way we can keep track of how many enemies are on the screen.

            // if so then we can move the player to towards left of the screen
            if (goLeft && Canvas.GetLeft(player1) > 0)
            {
                Canvas.SetLeft(player1, Canvas.GetLeft(player1) - 10);
            }
            // in the if statement below we are checking if the players left position plus 65 pixels is still inside the main application window from the right
            // if so we can move the player towards the right of the screen
            else if (goRight && Canvas.GetLeft(player1) + 80 < Application.Current.MainWindow.Width)
            {
                Canvas.SetLeft(player1, Canvas.GetLeft(player1) + 10);
            }

The two if statements above are checking whether go left or go right is true and that the player character is still inside of the screen, if so then we can move the player character with the speed of 10 to either side of the screen. We could have done this inside the key down and key up event but its much more efficient and the animation is smoother using it inside the timer event.

            //decrease 3 from the bullet timer interger every 20 milliseconds
            bulletTimer -= 3;

            // when the bullet timer integer reaches below 0
            // run the enemy bullet maker function and tell it where to place the bullet on screen
            if (bulletTimer < 0)
            {
                // we want the enemy bullet to be placed directly above the player character
                // this is why we are passing the player left position + 20 pixels
                // and the top position will be 10
                enemyBulletMaker((Canvas.GetLeft(player1) + 20), 10);
                // reset the bullet timer back to bullet timer limit value
                bulletTimer = bulletTimerLimit;
            }

As you can see, we are deducting 3 from the bullet timer integer, if the integer Is below 0 then we can run the enemy bullet maker function an give the x axis of the player and y axis of 10 this way where ever the player it will come down towards it. Next, we reset the integer back to its original value we set in the bullet timer limit integer beginning of the code.

            // if the total enemies number goes below 10
            // set the enemy speed to 20
            if (totalEnemeis < 10)
            {
                enemySpeed = 20;
            }

This if statement is checking if there are less than 10 enemy invaders left on the screen if YES, we increase their speed to 20. Don’t want to make things too easy for the player now do we.

            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 left 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);
                    }

We are starting the for each loop above, this may look complicated but it isn’t long as you take it nice and slow. No rush in learning this ok. So, for each loop are used to find different components that may be present on the canvas, we have used lots of them before in older tutorial and we will use them more in the future because its very useful. In this foreach loop there is a x variable created and we are looking specifically for rectangles in this canvas.

This piece of code will loop with every tick and we can then interact with different rectangles with different tags in the game.

Canvas.SetTop(x, Canvas.GetTop(x) – 20); this part of the code is moving the bullet towards top of the screen. Set Top sets the top location or y axis of the object and inside the set top we are getting the top location of the bullet object first then its deducting 20 pixels each frame. This way the object will move towards top of the screen because top of the screen is always set to 0.

We are always making another Rect object called bullet, as we have done for the player object before this we are doing it now for the bullet object, this will come handy when we want to check for collision with the enemy invaders.

The last if statement in this part is checking if the bullet has left the screen, if YES we need to add this bullet to the items to remove list.

// 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))
                            {
                                // remove the bullet, remove the enemy and deduct 1 from the total enemies integer
                                itemstoremove.Add(x);
                                itemstoremove.Add(y);
                                totalEnemeis -= 1;
                            }
                        }
                    }
                }

This for each loop will be inside the main foreach loop, we need this loop because we have to differentiate the bullet and the enemy objects. This for each loop has a variable called Y and we are also scanning the canvas for any rectangle objects present. If the new Y variable is a rectangle and has a tag called enemy then we make a new Rect class for the enemy to record the collisions.

The last if statement is checking if the enemy and bullet are colliding, if YES we add the bullet and then enemy to items to remove list and deduct 1 from the total enemies integer. This way we can keep track of how many enemies are still on the screen and how many have been shot down.

The foreach loop we are using above is only to identify the enemy objects, create a rect class around it and check for collision.

                // we are back in the main loop again, this timer we need to animate the enemies
                // check again if the any rectangle has the tag enemy inside it
                if (x is Rectangle && (string)x.Tag == "enemy")
                {
                    // move it towards right side of the screen with the enemy speed integer
                    Canvas.SetLeft(x, Canvas.GetLeft(x) + enemySpeed);

                    // if the enemeies have left the screen from the right
                    if (Canvas.GetLeft(x) > 820)
                    {
                        // position it back in the left
                        Canvas.SetLeft(x, -80);
                        // move it down the screen by 20 pixels
                        Canvas.SetTop(x, Canvas.GetTop(x) + (x.Height + 10));
                    }

In the above part of the code we are back in the main loop, we are out of the Y variable loop now. In this part of the code we will identify the enemy rectangles on the screen and then we will be moving them around the left or x axis first. Canvas.SetLeft(x, Canvas.GetLeft(x) + enemySpeed); this line is getting the enemy invaders across the screen. We are using the set left to set where we want the enemy invaders to be on the screen and inside of that we get the enemy invaders current location and then increase it with the enemy speed integer.

The if statement is checking if the enemy objects moved passed 820 pixels if YES it will set the left of the object to -80 and set the top of the object 10 pixels down each time. This is the effect we want for this game and helps us get the enemy objects moving down towards the player.

                    // make another local rect called enemy and put the new enemy properties into it
                    Rect enemy = new Rect(Canvas.GetLeft(x), Canvas.GetTop(x), x.Width, x.Height);

                    // check if the player character and the enemy are colliding
                    if (player.IntersectsWith(enemy))
                    {
                        // stop the timer and show a message that says you lose end game here
                        dispatcherTimer.Stop();
                        MessageBox.Show("you lose");
                    }
                }

In code above its creating a new Rect enemy (which we have used before in the other loop) to test collision with the player object. If the player and enemy collide in this case, it will stop the timer and show you lose message. Remember you can only do this Intersects with method with two Rect’s not rectangles. The player rect class was created earlier in the games engine event.

                // back at the main game loop again we need to check for enemy bullets now
                // check if any rectangle has the enemyBullet tag inside of it
                if (x is Rectangle && (string)x.Tag == "enemyBullet")
                {
                    // if we have found it then we will drop it towards bottom of the screen
                    Canvas.SetTop(x, Canvas.GetTop(x) + 10);

                    // if the bullet has gone passed the screen then we can add it to the remove list
                    if (Canvas.GetTop(x) > 480)
                    {
                        itemstoremove.Add(x);

                    }

In the code above its check if any rectangle on the screen has the enemy bullet tag attached to it, if so it will add 10 pixels to the speed of it and moving towards the player below. The last if statement is checking if the enemy bullet has gone passed the screen, then it will get added to the items to remove list.

                    // make a new local rect called enemy bullets and put the enemy bullets properites into it
                    Rect enemyBullets = new Rect(Canvas.GetLeft(x), Canvas.GetTop(x), x.Width, x.Height);

                    // check if the enemy bullet or the player rectangle is colliding

                    if (enemyBullets.IntersectsWith(player))

                    {

                        // if so stop the timer and show you lose message
                        // game ends here
                        dispatcherTimer.Stop();
                        MessageBox.Show("you lose");
                    }

                }
            }

In the code above its creating a new Rect class for the enemy bullet. We are doing this so we can check for the collision between the player and the enemy bullet. The if enemy bullet and player object is colliding then we stop the timer and show you lose message.

// this is the garbage collection loop
            // check for every rectangle thats added to the itemstoremove list
            foreach (Rectangle y in itemstoremove)
            {
                // remove them permanently from the canvas
                myCanvas.Children.Remove(y);
            }

            // if total enemies is 0
            if (totalEnemeis < 1)
            {
                // stop the timer and show you win message
                dispatcherTimer.Stop();
                MessageBox.Show("you win");
            }
        }

We have one last foreach loop to go through this is our garbage collector. All of the items we’ve been adding to the items to remove list will still exist in the memory so we need to dispose them from this application and that will help free up some RAM for there and it wont slow down the game. We are running this foreach loop to check if there are any rectangles present inside the items to remove list if there are, we will use my canvas tag to remove each rectangle from inside of it.

The last if statement of this event is checking if the total enemies integer is less than 0 if so we have shot down all of the invaders and saved earth to live another day. Stop the main timer and show you win message. Press the Debug button, Press F5 or CTRL F5 to start running the game and will see the following.

All the requirements for this game is now met, we have different enemies showing up, they move right and then move down, speed up when invaders are limited on the screen, game ends and player can win. We did a lot in this, you should be proud of yourself for following it through. Go to the the Full Code page below to see the full C# script for this game.




Comments are closed.