Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Brick Ball Game : WPF C# Game

0.00/5 (No votes)
16 May 2014 1  
This is not a simple brick ball game but we need to concentrate on two balls at a time.

This article is an entry in our AppInnovation Contest. Articles in this sub-section are not required to be full articles so care should be taken when voting.

Introduction

This game is a brick ball game that needs to break bricks on the top using two balls. In this game you need to handle two bottom bricks (Red and Blue) with your finger. If the game ball touches the bottom area then the game will be over. You should try your best to complete all the levels. This game will provide you the intermediate file to create your own game levels as many as you want. You can challenge your friend by creating complicated game levels.

Key information

Right Arrow: Blue brick will move to right

Left Arrow: Blue brick will move to left

S key: Red brick will move to left

F key: Red brick will move to right

TouchScreen

You can handle Red/Blue sliders using GoldenPlate. You can move your finger on that area to move sliders. First touch will be considered as the movement for the Red brick and the another for Blue. you need to use two finger to move the brick. with the help of single finger you can move only Red slider. You can switch the slider position from left hand finger (that handle Red one) could move Blue slider if you touch with your right hand finger first.

Let's see the screen

I have created seven different stages to play this game.

As you can see in the above screenshot. by pressing F5 button game will be started. You can press F1 to get more information about how to play the game. In between the game if you feel to pause the game, then simply press space bar.

To resume in play mode you need to hit space again. While playing the game, make sure Blue ball hit the Blue slider and Red with Red one. Opposite color slider will not work for you. And you will lost your game.

Initially the screen will be totally blank. You can see there are two balls and two moveable bricks at the bottom. You can move these bricks using the touch screen at a time.

Let's customize the game

You can find a text file with the project with a number of comma separated values inside it.

,,1,,,,1,,,,1,,,,1,,,,1,,,,1,,,,1,,,,1,,,,1,,,,1,,,,1,,,,1,,,,1,,,,1,,,,1,,,,1,,,,1,,,,1,,,,1,,,,1,,,,1,,,,1,,,,1,,,,1,,,,,

Above is one possible example of how it may look like. Each line contains information of how top bricks will look like.

There are many possible combinations that can be created. If no value is supplied between tww commas then it will not generate bricks in the game area. The value can between comma can be 1, 2 or 3. Each indicates how many times the ball needs to touch a particular brick to be broken.

Let's see some logic

[Image1 : Rank each direction with an integer value for further calcuation.]

Inside the Black game area, the ball can be rotated either clockwise or anti-clock wise. Depending on that we create a value for each rotation to indicate which state of rotation is going on in the game. E.g., the current rotation is anti-clock wise and if the ball touches the bottom brick with current position 0 then the next move will be on the direction of 3 (please see the above image).

So what does this number indicate?

Top Left in the canvas is the starting positing of the X and Y axes. The values of X and Y are zero at that place, when we are moving to the 0th direction we need to increment X and Y. It means the ball will be moving on the right bottom corner.

0 - X and Y both will be increment.

1 - X decrements and Y will increment.

2 - X and Y both will be decremented.

3 - X increments and Y will decrement.

XAML Code

As we have dynamically generated bricks on the top, so we do not need more xaml code to generate bricks.

<Window x:Class="WPFGame1.Gammer" Name="myWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        WindowStyle="None"
        AllowsTransparency="True"
        ResizeMode="CanMinimize"
        Title="Duo Brick Breaker" Height="650" Width="700" 
        KeyDown="Window_KeyDown" 
        WindowStartupLocation="CenterScreen" 
        Icon="/DuoBrickBreaker;component/Images/icon.ico">
    <Border BorderBrush="Black" BorderThickness="10" >
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="529"></RowDefinition>
                <RowDefinition Height="40"></RowDefinition>
                <RowDefinition Height="40"></RowDefinition>
            </Grid.RowDefinitions>
            <Canvas Name="MyGameCanvas" Width="650" 
                        Height="500" Background="LightPink" Opacity="0.6">
                <Rectangle Name="rectangleRed" Width="100" 
                    Height="15" RadiusX="3" RadiusY="3" 
                    Fill="Red" Canvas.Left="0" 
                    Canvas.Top="500" Opacity="1"></Rectangle>
                <Rectangle Name="rectangleBlue" Width="100" 
                   Height="15" Fill="Blue" RadiusX="3" 
                   RadiusY="3" Canvas.Left="550" 
                   Canvas.Top="500" Opacity="1" ></Rectangle>
                <Ellipse Name="GameBallRed" Fill="{DynamicResource MyRadialGradientRed}" 
                   Width="30" Height="30" Canvas.Left="30" 
                   Canvas.Top="470" Opacity="1" />
                <Ellipse Name="GameBallBlue" Fill="{DynamicResource MyRadialGradientBlue}" 
                   Width="30" Height="30" Canvas.Left="589" 
                   Canvas.Top="470" Opacity="1"></Ellipse>
            </Canvas>
            <Canvas Grid.Row="1" Height="40" 
               Background="Gold" Margin="10" Name="canvas1">
            </Canvas>
            <TextBlock Grid.Row="2" Text="F1:Help F5:Play 
               Space:Pause" FontSize="24" Margin="5" 
               HorizontalAlignment="Center" />
        </Grid>
    </Border>
    <Window.Resources>
        <RadialGradientBrush x:Key="MyRadialGradientRed" GradientOrigin="0.5,0.5">
            <GradientStop Color="Transparent" Offset="1"></GradientStop>
            <GradientStop Color="Red" Offset="0.8"></GradientStop>
            <GradientStop Color="Red" Offset="0.5"></GradientStop>
        </RadialGradientBrush>
        <RadialGradientBrush x:Key="MyRadialGradientBlue" GradientOrigin="0.5,0.5">
            <GradientStop Color="Transparent" Offset="1"></GradientStop>
            <GradientStop Color="Blue" Offset="0.8"></GradientStop>
            <GradientStop Color="Blue" Offset="0.5"></GradientStop>
        </RadialGradientBrush>
    </Window.Resources>
</Window> 

We have used WPF features to enhance User interface. but i am not going to discuss each one in depth. you can study it from the MSDN. Even so many articles are written on each and every point.

Our important controls are Canvas and Grid control. This two control will be help us to create great User Interface.

Let's see the code for how we are moving the game ball.

private void moveGameBall(int currentDirection, 
      ref double gameBallTop, ref double gameBallLeft, ref Ellipse gameBall)
{
    switch (currentDirection)
    {
        case 0:
            gameBallTop += motionRatio;
            gameBallLeft += motionRatio;
            break;

        case 1:
            gameBallTop += motionRatio;
            gameBallLeft -= motionRatio;
            break;

        case 2:
            gameBallTop -= motionRatio;
            gameBallLeft -= motionRatio;
            break;

        case 3:
            gameBallTop -= motionRatio;
            gameBallLeft += motionRatio;
            break;
        default:
            MessageBox.Show("Ehhh Error occur!!!");
            break;
    }

    Canvas.SetTop(gameBall, gameBallTop);
    Canvas.SetLeft(gameBall, gameBallLeft);
}

As you can see in the above function, ball will be moved with the ratio of motionRatio defined. if we increase it's value, game speed will be increased. We can make advance game by changing motionRatio for everystage.

Let's create our Top Breaks pattern from the text file

string[] stagesInfo = File.ReadAllLines("GameStages.txt"); 

This will read all the lines of the CSV and store in the string array. Now you have each game stage with each string value in the stageInfo array.

When the user clicks on the "Start New Game" button we are passing the 0th index to the function, indicating the start of the fresh game with stage 1.

private void brickGenerator(int currentStage)
{
    changeBackgroundImage();
    Rectangle rct;

    try
    {
        bricks.Clear();

        if (stagesInfo.Length <= currentStage)
        {
            movingTimer.Stop();
            MessageBox.Show("You have completed all the Stage. Congratulation!!!");
        }
        else
        {
            brickInfo = stagesInfo[currentStage].Split(',');

            for (int i = 1; i <= 10; i++)
            {
                for (int j = 1; j <= 10; j++)
                {
                    rct = new Rectangle();
                    rct.Opacity = 1;
                    if (!string.IsNullOrWhiteSpace(brickInfo[(j + ((i - 1) * 10)) - 1]))
                    {
                        int brickType = Convert.ToInt16(brickInfo[(j + ((i - 1) * 10)) - 1]);

                        switch (brickType)
                        {
                            case 0:
                                break;

                            case 1:
                                rct.Fill = Brushes.YellowGreen;
                                break;

                            case 2:
                                rct.Fill = Brushes.DarkOrange;
                                break;

                            case 3:
                                rct.Fill = Brushes.Khaki;
                                break;
                        }

                        rct.Height = 25;
                        rct.Width = 60;
                        rct.Stroke = Brushes.Black;
                        rct.RadiusX = 1;
                        rct.RadiusY = 1;
                        rct.StrokeThickness = 1;
                        Canvas.SetLeft(rct, (j * 60) - 30);
                        Canvas.SetTop(rct, (i * 25));
                        bricks.Insert((j + ((i - 1) * 10)) - 1, rct);
                        MyGameCanvas.Children.Insert(0, rct);
                    }
                    else
                    {
                        rct.Visibility = System.Windows.Visibility.Collapsed;
                        bricks.Add(rct);
                    }
                }
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

There are many things that need to be noticed in the above code. As you can see, we have created a dynamic rectangle with a filled different color. We have picked up three different colors to display brick. It will help to identify which type of brick is that. As I have discussed earlier, we have three types of bricks that need to be broken. So for each brick we have specified colors.

We are maintaining the game stage information in the text file. so once all the line in the game will be completed and you have successfully completed stages it means you won the game.

We are adding this rectangle in the Canvas as well as in a List of Rectangles for further calculation. In the next section you will come to know the purpose of the storage.

Calculate Collapsed Brick

Now we need to check when the ball will collapse with the dynamically generated bricks. For that we use a LINQ Lambda query to identify which brick needs to be broken.

To check if ball is collapsed with the brick we have to calculate different points on the ball in context of canvas. If we calculate 20 points on the ball and any of the point is inside any of the brick, it means ball is collapsed with that brick.

private List<coordinates> getCircularPoints(Ellipse gameBall)
{
    int distance = (int)gameBall.Width / 2;
    double originX = Canvas.GetLeft(gameBall) + distance;
    double originY = Canvas.GetTop(gameBall) - distance;

    List<coordinates> pointLists = new List<coordinates>();
    coordinates point;
    for (int i = 0; i < 360; i = i + 24)
    {
        point = new coordinates();

        point.X = (int)Math.Round(originX + distance * Math.Sin(i));
        point.Y = (int)(gameBall.Width + Math.Round(originY - distance * Math.Cos(i)));
        pointLists.Add(point);
    }

    return pointLists;
}

The above code will calculate the Co-ordinates on the game ball and return the list of X and Y information in context of the canvas. We have calculated total 15 different point on the ball curcumference.

Now we need to check if ball is collapsed with any of the brick after each ball movement. we have used Linq query for calculation.

var conflictedBrick = bricks.Where(s => ballCoordinate.Any(p =>
p.X >= Canvas.GetLeft(s) &&
p.X <= Canvas.GetLeft(s) + s.Width &&
p.Y <= Canvas.GetTop(s) + s.Height &&
p.Y >= Canvas.GetTop(s)));

If conflictedBrick count is greater then zero it means ball is collapsed with the brick and we need to perform certain staps on that. if ball is collapsed we need to remove that brick from the user canvas and we also need to change the direction of the ball movement. We also need to check if none of the brick exist on the canvas then we should shift the user on the next level or prompt "You won the game!!!".

Actually we are not deleting the brick but we are just hiding the brick and removing it from the private list. So in future calculations it will not come again.

All the steps that we have discussed in above paragraph can be checked from the attached code.

There are many conditions need to be checked at the time of calculation. so you may surprise with different logics in the code. But each of the code have it's own need.

We are having three different type of bricks so we also need to check if type 3 brick is collapsed then change the color of the brick and proceed further. if the brick is of type 1 then we just need to hide it from the user canvas.

Change Ball Direction

Another important portion of the code is, how we are changing the ball movement inside the canvas. Actually we are incrementing/decrementing the X and Y co-ordinates in the canvas. and we make sure ball is not going out of the boundry of the canvas.

private void changeBallDirection(ref int _currentDirection, 
          Ellipse _gameBall, Rectangle _crashBrick, coordinates nearCoordinate)
{
    int hitAt;
    int left = (int)(nearCoordinate.X - Canvas.GetLeft(_crashBrick));
    int right = (int)(nearCoordinate.X - (Canvas.GetLeft(_crashBrick) + _crashBrick.Width));
    int top = (int)(nearCoordinate.Y - Canvas.GetTop(_crashBrick));
    int bottom = (int)(nearCoordinate.Y - (Canvas.GetTop(_crashBrick) + _crashBrick.Height));

    int[] values = { Math.Abs(left), Math.Abs(right), Math.Abs(top), Math.Abs(bottom) };
    Array.Sort(values);

    if (values[0] == left)
        hitAt = 3;
    else if (values[0] == right)
        hitAt = 1;
    else if (values[0] == top)
        hitAt = 0;
    else
        hitAt = 2;
    // more code is in this function to do other calculation
    // but i have display only important code here.

}

If we have co-ordinate that indicate the ball is collapsed with the brick, then our next step is on which surface of the brick ball is collapsed. below are possible rotation we need when ball is collapsed on the surface.

Check Image1 for calculating next rotation.

Current Direction Brick Surface New Direction
0 Top 3
Left 1
Right NA
Bottom NA
1 Top 2
Left NA
Right 0
Bottom NA
2 Top NA
Left NA
Right 3
Bottom 1
3 Top NA
Left 2
Right NA
Bottom 0

Let See, If the current direction of the ball is 0 (See Image1) in that case the possibility of the ball to be collapsed with brick would be on Top/Left. It will never happen that ball will touch on the right or bottom brick when it's direction is 0. If ball touch the Top surface then the next direction should be 3 (See image1:1) And if ball touch the left surface then next direction should be 1 (See image1:2)

Hope the logic is clear, Feel free to ask any of the question related to the logic or anyother issue.

History

Initial release

10/10/2012: Mouse not able to move the brick, only keyboard can be used to move both balls.

11/15/2012: First Version of the Game, Now it can be called with "Duo Brick Breaker"

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here