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
Rectangle
s 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;
}
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"