WPF C# Tutorial – Create a space battle shooter game in Visual Studio
- Subject: WPF C# Tutorials
- Learning Time: 3 hours
Full Source C# for the Space Shooter Game Tutorial in WPF-
Below are all of the code and logic for the space shooter game in WPF. XAML code for this project is available on the first page so this is the C# script that makes the game work in the background. The green lines are all comments so you can use them or dispose them if you wish. One of the important programming principle is that you comment on the code. if you are using this as a course work please make sure you use your own comments and change the project to your requirement and not submit this as your own work.
Leave a comment for us to see how you got on with the project, we will be very pleased to read your comments.
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_shooter_game { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { //make a game timer DispatcherTimer gameTimer = new DispatcherTimer(); // move left and move right boolean decleration bool moveLeft, moveRight; // make a new items remove list List<Rectangle> itemstoremove = new List<Rectangle>(); // make a new random class to generate random numbers from Random rand = new Random(); int enemySpriteCounter; // int to help change enemy images int enemyCounter = 100; // enemy spawn time int playerSpeed = 10; // player movement speed int limit = 50; // limit of enemy spawns int score = 0; // default score int damage = 0; // default damage Rect playerHitBox; // player hit box to check for collision against enemy public MainWindow() { InitializeComponent(); gameTimer.Interval = TimeSpan.FromMilliseconds(20); // link the game engine event to the timer gameTimer.Tick += gameEngine; // start the timer gameTimer.Start(); // make my canvas focus of this game MyCanvas.Focus(); // make a new image brush instance called bg ImageBrush bg = new ImageBrush(); // pass the purple image as the bg image source bg.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/purple.png")); // set bg to tile mode bg.TileMode = TileMode.Tile; // set the height and width of bg image brush bg.Viewport = new Rect(0, 0, 0.15, 0.15); // set the bg view port unit bg.ViewportUnits = BrushMappingMode.RelativeToBoundingBox; // assign bg as the background of my canvas MyCanvas.Background = bg; // make a player image, image brush ImageBrush playerImage = new ImageBrush(); // load the player image into it playerImage.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/player.png")); // assign the player to the player rectangle fill player.Fill = playerImage; } private void onKeyDown(object sender, KeyEventArgs e) { // if the left key is pressed // set move left to true // if the right key is pressed // set move right to true if (e.Key == Key.Left) { moveLeft = true; } if (e.Key == Key.Right) { moveRight = true; } } private void onKeyUp(object sender, KeyEventArgs e) { // if the left key is released // set move left to false // if the right key is released // set move right to false if (e.Key == Key.Left) { moveLeft = false; } if (e.Key == Key.Right) { moveRight = false; } // if the space key is released // make a new rectangle called new bullet // give this rectangle a tag called bullet // height set to 20, width set to 5 // background colour white and border colour red if (e.Key == Key.Space) { Rectangle newBullet = new Rectangle { Tag = "bullet", Height = 20, Width = 5, Fill = Brushes.White, Stroke = Brushes.Red }; // place the bullet on top of the player location Canvas.SetTop(newBullet, Canvas.GetTop(player) - newBullet.Height); // place the bullet middle of the player image Canvas.SetLeft(newBullet, Canvas.GetLeft(player) + player.Width / 2); // add the bullet to the screen MyCanvas.Children.Add(newBullet); } } private void makeEnemies() { // this function will make the enemies for us including assignning them images ImageBrush enemySprite = new ImageBrush(); // make a new image brush called enemy sprite enemySpriteCounter = rand.Next(1, 5); // generate a random number inside the enemy sprite counter integer // below switch statement will check what number is generated inside the enemy sprite counter // and then assign a new image to the enemy sprite image brush depending on the number switch (enemySpriteCounter) { case 1: enemySprite.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/1.png")); break; case 2: enemySprite.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/2.png")); break; case 3: enemySprite.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/3.png")); break; case 4: enemySprite.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/4.png")); break; case 5: enemySprite.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/5.png")); break; default: enemySprite.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/1.png")); break; } // make a new rectangle called new enemy // this rectangle has a enemy tag, height 50 and width 56 pixels // background fill is assigned to the randomly generated enemy sprite from the switch statement above Rectangle newEnemy = new Rectangle { Tag = "enemy", Height = 50, Width = 56, Fill = enemySprite }; Canvas.SetTop(newEnemy, -100); // set the top position of the enemy to -100 // randomly generate the left position of the enemy Canvas.SetLeft(newEnemy, rand.Next(30, 430)); // add the enemy object to the screen MyCanvas.Children.Add(newEnemy); // garbage collection GC.Collect(); // collect any unused resources for this game } 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); } } } }
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?
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.
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 😀
Well done thank you for all the education to the internet!!!!!!!!!!!! <3
a fun tutorial to do because we are in space shooting alien space *suits* I mean if that’s not fun
Your sites are very helpful and cool. Thank you very much.
Thank You. 🙂