Добавить в цитаты Настройки чтения

Страница 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.