WPF C# Tutorial – Create a simple racing game in visual studio

In this tutorial we will be making top down racing game in visual studio with WPF and C# programming.  You will control the player yellow car in the game and avoid other cars in the road by going left or right. You can also collect a star in the game to get invincibility for short amount of time. When you collect the star, you won’t be affected by any other traffic while you are in the power mode. This game will be made from WPF components and C# scripts.

Lesson Objectives –

  • Create a simple racing game in visual studio with WPF and C#
  • Move player left and right using the key down and key up events
  • Import images for the player car, player power mode animation and traffic cars
  • Switch traffic car images real time as the game is running
  • Animate the road markings in the WPF Canvas
  • Move traffic cars towards the player and collide with the player
  • Collide with star objects and activate the power mode
  • Speed up the game as you score higher in the game

Video Tutorial –

 

Download the game images here

 

Xaml Code –

<Window x:Class="Car_Racing_Game_WPF_MOO_ICT.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Car_Racing_Game_WPF_MOO_ICT"
        mc:Ignorable="d"
        Title="Top Down Racing Game MOO ICT" Height="517" Width="525">
    <Canvas Background="Gray" Name="myCanvas" Focusable="True" KeyDown="OnKeyDown" KeyUp="OnKeyUP">

        <Rectangle Height="106" Width="20" Fill="White" Tag="roadMarks" Canvas.Left="237" Canvas.Top="-152" />
        <Rectangle Height="106" Width="20" Fill="White" Tag="roadMarks" Canvas.Left="237" Canvas.Top="10" />
        <Rectangle Height="106" Width="20" Fill="White" Tag="roadMarks" Canvas.Left="237" Canvas.Top="176" />
        <Rectangle Height="106" Width="20" Fill="White" Tag="roadMarks" Canvas.Left="237" Canvas.Top="348" />


        <Rectangle Tag="Car" Height="80" Width="55" Fill="Blue" Canvas.Left="90" Canvas.Top="56" />
        <Rectangle Tag="Car" Height="80" Width="55" Fill="Purple" Canvas.Left="381" Canvas.Top="286" />


        <Rectangle Name="player" Height="80" Width="55" Fill="Yellow" Canvas.Left="222" Canvas.Top="374" />

        <Label Name="scoreText" Content="Survived: 00 Seconds" FontSize="18" FontWeight="Bold" />


    </Canvas>
</Window>

Inside the XAML code here we are setting up the height and width of the game screen. The we add a Canvas and inside the canvas we are defining the background of the canvas, name of the canvas, key down event and key up event. Its important to set up the Focusable option here because when the game loads we will need to verify which element inside of this game will be the main focus also without the focusable option the key down and key up events won’t register.

After that we have 4 different rectangles defined, these rectangles are the road markings. they will be placed middle of the scene and when the game runs it will move down and give the illusion of a moving straight road.

3 more rectangles are added to the game, 2 of them are the other cars in the road that the player will be interacting with the last rectangle is the player. Inside of the other cars we are defining the Tag, height, width and positions. inside the player car we are doing the same except we don’t need the Tag we will add a name for the player instead.

Lastly we are adding the label to the canvas where we will show how long the player survived in the game.

C# Code for the Racing game

All of the code for the C# programming in this game has been commented, so its all explained in the comments.

using System;
using System.Collections.Generic;
using System.Data.SqlTypes;
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; // import the threading namespace first, this way we can use the dispatcher time inside of the c# script

namespace Car_Racing_Game_WPF_MOO_ICT
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        DispatcherTimer gameTimer = new DispatcherTimer(); // create a new instance of the dispatcher time called gameTimer
        List<Rectangle> itemRemover = new List<Rectangle>(); // make a new list called item remove, this list will be used to remove any unused rectangles in the game 

        Random rand = new Random(); // make a new instance of the random class called rand

        ImageBrush playerImage = new ImageBrush(); // create a new image brush for the player
        ImageBrush starImage = new ImageBrush(); // create a new image brush for the star

        Rect playerHitBox; // this rect object will be used to calculate the player hit area with other objects

        // set the game integers including, speed for the traffic and road markings, player speed, car numbers, star counter and power mode counter
        int speed = 15;
        int playerSpeed = 10;
        int carNum;
        int starCounter = 30;
        int powerModeCounter = 200;

        // create two doubles one for score and other called i, this one will be used to animate the player car when we reach the power mode
        double score;
        double i;

        // we will need 4 boolean altogether for this game, since all of them will be false at the start we are defining them in one line. 
        bool moveLeft, moveRight, gameOver, powerMode;


        public MainWindow()
        {
            InitializeComponent();

            myCanvas.Focus(); // set the main focus of the program to the my canvas element, with this line it wont register the keyboard events

            gameTimer.Tick += GameLoop; // link the game timer event to the game loop event
            gameTimer.Interval = TimeSpan.FromMilliseconds(20); // this timer will run every 20 milliseconds

            StartGame(); // run the start game function
        }

        private void GameLoop(object sender, EventArgs e)
        {
            score += .05; // increase the score by .5 each tick of the timer

            starCounter -= 1; // reduce 1 from the star counter each tick

            scoreText.Content = "Survived " + score.ToString("#.#") + " Seconds"; // this line will show the seconds passed in decimal numbers in the score text label

            playerHitBox = new Rect(Canvas.GetLeft(player), Canvas.GetTop(player), player.Width, player.Height); // assign the player hit box to the player

            // below are two if statements that are checking the player can move or right in the scene. 
            if (moveLeft == true && Canvas.GetLeft(player) > 0)
            {
                Canvas.SetLeft(player, Canvas.GetLeft(player) - playerSpeed);
            }
            if (moveRight == true && Canvas.GetLeft(player) + 90 < Application.Current.MainWindow.Width)
            {
                Canvas.SetLeft(player, Canvas.GetLeft(player) + playerSpeed);
            }

            // if the star counter integer goes below 1 then we run the make star function and also generate a random number inside of the star counter integer
            if (starCounter < 1)
            {
                MakeStar();
                starCounter = rand.Next(600, 900);
            }

            // below is the main game loop, inside of this loop we will go through all of the rectangles available in this game
            foreach (var x in myCanvas.Children.OfType<Rectangle>())
            {
                // first we search through all of the rectangles in this game

                // then we check if any of the rectangles has a tag called road marks
                if ((string)x.Tag == "roadMarks")
                {
                    // if we find any of the rectangles with the road marks tag on it then 

                    Canvas.SetTop(x, Canvas.GetTop(x) + speed); // move it down using the speed variable

                    // if the road marks goes below the screen then move it back up top of the screen
                    if (Canvas.GetTop(x) > 510)
                    {
                        Canvas.SetTop(x, -152);
                    }

                } // end of the road marks if statement

                // if we find a rectangle with the car tag on it
                if ((string)x.Tag == "Car")
                {

                    Canvas.SetTop(x, Canvas.GetTop(x) + speed); // move the rectangle down using the speed variable

                    // if the car has left the scene then run then run the change cars function with the current x rectangle inside of it
                    if (Canvas.GetTop(x) > 500)
                    {
                        ChangeCars(x);
                    }

                    // create a new rect called car hit box and assign it to the x which is the cars rectangle
                    Rect carHitBox = new Rect(Canvas.GetLeft(x), Canvas.GetTop(x), x.Width, x.Height);

                    // if the player hit box and the car hit box collide and the power mode is ON
                    if (playerHitBox.IntersectsWith(carHitBox) && powerMode == true)
                    {
                        // run the change cars function with the cars rectangle X inside of it
                        ChangeCars(x);
                    }
                    else if (playerHitBox.IntersectsWith(carHitBox) && powerMode == false)
                    {
                        // if the power is OFF and car and the player collide then
                        
                        gameTimer.Stop(); // stop the game timer
                        scoreText.Content += " Press Enter to replay"; // add this text to the existing text on the label
                        gameOver = true; // set game over boolean to true
                    }

                } // end of car if statement

                // if we find a rectangle with the star tag on it
                if ((string)x.Tag == "star")
                {
                    // move it down the screen 5 pixels at a time
                    Canvas.SetTop(x, Canvas.GetTop(x) + 5);

                    // create a new rect with for the star and pass in the star X values inside of it
                    Rect starHitBox = new Rect(Canvas.GetLeft(x), Canvas.GetTop(x), x.Width, x.Height);

                    // if the player and the star collide then
                    if (playerHitBox.IntersectsWith(starHitBox))
                    {
                        // add the star to the item remover list
                        itemRemover.Add(x);

                        // set power mode to true
                        powerMode = true;

                        // set power mode counter to 200
                        powerModeCounter = 200;

                    }

                    // if the star goes beyon 400 pixels then add it to the item remover list
                    if (Canvas.GetTop(x) > 400)
                    {
                        itemRemover.Add(x);
                    }

                } // end of start if statement
            } // end of for each loop

            // if the power mode is true
            if (powerMode == true)
            {
                powerModeCounter -= 1; // reduce 1 from the power mode counter 
                // run the power up function
                PowerUp();
                // if the power mode counter goes below 1 
                if (powerModeCounter < 1)
                {
                    // set power mode to false
                    powerMode = false;
                }
            }
            else
            {
                // if the mode is false then change the player car back to default and also set the background to gray
                playerImage.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/playerImage.png"));
                myCanvas.Background = Brushes.Gray;
            }

            // each item we find inside of the item remove we will remove it from the canvas
            foreach (Rectangle y in itemRemover)
            {
                myCanvas.Children.Remove(y);
            }

            // below are the score and speed configurations for the game
            // as you progress in the game you will score higher and traffic speed will go up

            if (score >= 10 && score < 20  )
            {
                speed = 12;
            }

            if (score >= 20 && score < 30)
            {
                speed = 14;
            }
            if (score >= 30 && score < 40)
            {
                speed = 16;
            }
            if (score >= 40 && score < 50)
            {
                speed = 18;
            }
            if (score >= 50 && score < 80)
            {
                speed = 22;
            }


        }

        private void OnKeyDown(object sender, KeyEventArgs e)
        {
            // key down function will listen for you the user to press the left or right key and it will change the designated boolean to true

            if (e.Key == Key.Left)
            {
                moveLeft = true;
            }
            if (e.Key == Key.Right)
            {
                moveRight = true;
            }
        }

        private void OnKeyUP(object sender, KeyEventArgs e)
        {
            // when the player releases the left or right key it will set the designated boolean to false

            if (e.Key == Key.Left)
            {
                moveLeft = false;
            }
            if (e.Key == Key.Right)
            {
                moveRight = false;
            }

            // in this case we will listen for the enter key aswell but for this to execute we will need the game over boolean to be true
            if (e.Key == Key.Enter && gameOver == true)
            {
                // if both of these conditions are true then we will run the start game function
                StartGame();
            }
        }

        private void StartGame()
        {
            // thi sis the start game function, this function to reset all of the values back to their default state and start the game

            speed = 8; // set speed to 8
            gameTimer.Start(); // start the timer

            // set all of the boolean to false
            moveLeft = false; 
            moveRight = false;
            gameOver = false;
            powerMode = false;

            // set score to 0
            score = 0;
            // set the score text to its default content
            scoreText.Content = "Survived: 0 Seconds";
            // set up the player image and the star image from the images folder
            playerImage.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/playerImage.png"));
            starImage.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/star.png"));
            // assign the player image to the player rectangle from the canvas
            player.Fill = playerImage;
            // set the default background colour to gray
            myCanvas.Background = Brushes.Gray;

            // run a initial foreach loop to set up the cars and remove any star in the game

            foreach (var x in myCanvas.Children.OfType<Rectangle>())
            {
                // if we find any rectangle with the car tag on it then we will
                if ((string)x.Tag == "Car")
                {
                    // set a random location to their top and left position
                    Canvas.SetTop(x, (rand.Next(100, 400) * -1));
                    Canvas.SetLeft(x, rand.Next(0, 430));
                    // run the change cars function
                    ChangeCars(x);
                }

                // if we find a star in the beginning of the game then we will add it to the item remove list
                if ((string)x.Tag == "star")
                {
                    itemRemover.Add(x);
                }

            }
            // clear any items inside of the item remover list at the start
            itemRemover.Clear();
        }

        private void ChangeCars(Rectangle car)
        {

            // we want the game to change the traffic car images as they leave the scene and come back to it again

            carNum = rand.Next(1, 6); // to start lets generate a random number between 1 and 6

            ImageBrush carImage = new ImageBrush(); // create a new image brush for the car image 

            // the switch statement below will see what number have generated for the car num integer and 
            // based on that number it will assign a different image to the car rectangle
            switch (carNum)
            {
                case 1:
                    carImage.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/car1.png"));
                    break;
                case 2:
                    carImage.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/car2.png"));
                    break;
                case 3:
                    carImage.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/car3.png"));
                    break;
                case 4:
                    carImage.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/car4.png"));
                    break;
                case 5:
                    carImage.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/car5.png"));
                    break;
                case 6:
                    carImage.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/car6.png"));
                    break;
            }

            car.Fill = carImage; // assign the chosen car image to the car rectangle

            // set a random top and left position for the traffic car
            Canvas.SetTop(car, (rand.Next(100, 400) * -1));
            Canvas.SetLeft(car, rand.Next(0, 430));
        }

        private void PowerUp()
        {
            // this is the power up function, this function will run when the player collects the star in the game

            i += .5; // increase i by .5 


            // if i is greater than 4 then reset i back to 1
            if (i > 4)
            {
                i = 1;
            }

            // with each increment of the i we will change the player image to one of the 4 images below

            switch (i)
            {
                case 1:
                    playerImage.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/powermode1.png"));
                    break;
                case 2:
                    playerImage.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/powermode2.png"));
                    break;
                case 3:
                    playerImage.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/powermode3.png"));
                    break;
                case 4:
                    playerImage.ImageSource = new BitmapImage(new Uri("pack://application:,,,/images/powermode4.png"));
                    break;
            }

            // change the background to light coral colour
            myCanvas.Background = Brushes.LightCoral;


        }

        private void MakeStar()
        {
            // this is the make star function
            // this function will create a rectangle, assign the star image to and place it on the canvas

            // creating a new star rectangle with its own properties inside of it
            Rectangle newStar = new Rectangle
            {
                Height = 50,
                Width = 50, 
                Tag = "star",
                Fill = starImage
            };

            // set a random left and top position for the star
            Canvas.SetLeft(newStar, rand.Next(0, 430));
            Canvas.SetTop(newStar, (rand.Next(100, 400) * -1));

            // finally add the new star to the canvas to be animated and to interact with the player
            myCanvas.Children.Add(newStar);

        }
    }
}

 

 

 

 




Comments are closed.