C++ Builder :: Игрописательство :: Как написать игру за 21 день ?

Главная

Введение

ЛИКБЕЗ
C++ Builder


ЛИКБЕЗ
C++

Глава №1
Глава №2
Глава №3
Глава №4
Глава №5
Глава №6

Исходники
к пособию

Мои исходники

Статьи
&
Книги


Гостевая

Ссылки

About

E-mail

Rambler's Top100


Создай игру на C++Builder за 21 день - Глава №1 (Черновой вариант)
 

Глава №1

Приступим к нашему первому проекту. Предположим, что вы уже представляете, что такое Билдер и немного знаете C++. Если вы первый раз слышите это, добро пожаловать в раздел ликбез (хотя в принципе тут ничего сложного мы делать не будем – попробуйте прочитать так).

Сейчас мы с вами сделаем кругляшок, управляемый стрелочками. Для этого нам понадобится создать новый проект. Создали?

Теперь, зайдите в инспектор объектов (F11) на вкладку Events (по-русски События) и два раза нажмите в поле справа от надписи OnKeyDown. Откроется окно с кодом, в котором будет написан обработчик события.

void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key,
TShiftState Shift)
{

}

Как вы можете догадаться, вам нужно вписать обработку события между двух фигурных скобок.

Обратите внимание на параметры функции в круглых скобках. В каждом событии там стоит Sender, однако он нам пока что не потребуется.

В этом обработчике вы можете увидеть параметр Key. Вот он нам и понадобится. В переменной Key хранится код нажатой клавиши. Чтобы узнать, как выглядят коды клавиш, впишите в обработчик строчку ShowMessage(Key);

Запустим программу (F9) и посмотрим, что получится. Понажимайте разные кнопки, в частности на стрелочки. Видите сообщения? Запомнили какие были числа? Забудьте, они нам не нужны. Жизнь программиста была бы гораздо тяжелей, если бы ему приходилось помнить наизусть коды всех клавиш.

Поэтому для упрощения жизни люди придумали Virtual key codes. И вместо числовых кодов частоиспользуемых клавиш стало возможным писать их названия. Для стрелочек это: VK_LEFT, VK_UP ,VK_RIGHT и VK_DOWN.

Чтобы узнать про какие названия у остальных клавиш, зайдите в Билдеровскую справку и найдите раздел: Virtual key codes.

Также ради интереса можно заглянуть в winuser.h (лежит в папке inludes). Там прописано:

#define VK_LEFT 0x25
#define VK_UP 0x26
#define VK_RIGHT 0x27
#define VK_DOWN 0x28

Не удивляйтесь, что цифры немного несоответствуют полученным вами - это шестнадцатеричные числа. То что в шестнадцатеричной - 25, в десятичной - 37 и.т.д ...

Сейчас вам нужно будет прописать разные действия на разные кнопки. Как это сделать? Самое удобное – использовать конструкцию switch (хотя можно использовать и if, но это будет некрасиво). Пишите:

switch(Key)
{
case VK_LEFT : ShowMessage(“Нажата стрелочка влево”); break;
case VK_UP : ShowMessage(“Нажата стрелочка вверх”); break;
case VK_RIGHT : ShowMessage(“Нажата стрелочка вправо”);break;
case VK_DOWN : ShowMessage(“Нажата стрелочка вниз”); break;
}

Попробуйте запустить программу. Работает? Тогда поехали дальше. Само собой, вместо ShowMessage’ей вы можете прописать там что угодно.

***

Вернемся к нашим баранам вернее к шарикам. Для шарика, движущегося по нажатиям стрелочек нужно менять его координаты x и y.

Объявите две глобальные переменные x и y (типа int).

*** КАК ОБЪЯВЛЯТЬ ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ ***

Объявить глобальные переменные вы можете в двух местах: в Unit1.cpp в самом начале кода после строчек с инклюдами или в заголовочном файле Unit1.h в разделе public.

Если у вас в программе больше одной формы и вам потребуется использовать переменные из одной формы в другой, то следует использовать второй способ. При этом вы сможете вызывать из Формы2 переменные так Form1->Переменная.

***

Ну, отвлеклись и хватит, после прописывания глобальных переменных нужно поменять в код в switch'e, и сделать так, чтобы при нажатии на стрелки у вас не выводились сообщения, а менялись координаты x,y.

На стрелке вправо пропишем: Вместо ShowMessage x=x+30; или короче x+=30; На остальных стрелках пропишите соответственно:

switch(Key)
{
case VK_LEFT : x-=30; break;
case VK_UP: y-=30; break;
case VK_RIGHT: x+=30; break;
case VK_DOWN: y+=30; break;
}

Теперь вам нужно прописать собственно рисование шарика. В билдере это делается так: у Form есть свойство Canvas (Холст), у которого в свою очередь есть методы прорисовки примитивов: линий, прямоугольников, эллипсов и битмапов.

Нам нужно нарисовать круг. А как известно круг это частный случай эллипса. Как задается эллипс? Эллипс задается двумя точками(четырьмя числами) – левой верхней и правой нижней. Существуют эти две точки на которых строится прямоугольник, в который в свою очередь вписывается эллипс. Когда-нибудь я доберусь до иллюстрирования и нарисую картинку, как это выглядит. А пока пытайтесь понять это так.

Вы скажете, две переменные есть, но у Эллипса должно быть 4 параметра? Все просто -одна точка будет A(x;y), другая - B(x+30,y+30). Разумеется, правильнее бы было написать A(x-15;y-15) B(x+15,y+15), тогда центр окружности находился бы в точке (x;y)? однако нам все же удобнее будет сделать так:

Form1->Canvas->Ellipse(x, y, x+30, y+30);

Попробуем запустить наше приложение. Все замечательно, вот только стандартный черный цвет не внушает оптимизма? А может, кроме цвета обводки вам хочется поменять стиль обводки *(сделать чтобы он рисовался с штрихованной границей), стиль и цвет заливки, толщину обводки? Да не вопрос! В свойстве Canvas также существуют подобъекты Brush и Pen, которые соответственно позволяют менять параметры заливки и пера.

Обратите внимание: если вы поменяли свойства Pen и Brush, то они будут использоваться и для всех объектов рисуемых в дальнейшем (пока вы опять их не поменяете).

Меняем цвет заливки на красный: Form1->Brush->Color=clRed;
Меняем цвет обводки на синий Form1->Pen->Color= clBlue;
Меняем толщину пера Form1->Pen->Width=5;

Скачать готовый пример №1

Карта местности…

Как сделать, чтобы вместо шара двигалась какая-нибудь картинка? В этом нет ничего сложного и, скорее всего, это мы рассмотрим на следующем уроке, а пока займемся проработкой пространства среды, говоря по-русски, поставим стены.

Сделайте заготовку карты – набейте в блокноте текстовый файл, состоящий из нулей и единичек размером 10x10. Единичкой будет стена, а нулем – пустое место.

Как экспортировать (загрузить) карту из файла? Не будем хитровать и используем стандартные функции языка C для работы с файлами – fopen и fgetc. Для их того, чтобы их использовать вам потребуется подключить библиотеку стандартного ввода/вывода stdio.h. Чтобы это сделать, пропишите в самом начале программы, где идут строчки, начинающиеся с #include еще одну - #include <stdio.h>. Это нужно сделать обязательно, иначе ваша программа не скомпилируется !

Создайте на форме кнопку и в обработчике события ее впишите загрузку содержимого файла в массив. Для начала неплохо бы было объявить сам массив, как глобальную переменную (как объявлять глобальные переменные). Для этого в начале программы пропишите: int a[10][10];

Объявим переменную файла:
FILE *f;

Откроем файл
f=fopen(“C:\\map.txt”, “r”);

“r” – режим (только для чтения), в котором открывается файл.

“r” – read - для чтения
“w” – write – для записи
“a” – append - для дозаписи

Когда нам нужно будет сохранять файл, мы будем использовать w и a режимы, а пока нам нужен только r.

И еще – обратите внимание на то, что путь к файлу прописывается с двойными левыми слешами, именно так и никак иначе!!!

***

Если вы хотите сделать так, чтобы карта лежала рядом с файлом, а не по какому то конкретному пути читайте Совет №3 из Полезных советов.

***

Теперь, прежде чем начать работать с файлом, нужно проверить открылся он или нет (а то ведь всякое бывает).

if(f!=NULL) { /* а здесь писать все относящееся к работе с файлом*/ }

Если вы хотите показаться круче, можете писать короче - if(f) { … }

Вспомним циклы (из ликбеза) и зададим вложенный двойной цикл:

for(int i=0;i<10;i++)
{
for(int j=0;j<11;j++) // на единицу больше из-за символа конца строки
a[i][j]= fgetc(f); //
}

fgetc – функция получающая символ из файла. И еще один важный момент в 1-м цикле написано 10, а во втором 11, хотя карта 10х10. Это не опечатка. Все дело в том, что в файле содержатся символы концов строк и из-за них в строке получается не 10 символов, а 11.

Любите убирать за собой посуду? Не любите, но надо. Раз файл открыли, так уж извольте его закрыть за собой. Конечно, если вы забудете его закрыть, скорее всего, ничего смертельного не случится, однако это признак плохого тона. Вы же не хотите прослыть плохим программером ? :)

Тогда впишите эту строчку в конце работы с файлом:

fclose(f); // закрытие файла f

***

Ну а теперь пропишем собственно прорисовку массива на экран. Пусть зеленым цветом будет обозначено пустое место, а красным – стена. В дальнейшем, мы введем здесь текстуры, а пока будем довольствоваться двуцветным ландшафтом.

Создадим в Form’е отдельную функцию отрисовки карты. Хотя на данном этапе можно обойтись и без нее (не создавать отдельную функцию), но мы будем с вами приучаться писать правильно. Вы же хотите, чтобы ваша программа выглядела красиво, да еще и так, чтобы в ней без труда мог разобраться другой человек.

Вам и самим будет очень трудно разбираться в том, что и где написано, когда программа не структурирована и содержит более 500 строчек … да что там 500

Так что теперь без лишних разговоров ? откройте файл Unit1.h (Ctrl-F6) и в секции public:

Пропишите void Paint_Map(void);

Вернитесь обратно в Unit1.cpp (Ctrl-F6) и впишите в конце новую функцию:

void Form1::Paint_Map(void)
{

}

А теперь будем наполнять ее содержимым. Вспомните, как рисовали шарик. Похожим образом рисуется и квадратик. Только вместо Ellipse нужно писать Rectangle.

for(int i=0;i<10;i++)
{
for(int j=0;j<10;j++)
{
switch(a[i][j])
{
case 0 : Form1->Canvas->Brush->Color=clRed; break;
case 1 : Form1->Canvas->Brush->Color=clGreen; break;
}
Form1->Canvas->Rectangle(i*30,j*30,i*30+30,j*30+30); // 30 = размер клетки в пикселях
}
}

Ну вот, функция наполнена содержанием, теперь запустите ваше приложение. Работает? Нет. Не волнуйтесь, так и должно быть. Чтобы что-то заработало нужно эту функцию еще и вовремя вызвать.

Зайдите в обработчик Button1Click и напишите: Paint_Map();

Теперь карта будет рисоваться по нажатию на кнопку. Попробуйте запустить программу.

Однако, вам наверное хочется, чтобы карта перерисовывалась каждый раз, когда движется шарик. Тогда нужно прописать Paint_Map() в начале FormKeyDown’а. Почему не в конце? Потому что тогда вы не увидите шарик, ведь сначала нарисуется он, а потом карта. Очевидно, вам нужно, чтобы было наоборот.

Скачать готовый пример (№3)

Если вы запустили программу (F9) и все заработало, вы можете убедиться, что шарику фиолетово, где бегать по зеленым или по красным квадратам. Конечно, это никуда не годится. Поэтому, сейчас мы с вами займемся одной из важнейших задач в написании игр а именно - пропишем проходимость сквозь стены … в смысле непроходимость :)

Зайдите в FormKeyDown и найдите движение по стрелочкам. Пока что никаких проверок на наличие стены там нету, исправим это …

Заменим

x++

на

if(a[x+1][y])!=0)
x++

первый вариант значит – просто прибавить координату x.
Второй вариант значит – прибавить координату x в случае если на карте в той точке не стоит стена.

Таким же Макаром нужно заменить и все действия для других стрелочек. Изменили? Можете запускать. Впечатляет? Не прошло и часа, как вы уже сделали суперигру.

Скачать готовый пример (№4)

Аптечко и иже с ними …

Все работает? Замечательно! Но, согласитесь, что как то скучно это просто ходить по лабиринтам. Делать сразу монстров я вам не предложу, а вот что-нибудь типа аптечки, патронов и тому подобных артефактов мы с вами сможем сделать прямо сейчас.

Для определенности пусть это будут жизни. Знаете типа сердечек в Пакмэне. Правда пока они будут выглядеть, как квадратики, но в том, чтобы сделать их сердечками нет ничего сложного. Если у вас не хватает терпения ждать, пока я напишу главу про сердечки, я могу скинуть вам на мыло пример готовой проги, пишите.

Значит так, чтобы прописать аптечки откройте для начала файл с картой.и накидайте где-нибудь двоек вместо 0 и 1, само собой так, чтобы к ним можно было подобраться, затем сделайте в функции прорисовки карты выделение двоек другим цветом, например желтым.

А теперь самое интересное – как аптечку сделать аптечкой. Т.е. как сделать так, чтобы ее можно было забрать и на ее месте осталось пустое место

Создайте еще одну глобальную переменную. Пусть она будет называться ochki.
Пропишите, рядом с объявлением x и y, ochki.

Вот, а теперь опять будем мучать КейДаун. В каждом кейсе нашего свитча, нам надо прописать внутри проверки существования стен, еще и проверку существования аптечки.

case VK_LEFT :
if(a[x/30-1][y/30]!=1) // если справа нет стены
{
if(a[x/30-1][y/30]==2) { a[x/30-1][y/30]=0; ochki++; } // если нашли аптечко прибавилась жизнь и аптечка превратилась в пол ….
x-=30;
}

Теперь switch в FormKeyDown будет выглядеть приблизительно так:

switch(Key)
{
case VK_LEFT : /// кнопка влево
if(a[x/30-1][y/30]!=1)
{
if(a[x/30-1][y/30]==2) { a[x/30-1][y/30]=0; ochki++; } // если нашли аптечко прибавилась жизнь
x-=30;
}
break;

case VK_UP : /// кнопка вверх
if(a[x/30][y/30-1]!=1)
{
if(a[x/30][y/30-1]==2) { a[x/30][y/30-1]=0; ochki++; } // если нашли аптечко прибавилась жизнь
y-=30;
}
break;

case VK_RIGHT : /// кнопка вправо
if(a[x/30+1][y/30]!=1)
{
if(a[x/30+1][y/30]==2) {a[x/30+1][y/30]=0; ochki++; } // если нашли аптечко прибавилась жизнь
x+=30;
}
break;

case VK_DOWN : /// кнопка вниз
if(a[x/30][y/30+1]!=1)
{
if(a[x/30][y/30+1]==2) {a[x/30][y/30+1]=0; ochki++; } // если нашли аптечко прибавилась жизнь
y+=30;
}
break;
}

А чтобы вы знали сколько у вас очков допишите в конец КейДауна:

Caption="Вы набрали " + String(ochki) + " очков";

Теперь очки будут выводиться в заголовок формы.

Скачать готовый пример (№5)

На сегодня наверное хватит. Чувствую эту главу придется разбить на несколько глав и расписать все попонятнее …

Если есть вопросы, нашли ошибки (а они, чувствую, тут имеются в большом количестве), пишите toshibant@mail.ru ...

 

 

 
 
Hosted by uCoz