Страница 17 из 18
g.DrawImage(breadImage, bx, by);
for (int i = 0; i < tomatoes.Length; i++)
{
if (tomatoes[i].visible)
{
g.DrawImage(tomatoImage,
tomatoes[i].rectangle.X,
tomatoes[i].rectangle.Y);
}
}
}
//We draw the image on the Form1:
e.Graphics.DrawImage(backBuffer, 0, 0);
} //End of the method Form1_Paint.
Добавление новых объектов в игру соответственно усложняет код. В панели Properties (для Form1) на вкладке Events дважды щёлкаем по имени события Load. Появившийся шаблон метода Form1_Load после записи нашего кода принимает следующий вид.
Листинг 5.6. Метод для рисования изображения.
private void Form1_Load(object sender, EventArgs e)
{
//We load into objects of class System.Drawing.Image
//the image files of the set format, added to the project,
//by means of ResourceStream:
cheeseImage =
new Bitmap(myAssembly.GetManifestResourceStream(
myName_of_project + "." + "cheese.JPG"));
breadImage =
new Bitmap(myAssembly.GetManifestResourceStream(
myName_of_project + "." + "bread.JPG"));
//We initialize the rectangles, described around objects:
cheeseRectangle = new Rectangle(cx, cy,
cheeseImage.Width, cheeseImage.Height);
breadRectangle = new Rectangle(bx, by,
breadImage.Width, breadImage.Height);
//We load the tomato:
tomatoImage =
new Bitmap(myAssembly.GetManifestResourceStream(
myName_of_project + "." + "tomato.gif"));
//We initialize an array of tomatoes and rectangles:
initialiseTomatoes();
//We place the tomatoes in an upper part of the screen:
placeTomatoes();
//We turn on the timer:
timer1.Enabled = true;
}
И наконец, вместо приведённого выше метода updatePositions записываем следующий метод, дополненный новым кодом для изменения координат, обнаружения столкновений объектов и уничтожения помидоров.
Листинг 5.7. Метод для изменения координат и обнаружения столкновения объектов.
private void updatePositions()
{
if (goingRight)
{
cx += xSpeed;
}
else
{
cx -= xSpeed;
}
if ((cx + cheeseImage.Width) >= this.Width)
{
goingRight = false;
//At the time of collision, the Beep signal is given:
Microsoft.VisualBasic.Interaction.Beep();
}
if (cx <= 0)
{
goingRight = true;
//At the time of collision, the Beep signal is given:
Microsoft.VisualBasic.Interaction.Beep();
}
if (goingDown)
{
cy += ySpeed;
}
else
{
cy -= ySpeed;
}
//That the cheese did not come for the button3.Location.Y:
if ((cy + cheeseImage.Height) >= button3.Location.Y)
{
goingDown = false;
//At the time of collision, the Beep signal is given:
Microsoft.VisualBasic.Interaction.Beep();
}
if (cy <= 0)
{
goingDown = true;
//At the time of collision, the Beep signal is given:
Microsoft.VisualBasic.Interaction.Beep();
}
//We set to rectangles of coordinate of objects:
cheeseRectangle.X = cx;
cheeseRectangle.Y = cy;
breadRectangle.X = bx;
breadRectangle.Y = by;
//We check the collision of objects
//taking into account the tomatoes:
if (goingDown)
{
// only bounce if the cheese is going down
if (cheeseRectangle.IntersectsWith(breadRectangle))
{
//At the time of collision,
//the Beep signal is given:
Microsoft.VisualBasic.Interaction.Beep();
// we have a collision
bool rightIn = breadRectangle.Contains(
cheeseRectangle.Right,
cheeseRectangle.Bottom);
bool leftIn = breadRectangle.Contains(
cheeseRectangle.Left,
cheeseRectangle.Bottom);
// now deal with the bounce
if (rightIn & leftIn)
{
// bounce up
goingDown = false;
}
else
{
// bounce up
goingDown = false;
// now sort out horizontal bounce
if (rightIn)
{
goingRight = false;
}
if (leftIn)
{
goingRight = true;
}
}
}
}
else
{
// only destroy tomatoes of the cheese is going up
for (int i = 0; i < tomatoes.Length; i++)
{
if (!tomatoes[i].visible)
{
continue;
}
if (cheeseRectangle.IntersectsWith(
tomatoes[i].rectangle))
{
//At the time of collision,
//the Beep signal is given:
Microsoft.VisualBasic.Interaction.Beep();
// hide the tomato
tomatoes[i].visible = false;
// bounce down
goingDown = true;
// only destroy one at a time
break;
}
}
}
} //End of the method updatePositions.
В режиме выполнения (Build, Build Selection; Debug, Start Without Debugging) несколько i-х помидоров появляются в верхней части экрана в качестве мишеней (рис. 5.7), которые исчезают после попадания в них летающего сыра (рис. 5.8).
Управляя при помощи кнопок Button и мыши перемещением батона хлеба, мы можем отражать сыр вверх таким образом, чтобы уничтожить как можно больше помидоров за меньшее время, набирая при этом очки.
К разработке методики подсчёта очков в игре мы и приступаем.
5.6. Методика подсчёта очков в игре
Игра отличается от любого другого приложения тем, что один или несколько игроков набирают в игре очки, и победителем считается игрок, набравший наибольшее количество очков. А после набора определённого количества очков игра может переходить на более высокие (более сложные) и интересные уровни, после прохождения которых игрок может получить приз, например, в виде изображения какого-нибудь смешного персонажа.
Методика подсчёта очков (score) в игре подразумевает наличие в программе счётчика (scorer) очков и вывода очков на экран (например, методом DrawString) в строке:
g.DrawString(messageString, messageFont, messageBrush,
messageRectangle);
Видно, что в этом методе DrawString мы дожны определить параметры в виде шрифта messageFont, кисти messageBrush и зарезервированного прятоугольника для записи очков messageRectangle, причём в этот прямоугольник летающие объекты не должны залетать. На рис. 5.9 мы получили 20 очков за 2 сбитых помидора, а на 5.10 – 50 очков за 5 сбитых помидоров.
За каждый сбитый помидор мы можем начислить игроку любое количество очков, например, 10 очков в строке:
scoreValue = scoreValue + 10;
Новые очки сразу же выводятся на экран, информируя игрока.
Рис. 5.9. Получили 20 очков за 2 сбитых помидора. Рис. 5.10. Получили 50 очков.
Приступим к программной реализации методики подсчёта очков в игре в нашем базовом учебном проекте.
Сначала мы должны опустить ряд помидоров пониже, чтобы освободить место вверху для записи очков, поэтому вместо 4 записываем ординату, равную, например, 20:
int tomatoDrawHeight = 20;
В любом месте класса Form1 добавляем новые переменные для счётчика очков.
Листинг 5.8. Новые переменные.
// Font for score messages.
Font messageFont = null;
// Rectangle for score display.
Rectangle messageRectangle;
// Height of the score panel.
int scoreHeight = 20;
// Brush used to draw the messages.
SolidBrush messageBrush;
// The string, which is drawn as the user message.
string messageString = "Score : 0";
// Score in a game.