The last and, in my oppinion, the coolest part of this tutorial is making our doggy splash water from his fire-hose. There are a lot of ways to do this… My first idea was to make him splash a stream of water in a horizontal line… But I wasn't satisfied. Then, i figured out how to make him splash wather at an angle… But that didn't make me satisfied either. Then I decided to renew my high school math knowlege, and to force this dog to splash water to the exact point where the player would click the mouse… And, how does this look in theory? Here's a drawing…
Here's a little legend: Point B is the point where player clicked. Point A is the starting point of the splash. So, that makes the blue line c our splash. Angle alpha is the angle of the splash. It can be positive, or negative. So, how can we figure out the lenght of the splash (c), and it's angle (alpha)??? Just a little math. Our points are defined with x and y coordinates. So, if we know the horizontal coordinate for B, and the width of our game field, then we know the lenght of the red line b. And on the same priciple, we can find the lenght of the red line a. Calculating splash lenght c is just a matter of Pythagoras. Remember that jibberish your math teacher filled your hed with? I hate to admit it, but, it came useful. So, here's the equation:
(Pythagoras' theorem):
That's how we would write it on a peace of paper. And to make our C# understand it, we can write it like this:
int c = (int)Math.Sqrt(a * a + b * b); And if we have two sides of the triangle calculated, we can determine the angle with another math operation… Uff… Here's the equation:
Again, translated into C# il would look like this:
float alpha = (float)Math.Atan
((double)a / (double)b); To rotate an image, we'll use matrix translations… More math… Ah well… So, now when we finally have everything, we can write the code. Here it is. Enjoy it, it's your last peace of code in this tutorial.
private void Splash(int MouseY, int MouseX)
{
// Point A:
Point pStart = new Point
(picGameField.Width - 1, 195);
// Calculating the lenght of the splash,
// and other sides of the triangle:
int a = (picGameField.Height - MouseX
- (picGameField.Height - 215));
int b = (picGameField.Width - MouseY);
int c = (int)Math.Sqrt(a * a + b * b);
// Calculating the angle of the splash:
float alpha = (float)Math.Atan
((double)a / (double)b);
// Convert from Radians to Degrees
alpha = alpha * (float)(180.0 / Math.PI);
int x = picGameField.Width - c;
int y = 195;
// Defining the position of our splash image:
Rectangle rSplash = new Rectangle(x,y,c,50);
Graphics gSplash = picGameField.CreateGraphics();
// Matrix rotations:
Matrix X = new Matrix();
X.RotateAt(alpha, pStart, MatrixOrder.Append);
gSplash.Transform = X;
// Drawing our image to the screen:
gSplash.DrawImage(picSplash.Image, rSplash);
// Pause for a moment:
System.Threading.Thread.Sleep(100);
// Getting rid of our splash image:
gSplash.Dispose();
}
Obviously, we need some mouse coordinates for this code to work... In the next (probably the last) post - I'll post the whole source code for the project. With a download link... :) I know I skipped a few parts of the code, so, you'll be able to 'grab' them from actual project files! :)
Up to now, we displayed the blocks as squares filled with color. From now on, we'll display little icon images instead. If you remember, we used rectangles to define the size, and the position for each field. And that suits us just fine! So, here's a part of our code that we wrote in chapter 7:
(This is a part of the code from chapter 7, method DrawField())
switch (Field[v, s])
{
case 0:
// Draw empty field...
break;
case 1:
// I've decided that color #1 is Blue. So, if
// the field holds a value of 1 – We'll color it
// blue. And we'll do the same for all
// other colors.
gField.FillRectangle (Brushes.Blue, rtgField);
break;
case 2:
// If the field contains value 2:
// we'll fill it red.
gField.FillRectangle (Brushes.Red, rtgField);
break;
case 3:
// If the field contains value 3:
// we'll fill it green.
gField.FillRectangle (Brushes.Green, rtgField);
break;
case 4:
// If the field contains value 4:
// we'll fill it yellow.
gField.FillRectangle (Brushes.Yellow, rtgField);
break; case 5:
// If the field contains value 5:
// we'll fill it purple.
gField.FillRectangle (Brushes.Purple, rtgField);
break;
case 6:
// If the field contains value 6:
// we'll fill it black.
gField.FillRectangle (Brushes.Black, rtgField);
break;
case 7:
// If the field contains value 7:
// we'll fill it orange.
gField.FillRectangle (Brushes.Orange, rtgField);
break;
case 8:
// If the field contains value 8:
// we'll fill it gray.
gField.FillRectangle (Brushes.Gray, rtgField);
break;
case 9:
// If the field contains value 9:
// we'll fill it dark blue.
gField.FillRectangle (Brushes.DarkBlue, rtgField);
break;
case 10:
// If the field contains value 10:
// we'll fill it pink.
gField.FillRectangle (Brushes.Pink, rtgField);
break;
default:
// If our program comes to this // point of the code,
// something's gone wrong! ;) XD
break;
}We'll replace that FillRectangle statement with a new one: DrawImage. But before we do that, we have to store our images somewhere. And, lucky us, there is a control made just for that. Go to your toolbox, and find the Components group. In there you'll find the ImageList control. Double-click it, and it will apear next to your timers. Nice. Set the properties like this:
ImageList
- (name):ilTiles
- ColorDepth: Depth32Bit
- TransparencyColor: Web > Transparent
- Images: [Load 10 different bubble images]
- ImageSize: 32; 32
Now, add add our bubble graphics files into the list. You can reorder them however you want. After all, we'll display the right picture by calling it's index number. Ready? Ok… Here is the revised code for the Switch in the 'DrawField()' method. See the difference? Nice… How about trying it out?
switch (Field[v, s])
{
case 0:
//Draw empty field...
break;
case 1:
gField.DrawImage (ilTiles.Images[0], rtgField);
break;
case 2:
gField.DrawImage (ilTiles.Images[1], rtgField);
break;
case 3:
gField.DrawImage (ilTiles.Images[2], rtgField);
break;
case 4:
gField.DrawImage (ilTiles.Images[3], rtgField);
break;
case 5:
gField.DrawImage (ilTiles.Images[4], rtgField);
break;
case 6:
gField.DrawImage (ilTiles.Images[5], rtgField);
break;
case 7:
gField.DrawImage (ilTiles.Images[6], rtgField);
break;
case 8:
gField.DrawImage (ilTiles.Images[7], rtgField);
break;
case 9:
gField.DrawImage (ilTiles.Images[8], rtgField);
break;
case 10:
gField.DrawImage (ilTiles.Images[9], rtgField);
break;
default:
break;
}
It looks a lot like the screenshot from chapter 1, doesn't it? Great! So, in the next chapter, we'll add one more extremly cool feature, to complete our game. We'll make our doggy splash water. And that's it. The game will be complete, and this tutorial will be almost over. As the last topc, I'll cover packaging and distribution of your game. And that's it… ;) Finally…