WPF C# Tutorial – Create Parallax Scrolling Endless Runner Game in Visual Studio

The Game Engine

We made it to the game engine event, this is the longest event or function we have in this game. This event is linked to the game timer so each time it ticks (once every 20 milliseconds) this entire event will load and make changes to the game as we have instructed. The full game engine source code is shown below, we will explain this function in chunks so scroll down when you want to fully understand what is going on here.

private void gameEngine(object sender, EventArgs e)
        {
            // move the player character down using the speed integer
            Canvas.SetTop(player, Canvas.GetTop(player) + speed);
            // move the background 3 pixels to the left each tick
            Canvas.SetLeft(background, Canvas.GetLeft(background) - 3);
            Canvas.SetLeft(background2, Canvas.GetLeft(background2) - 3);
            // move the obstacle rectangle to the left 12 pixels per tick
            Canvas.SetLeft(obstacle, Canvas.GetLeft(obstacle) - 12);
            // link the score text label to the score integer
            scoreText.Content = "Score: " + score;

            // assign the player hit box to the player, gound hit box to the ground rectangle and obstacle hit box to the obstacle rectangle
            playerHitBox = new Rect(Canvas.GetLeft(player), Canvas.GetTop(player), player.Width, player.Height);
            groundHitBox = new Rect(Canvas.GetLeft(ground), Canvas.GetTop(ground), ground.Width, ground.Height);
            obstacleHitBox = new Rect(Canvas.GetLeft(obstacle), Canvas.GetTop(obstacle), obstacle.Width, obstacle.Height);

            // check player and ground collision
            // IF player hits the ground 
            if (playerHitBox.IntersectsWith(groundHitBox))
            {
                //if the player is on the ground set the speed to 0
                speed = 0;
                // place the character on top of the ground rectangle
                Canvas.SetTop(player, Canvas.GetTop(ground) - player.Height);
                // set jumping to false
                jumping = false;
                // add .5 to the sprite int double
                spriteInt += .5;
                // if the sprite int goes above 8
                if (spriteInt > 8)
                {
                    // reset the sprite int to 1
                    spriteInt = 1;
                }
                // pass the sprite int values to the run sprite function
                runSprite(spriteInt);
            }

            //if the player hit the obstacle
            if (playerHitBox.IntersectsWith(obstacleHitBox))
            {
                // set game over boolean to true
                gameover = true;
                // stop the game timer
                gameTimer.Stop();

            }

            //if jumping boolean is true
            if (jumping)
            {
                // set speed integer to -9 so the player will go upwards
                speed = -9;
                // reduce the force integer
                force--;
            }
            else
            {
                // if jumping is not true then set speed to 12
                speed = 12;
            }

            // if force is less than 0 
            if (force < 0)
            {
                // set jumping boolean to false
                jumping = false;
            }

            // parallax scrolling code for c#
            // the code below will scroll the background simultaneously and make it seem endless

            // check the first background
            // if the first background X position goes below -1262 pixels
            if (Canvas.GetLeft(background) < -1262)
            {
                // position the first background behind the second background
                // below we are setting the backgrounds left, to background2 width position
                Canvas.SetLeft(background, Canvas.GetLeft(background2) + background2.Width);
            }
            // we do the same for the background 2
            // if background 2 X position goes below -1262
            if (Canvas.GetLeft(background2) < -1262)
            {
                // position the second background behind the first background
                // below we are setting background 2s left position or X position to backgrounds width position
                Canvas.SetLeft(background2, Canvas.GetLeft(background) + background.Width);
            }

            // if the obstacle goes beyond -50 location
            if (Canvas.GetLeft(obstacle) < -50)
            {
                // set the left position of the obstacle to 950 pixels
                Canvas.SetLeft(obstacle, 950);
                // randomly set the top positio of the obstacle from the array we created earlier
                // this will randomly pick a position from the array so it won't be the same each time it comes around the screen
                Canvas.SetTop(obstacle, obstaclePosition[rand.Next(0, obstaclePosition.Length)]);
                // add 1 to the score
                score += 1;
            }

            // if the game over boolean is set to true
            if (gameover)
            {
                // draw a black border around the obstacle
                // and set the border size to 1 pixel
                obstacle.Stroke = Brushes.Black;
                obstacle.StrokeThickness = 1;

                // draw a red border around the player
                // and set the border size to 1 pixel
                player.Stroke = Brushes.Red;
                player.StrokeThickness = 1;
                // add the following to the existing score text label
                scoreText.Content += "   Press Enter to retry";
            }
            else
            {
                // if the game is not order then reset the border thickness to 0 pixel
                player.StrokeThickness = 0;
                obstacle.StrokeThickness = 0;
            }
        }

First, we start off by animating background rectangle, player rectangle, obstacle rectangle and updating the score.

            // move the player character down using the speed integer
            Canvas.SetTop(player, Canvas.GetTop(player) + speed);
            // move the background 3 pixels to the left each tick
            Canvas.SetLeft(background, Canvas.GetLeft(background) - 3);
            Canvas.SetLeft(background2, Canvas.GetLeft(background2) - 3);
            // move the obstacle rectangle to the left 12 pixels per tick
            Canvas.SetLeft(obstacle, Canvas.GetLeft(obstacle) - 12);
            // link the score text label to the score integer
            scoreText.Content = "Score: " + score;

In the code above the first line is setting the top location or y of the player object by obtaining the top position of the player and adding the value of speed to it. So if the player top position 12 then it will add 5 to it each frame so first tick it will be 17, second tick it will be 22 third tick it will be 27 and so on. So by adding the speed integers value to the player top location we are moving the player object downwards of the screen. It will look like gravity is pulling the player down but we know better don’t we.

Second and third line of the code is dealing with both background rectangles. As the player is on the screen, the player object doesn’t move anywhere only moves up and down however we move the whole level around the player, the background images will be moving towards the left of the player so there is an illusion of the player moving in the RIGHT direction. If you look at the code we are setting left of or X of the backgrounds by getting the x location first and deducting three from there each tick, this way with each tick their left position will be lower and the backgrounds will be moving towards the left.

Fourth line is for the obstacle and it doing exactly the same thing as the background except its moving at much faster pace. The obstacle is moving towards the left 12 pixels at a time so it will make the game look more parallax then if we moved the background and the obstacle together at the time same.

Last line there will be updating the score on the score text label.

Assigning rectangle hit boxes

            // assign the player hit box to the player, gound hit box to the ground rectangle and obstacle hit box to the obstacle rectangle
            playerHitBox = new Rect(Canvas.GetLeft(player), Canvas.GetTop(player), player.Width, player.Height);
            groundHitBox = new Rect(Canvas.GetLeft(ground), Canvas.GetTop(ground), ground.Width, ground.Height);
            obstacleHitBox = new Rect(Canvas.GetLeft(obstacle), Canvas.GetTop(obstacle), obstacle.Width, obstacle.Height);

In the code above we are linking the hitboxes to their rectangles. Rect classes have a function called intersects with, which we need to check if two or three objects are colliding together and give instructions on what to do if they are. So since we have rectangles in the screen we can create RECT classes and wrap them around the original rectangles. Each rect class takes 4 properties, we need to give it the left and top location or x and y and height and width of the original rectangle. Since we are doing this inside the timer even if the object is moving the rect will move with it.

First we created the player hit box and inside the new rect(giving the player x y position and height and width). We do the same for the ground and for the obstacle rect.

If player hits the ground

            // check player and ground collision
            // IF player hits the ground 
            if (playerHitBox.IntersectsWith(groundHitBox))
            {
                //if the player is on the ground set the speed to 0
                speed = 0;
                // place the character on top of the ground rectangle
                Canvas.SetTop(player, Canvas.GetTop(ground) - player.Height);
                // set jumping to false
                jumping = false;
                // add .5 to the sprite int double
                spriteInt += .5;
                // if the sprite int goes above 8
                if (spriteInt > 8)
                {
                    // reset the sprite int to 1
                    spriteInt = 1;
                }
                // pass the sprite int values to the run sprite function
                runSprite(spriteInt);
            }

If player and the ground rectangle collide or if the player hit box intersects with ground hit box

THEN

We will set speed to 0, set the players new position above the ground rectangle, set jumping to false, because his gonna be on the floor. SpriteInt will be increasing by .5 this is why we used plus and equals sign spriteInt += .5; the reason we have done that is because the timer is running very fast and we want the animation to look smooth not in a hurry. So by adding .5 we made 1 after 2 40 milliseconds, 2 after 80, 3 after 120 and so on so we are slowing down the animation thus it will look much more smoother. After that line we are checking if the sprite int goes above 8, then we will set it back to 1. Lastly we are running the run sprite function with the spriteint inside of it. Because the sprite int is increasing every frame the run sprite function will change the animation soon as it hits 1,2,3,4,5,6,7 or 8 and it will reset back to 1 once it goes above 8. LOOOOOPPPPINGGGG

If player hit the object

            //if the player hit the obstacle
            if (playerHitBox.IntersectsWith(obstacleHitBox))
            {
                // set game over boolean to true
                gameover = true;
                // stop the game timer
                gameTimer.Stop();

            }

If player hit the object then we change the game over to true and stop the game timer. See we are using the same hit box and intersects with method.

Jumping in the game

            //if jumping boolean is true
            if (jumping)
            {
                // set speed integer to -9 so the player will go upwards
                speed = -9;
                // reduce the force integer
                force--;
            }
            else
            {
                // if jumping is not true then set speed to 12
                speed = 12;
            }

            // if force is less than 0 
            if (force < 0)
            {
                // set jumping boolean to false
                jumping = false;
            }

If jumping Boolean is set to true, then we change the speed from 5 to -9 meaning the direction of the player will be reversed. If the speed is 5 then it will add 5 to the existing top location of the player thus moving it downwards, but if the number is -5 then it will pull upwards. Makes sense position down negative up ok moving on. After the speed we move on to force now the force will determine how high the player can jump. So each time the jump is true we are deducting 1 from the force by noting force–; now this is happening every tick so the force will go down pretty quick. In the else part if jumping is not true then the normal gravity will be on.

In the second if statement we are checking if force goes below 0 meaning its gone -1 or something then we can simply set jumping to false. Soon as jumping is set back to false the player will reverse speed and start going down instead of up.

Parallax Scrolling the background

            // check the first background
            // if the first background X position goes below -1262 pixels
            if (Canvas.GetLeft(background) < -1262)
            {
                // position the first background behind the second background
                // below we are setting the backgrounds left, to background2 width position
                Canvas.SetLeft(background, Canvas.GetLeft(background2) + background2.Width);
            }
            // we do the same for the background 2
            // if background 2 X position goes below -1262
            if (Canvas.GetLeft(background2) < -1262)
            {
                // position the second background behind the first background
                // below we are setting background 2s left position or X position to backgrounds width position
                Canvas.SetLeft(background2, Canvas.GetLeft(background) + background.Width);
            }

Above we have two if statements first for the background rectangle and record for the background 2 rectangle. Now we know that both of the backgrounds will be going 3 pixels each tick towards left of the screen so we need a way for them to comeback and do it all over again so it looks seamless. Backgrounds width is 1262 pixels so if you say IF background left is below -1262 meaning it has completely gone passed the screen then we can set a new left for the first background this time we will find the background2s left position and add backgrounds width and leave it on that position. Each time the background goes beyond the screen it will be re positioned behind the second background and when the second background goes beyond the screen it will be re positioned behind the first background this way it will look like we are running in a infinite background scrolling game. NOICE.

Moving and resetting the obstacle rectangle

            // if the obstacle goes beyond -50 location
            if (Canvas.GetLeft(obstacle) < -50)
            {
                // set the left position of the obstacle to 950 pixels
                Canvas.SetLeft(obstacle, 950);
                // randomly set the top positio of the obstacle from the array we created earlier
                // this will randomly pick a position from the array so it won't be the same each time it comes around the screen
                Canvas.SetTop(obstacle, obstaclePosition[rand.Next(0, obstaclePosition.Length)]);
                // add 1 to the score
                score += 1;
            }

In the if statement above we are checking if the obstacle rectangle has gone beyond 50 pixels from the left, if this is true then we reset the location of the obstacle to 950 pixels to the right so it goes off the screen and comes back again.

Canvas.SetTop(obstacle, obstaclePosition[rand.Next(0, obstaclePosition.Length)]); In this line we are setting top location of the obstacles by using the obstacle position array we made earlier in the game. In this case we are saying that set the top location of the obstacle rectangle by finding a random location from the obstacle position array and assigning it.

We have 5 total objects in the array, arrays count 0 as well so technically we have 4 integers

0 – 320

1 – 310

2 – 300

3 – 305

4 – 315

The random number will be generated between 0 and length of this array which is 4 so lets say if its 3 then the program will assign 305 to the top location of the obstacle, if its 4 it will assign 315 to the top location, if its 2 It will assign 300 to its top location. So, with each iteration it will have different heights as you are playing this game. It makes it more interesting because otherwise we can figure out when to jump and this game can get boring very quickly.

Lastly, we are adding 1 to the score each time the obstacle goes off the screen, meaning it didn’t hit the player so the jump was a success.

Game Over Boolean

            // if the game over boolean is set to true
            if (gameover)
            {
                // draw a black border around the obstacle
                // and set the border size to 1 pixel
                obstacle.Stroke = Brushes.Black;
                obstacle.StrokeThickness = 1;

                // draw a red border around the player
                // and set the border size to 1 pixel
                player.Stroke = Brushes.Red;
                player.StrokeThickness = 1;
                // add the following to the existing score text label
                scoreText.Content += "   Press Enter to retry";
            }
            else
            {
                // if the game is not order then reset the border thickness to 0 pixel
                player.StrokeThickness = 0;
                obstacle.StrokeThickness = 0;
            }

In the code above we are checking if the game over Boolean is true, when the character hits the obstacle the game over Boolean will change to true and when that happens the game will a black stroke colour around the obstacle object and set its thickness to 1 meaning there will be black border of 1 pixel outside of the obstacle object. The player object will get a 1 pixel border around it and it will have the Red colour border.

If the game over Boolean is false then we set the stroke thickness or border size for player and obstacle to 0.

Thats the end of this Games engine event, make sure you have got all of the code accurate if you need to revisit some of it, take your time and understand how it all works.

Debugging the game

Go to Debug and click on any of the following –

wpf c# endless runner tutorial start debugging the game in visual studio

It should run the game, if there are any errors, double click on the line and compare them with the tutorials provided here.

See the game running below

wpf c# endless runner tutorial the final game screen shots of jumping, scoring, parallax scrolling, obstacles and end screen

Player animation is working, we can jump, obstacles are coming towards the player. When we jump over them successfully, we get a point and it adds to the label. The background image is scrolling endlessly and looking good. When we hit the obstacle, we get a border around both objects showing where the hit happened.

If you’ve followed this tutorial so far, very well done and you should be proud of the work you have done here Full source is available on the Full Source Code page for this Endless Runner WPF C# Project.




7 responses to “WPF C# Tutorial – Create Parallax Scrolling Endless Runner Game in Visual Studio”

  1. Pascal F says:

    Very nice tutorial, I really appreciate it.

    But i got one question:

    How do i get a moving ground into the game? when i put an image with the same length as the background and also the nearly same code i fall through the ground.

    Pascal

  2. Anhar Ali says:

    Hi Pascal, glad you liked the tutorial, worked really hard on this one. For your question about moving the ground, you can use similar techniques as being used with the background scrolling animation , have two separate ground rectangles and move them the same way as the backgrounds are. Within the rectangles you can images as it’s texture so it looks like the ground is scrolling with the background.

    I think the reason your character is falling through it is because it’s not checking whether you have landed on the ground rectangle. See if that helps.

    Happy programming.

  3. kobubu says:

    Dude your tutorials get better.
    I love how you explain the things now.
    Thanks for everything you do to us!

  4. anti says:

    realy nice tutorial! big thanks =)
    but i have a problem. if i execute the code in vs it is realy slow and lags all the time but if i start the exe under win10 its totaly smooth. so it must be a vs display failure. Do you know a solution for me to solve this issur in vs? its maybe a dump loading property which make it slow. thanks. have a nice day..

  5. anti says:

    maybe its the dispatcher timer because if i try to make a stop watch the displayed counting lags too. it’s the same as i do a normal clock or a timer for a media file. the time is always correct but the displaying is uneven and laggy. i hope you can help me. thanks.

  6. Stela Kostova says:

    Hello, I was wondering whether this could be done in Win Forms?

  7. Anhar Ali says:

    Yes you can do similar games in windows form. You won’t get the transparency with the player image and background if you use picture-boxes. This is why I’ve used WPF for this tutorial, it’s a lot easier to have transparency with sprite animation.