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

Full Source For Space Invaders Game in WPF and C#–

Below is the full source code for the space inavders game we created. Use them as you would make sure you use your own comments on this game, this way you can reinforce learning as you are completing different projects.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using System.Windows.Threading; // add this for the timer

namespace space_invaders
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        // go left and right boolean are set to false
        bool goLeft, goRight = false;
        // this list items to remove will be used as a garbage collector
        List<Rectangle> itemstoremove = new List<Rectangle>();
        // this int enemy images will help us change enemy pictures
        int enemyImages = 0;
        // this is the enemy bullet timer
        int bulletTimer;
        // this is the enemy bullet timer limit and frequency
        int bulletTimerLimit = 90;
        // save the total number of enemies
        int totalEnemeis;
        // make a new instance of the dispatch timer class
        DispatcherTimer dispatcherTimer = new DispatcherTimer();
        // image brush class that we will use as the player image called player skin
        ImageBrush playerSkin = new ImageBrush();
        // the default enemy speed
        int enemySpeed = 6;

        public MainWindow()
        {
            InitializeComponent();

            // set up the timer and events
            // link the dispatcher timer to a event called game engine
            dispatcherTimer.Tick += gameEngine;
            // this timer will run every 20 milliseconds
            dispatcherTimer.Interval = TimeSpan.FromMilliseconds(20);
            // start the timer
            dispatcherTimer.Start();
            // load the player images from the images folder
            playerSkin.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/player.png"));
            // assign the new player skin to the rectangle
            player1.Fill = playerSkin;
            // run the make enemies function and tell it to make 30 enemies
            makeEnemies(30);
        }

        private void Canvas_KeyisDown(object sender, KeyEventArgs e)
        {
            // this is the key down event
            // if the left key is pressed set go left to true
            // if the right key is pressed set go right to true
            if (e.Key == Key.Left)
            {
                goLeft = true;
            }
            if (e.Key == Key.Right)
            {
                goRight = true;
            }
        }

        private void Canvas_KeyIsUp(object sender, KeyEventArgs e)
        {
            // this is the key up event
            // if the left key is let go set go left to false
            // if the right key is let go set go right to false

            if (e.Key == Key.Left)
            {
                goLeft = false;
            }
            if (e.Key == Key.Right)
            {
                goRight = false;
            }

            // below you have the if statement that will make the bullets
            // check if the space key is let go
            if (e.Key == Key.Space)
            {
                // clear all the items from the items to remove list first
                itemstoremove.Clear();

                // make a new rectangle called new bullet and add a tag called bullet, height 20 width 5 backgroubnd white and border to red
                Rectangle newBullet = new Rectangle
                {
                    Tag = "bullet",
                    Height = 20,
                    Width = 5,
                    Fill = Brushes.White,
                    Stroke = Brushes.Red
                };

                // place the bullet where the player is
                Canvas.SetTop(newBullet, Canvas.GetTop(player1) - newBullet.Height);
                Canvas.SetLeft(newBullet, Canvas.GetLeft(player1) + player1.Width / 2);
                // add the bullet to the screen
                myCanvas.Children.Add(newBullet);

            }
        }

        private void enemyBulletMaker(double x, double y)
        {
            // this function creates the enemy bullets firing towards the player object in the game
            // see this function is passing through 2 variables x and y these will be location where we place the bullets
            // first create a new rectangle
            // this rectangle will have a tag called enemy bullet, height 40 pixels, width 15 pixels, background yellowm border black and border size 5
            Rectangle newEnemyBullet = new Rectangle
            {
                Tag = "enemyBullet",
                Height = 40,
                Width = 15,
                Fill = Brushes.Yellow,
                Stroke = Brushes.Black,
                StrokeThickness = 5

            };

            // now we place the bullets top location to the Y variable
            Canvas.SetTop(newEnemyBullet, y);
            // set the left location to the X location
            Canvas.SetLeft(newEnemyBullet, x);
            // add the bullet to the screen
            myCanvas.Children.Add(newEnemyBullet);
        }

        private void makeEnemies(int limit)
        {
            // make a local integer called left and set to 0
            int left = 0;
            // save the enemy limit as as the total enemy
            totalEnemeis = limit;

            // this is the for loop that will make all of the enemies for this game
            // if the limit is set to 10 this loop will run 10 times if set 20 to then 20 times and so on
            for (int i = 0; i < limit; i++)
            {
                // with each loop 
                // will create a new enemy skin image brush to be used with the enemy rectangle
                ImageBrush enemySkin = new ImageBrush();

                // make a new rectangle called new enemy
                // inside this rectangle we set the properties to tag called enemy 45 height and width and link the enemy skin as the fill
                Rectangle newEnemy = new Rectangle
                {
                    Tag = "enemy",
                    Height = 45,
                    Width = 45,
                    Fill = enemySkin,

                };

                // set the starting location of the space inavder
                Canvas.SetTop(newEnemy, 10); // this is the top location
                Canvas.SetLeft(newEnemy, left); // this is the left location
                // add one to the scene 
                myCanvas.Children.Add(newEnemy);
                // change the to -60
                left -= 60;

                // add 1 to the enemy images integer
                enemyImages++;
                // if enemy images integer goes aove 8 
                // then we set the integer back to 1
                if (enemyImages > 8)
                {
                    enemyImages = 1;
                }

                // the switch statement below is checking the enemy images integer
                // with each number it will assign a new skin to the enemy
                // this switch statement will run throughout the loop and it will help us make use of those space invader images we imported earlier
                // it will look for what number is in the enemy images integer and then assign that image to the enemy skin class and then break the loop. 
                switch (enemyImages)
                {
                    case 1:
                        enemySkin.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/invader1.gif"));
                        // if the enemy images number comes up as 1 we can change the image source to the invader 1 GIF file
                        break;
                    case 2:
                        enemySkin.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/invader2.gif"));
                        // if the enemy images number comes up as 1 we can change the image source to the invader 2 GIF file
                        break;
                    case 3:
                        enemySkin.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/invader3.gif"));
                        // if the enemy images number comes up as 1 we can change the image source to the invader 3 GIF file
                        break;
                    case 4:
                        enemySkin.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/invader4.gif"));
                        // if the enemy images number comes up as 1 we can change the image source to the invader 4 GIF file
                        break;
                    case 5:
                        enemySkin.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/invader5.gif"));
                        // if the enemy images number comes up as 1 we can change the image source to the invader 5 GIF file
                        break;
                    case 6:
                        enemySkin.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/invader6.gif"));
                        // if the enemy images number comes up as 1 we can change the image source to the invader 6 GIF file
                        break;
                    case 7:
                        enemySkin.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/invader7.gif"));
                        // if the enemy images number comes up as 1 we can change the image source to the invader 7 GIF file
                        break;
                    case 8:
                        enemySkin.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/invader8.gif"));
                        // if the enemy images number comes up as 1 we can change the image source to the invader 8 GIF file
                        break;
                }
            }
        }

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

 




Comments are closed.