Журнал LinuxFormat - перейти на главную

LXF98:Стрелялка

Материал из Linuxformat
Перейти к: навигация, поиск


ИГРОСТРОЙ Все о разработке компьютерных игр с использованием свободного программного обеспечения

Содержание

Постепенное погружение

АНДРЕЙ ПРАХОВ Участник нескольких игровых проектов, представитель СМИ и начальник http://www.linuxmedia.ru

Игрострой – дело нелегкое и весьма-весьма затратное. Понятно, почему маститые разработчики игр не горят желанием ваять свои шедевры под открытый и свободный Linux. Ну никак не окупится разработка, ну не та идеология у пользователей открытых систем! И получается, что основная надежда игроков остается лишь на своих же «свободных» разработчиков. Конечно, радует появление таких проектов, как AstroMenace или игровой LiveDVD от linux-games.net. Честь и хвала людям, занимающимся этим делом почти на чистом энтузиазме. Да вот уровень у них, мягко говоря, не дотягивает до желанной истинными геймерами хардкорной планки. Вот и ждут игроки у моря погоды, в надежде, что разработчики игр «одумаются». Однако давайте вспомним, какие масштабные проекты были осуществлены на этом самом энтузиазме, столь нелюбимом некоторыми несознательными элементами ИТ-мира. Думается, создание и поддержка какого-либо дистрибутива отнюдь не легче, чем работа над серьезным игровым проектом. Так, может, объединение светлых голов по известной схеме Open Source и приведет к долгожданному результату?

«Москва не сразу строилась…» – это известно всем и каждому. Попробуйте свои силы в самом маленьком, крошечном проекте. Еще никто не говорил, что офисные игры – это зло. А «Игрострой» всецело вам в этом поможет. info@linuxmedia.ru

Стрелялка за выходные

ЧАСТЬ 1 Скучаете по R-Type и River Raid и готовы сделать что-то сами, но не знаете, с чего начать? Александр Супрунов покажет путь, доступный даже новичку!

Признаюсь сразу – это самый странный урок из всех, что вас ожидают. Я, конечно, постараюсь скрасить его различными интересными отступлениями, но уж ничего не поделаешь – в нем вы начнете учиться с конца. В качестве положительного момента отмечу, что изложенных в нем сведений должно хватить для того, чтобы начать писать компьютерные игры для Linux и, таким образом, значительно увеличить их число в нашей любимой ОС. Мы будем использовать язык C/C++, но, чтобы следовать курсу, вам потребуются только базовые знания.

Основной игровой библиотекой в Linux, пожалуй, следует назвать SDL. Скажу больше – написав игру с использованием SDL, вы без каких-либо изменений сможете откомпилировать ее для Linux, Windows, Mac OS X, Amiga Pegasos и даже наладонников, а возможностей библиотеки хватило для портирования Heroes of Might and Magic 3. Я не сомневаюсь, что ваши планы более грандиозны, но SDL способна реализовать и их. В крайнем случае (для повышения быстродействия и скоростных операций масштабирования, вращения и прозрачности) всегда можно подключить OpenGL.

При всех достоинствах SDL – это конструктор, позволяющий собрать действительно удобный инструмент. Например, вместо следующего кода, выводящего спрайт на экран стандартными средствами SDL

 SDL_Rect shadow;
 shadow.x=(Sint16)x;
 shadow.y=(Sint16)y;
 SDL_SetColorKey(img,SDL_SRCCOLORKEY,SDL_MapRGB(img->format,255,0,255));
 SDL_BlitSurface(img,0,screen,&shadow);

мне кажется более логичным написать:

sprite(номер, x, y);

Если вам тоже импонирует эта мысль, читайте дальше – мы доведем SDL именно до такой степени. При этом исходный код ваших игр едва ли превысит 20–30 КБ и будет кристально понятным даже новичкам.

Мы поместим на игровое поле крошечный кораблик, храбро «выносящий» с экрана полчища врагов (будут ли ужасные БОССы и различные типы оружия – зависит от вас), реализуем многоплановый параллаксный скроллинг, эффекты прозрачности и другие интересные вещи. Подобный тип игр малораспространен на платформе Linux, так давайте разберем по шагам все моменты, которые требуются для создания игры и, следуя им, напишем новую!

Приготовим рабочее место

Взгляните на врезку Что нам потребуется? и убедитесь, что указанные в ней компоненты присутствуют и готовы к работе. Я специально не стал упоминать популярные IDE типа KDevelop – при всем своем удобстве они достаточно громоздки и скрывают суть происходящих процессов. Для компиляции нашего кода потребуется написать лишь крошечный make-файл (назовите его Makefile).

 TARGET = ingame.run
 CFLAGS= `sdl-config --cflags`
 LIBS = `sdl-config --libs` -lSDL_ttf -lSDL_mixer
 CC=g++
 all:
                $(CC) -o $(TARGET) starfighter.cpp $(LIBS)
                strip $(TARGET)
                ./$(TARGET)&

Переменная TARGET задает имя исполняемого файла, который будет получен в результате компиляции. CFLAGS содержит флаги, необходимые любому SDL-приложению – в данном случае мы получаем их командой sdl-config. В поле LIBS указываются требуемые библиотеки. Если понадобиться добавить еще одну, например, SDL_image, следует просто дописать -lимя_библиотеки в конце этой строки. Переменная CC содержит команду для вызова компилятора C++.

Строки, следующие за all: – это те самые правила, по которым будет происходить сборка. Думаю, вы уже догадались, как интерпретировать строку $(CC) -o $(TARGET) starfighter.cpp $(LIBS)

а если нет, сделаю подсказку – $(var) подставляет в строку значение переменной var. Что же касается необязательной команды strip $(TARGET), то она очищает получившийся исполняемый файл от ненужной служебной информации. Наконец, последняя строчка

./$(TARGET)&

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

Общий цикл разработки нашей игры теперь будет выглядеть следующим образом:

  1. Открыть текстовый редактор и набрать код программы.
  2. Запустить терминал, перейти в каталог с игрой и набрать make.
  3. Оценить результат.
  4. Завершить программу, нажав клавишу Escape.
  5. Перейти к пункту 1.

...и так до тех пор, пока оценка, выставленная в пункте 3, не достигнет «хорошо» или «отлично».

Приступим к делу

Ну-с, теперь мы готовы начать программирование. И в первую очередь следует подключить файл ingame.h – он содержит все основные функции, которые потребуются нам при написании игры (см. «Основные функции»). Простейшая программа, не создающая ничего, помимо пустого окна (но уже умеющая вычислять FPS и реагировать на клавишу Escape) будет иметь следующий вид:

  1 #include “ingame.h”
  2
  3 int main(int n, char **s)
  4 {
  5       screen(1024, 768);
  6       while (GAME)
  7       {
  8          fx();
  9       }
 10        return 0;
 11 }

Давайте разберемся, что здесь происходит. Функция screen(), вызванная в строке 5, устанавливает полноэкранный режим 1024x768 (кстати, как мы вскоре увидим, здесь можно указать и любое другое значение). В строке 6 запускается главный цикл игры, обрабатывающий события, поступающие от пользователя. Этим занимается вспомогательная функция fx(), определенная в ingame.h – она отслеживает нажатие на клавиши, вычисляет значение FPS и так далее. Если пользователь нажимает Escape, функция fx() сбрасывает флаг GAME возвращает управление, после чего главный цикл, а вместе с ним и наша программа, завершаются.

Разместим первый спрайт

Теперь немного усложним программу – заставим ее выводить на экран картинку, сохраненную в формате BMP. Изображение можно взять с LXFDVD или подготовить самостоятельно в графическом/трехмерном редакторе. Я, например, создал боевой космический истребитель в Blender (LXF89-91). Учтите только, что для правильного отображения нашим движком, прозрачные участки картинки должны иметь цвет (255,0,255) в RGB-нотации.

 #include “ingame.h”
 int main(int n, char **s)
 {
    screen(500, 700);
    loadsprite(1, “ship.bmp);
    while (GAME)
    {
       sprite(1,250,650);
       fx();
    }
    return 0;
 }

По сравнению с предыдущим случаем добавился вызов функции loadsprite(), загружающей спрайт ship.bmp в память и присваивающей ему номер 1. Это число может изменяться в пределах от 0 до 999 – более высокие значения зарезервированы ingame.h для служебных целей. При этом количество копий каждого спрайта на экране практически неограничено. Спрайт выводится на экран функцией sprite(), которой следует передать номер и координаты точки, в которой осуществляется отображение. Для вашего удобства в ingame.h уже определены такие переменные, как x, y, x2 и y2, поэтому вы можете просто использовать их в коде. Например, если вы измените


 sprite(1,250,650);
 на
 x=250;
 y=650;
 ...
 sprite(1,x,y);

все будет работать, как раньше.

Итак, с выводом одной картинки мы разобрались. Программирование игр – не жонглирование, и обращаться с несколькими спрайтами ненамного сложнее:

 screen(800,600);
 loadsprite(1,”luna.png);
 loadsprite(2,”ship.png);
 loadsprite(3,”fire.png);
 while (GAME)
 {
     sprite(1, 150 , 0);
     sprite(3, 250 , 300);
     sprite(2, 350 , 500);
     fx();
 }

С назначением переменных UP (вверх), DOWN (вниз) и FIRE (огонь) вы теперь можете разобраться самостоятельно.

Ключ на старт!

Чтобы находящийся на экране неподвижный корабль начал движение, в программу необходимо добавить всего две строчки. Вот так:

 screen(500, 700);
 loadsprite(1, “ship.bmp);
 x=250;
 y=650;
 while (GAME)
 {
    sprite(1,x,y);
    if (LEFT) {x=x-2;}
    if (RIGHT) {x=x+2;}
    fx();
 }

Чем больше будет изменение координаты, тем быстрее будет перемещаться корабль по экрану. И наооборот, если приращение координаты установить равным 0,1 или 0,01, ваш скоростной истребитель будет ползти, как старый имперский сухогруз.

Что дальше?

Прошло каких-то несколько минут, а вы уже имеете работающую демо-версию новой игры. Есть что показать друзьям, поэтому самое время решительно сказать: «Стоп!». Все должно развиваться по плану.

Начнем с уже озвученной фабулы. Мы управляем небольшим космическим истребителем. Цель: уничтожить враждебных пришельцев, основавших цитадель на Обратной стороне Луны. Соответственно, до этой самой Луны необходимо добраться, поэтому игровой процесс целесообразно разделить на 3 этапа:

  • Первый – добраться до Луны через открытый космос. Этому, очевидно, будут мешать вражеские перехватчики.
  • Второй этап происходит над Лунной поверхностью. Это повод реализовать фантастический многоплановый паралаксный cкролинг! Нашими врагами будут все те же истребители, а также пушки, вмонтированные в скалы.
  • Третий этап – битва с БОССом. В роли «великого и ужасного» будет выступать Гигантский корабль-матка.
  • Конец. Враг разгромлен, но одна шлюпка выскользнула за пределы оцепления и скрылась в звездных просторах. Продолжение следует?

Конечно, вы вольны придумать свою сюжетную линию, но главное здесь – увидеть примерную структуру игры. И могу вас заверить – если все сделать грамотно, то играть будет весьма увлекательно. А что самое важное в космических стрелялках? Конечно же, красивые взрывы, поэтому на красочных эффектах тоже экономить не стоит.

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

Не забывайте и о факторе внезапности, а так же физических законах. Где-то на полпути к Луне кораблю может повстречаться метеоритный поток. Некоторые метеориты будут настолько велики, что окажутся способны своим импульсом изменить направление движения истребителя. Но именно в этом астероидном поле устроили засаду мириады вражеских перехватчиков – земному пилоту придется ой как не сладко! Однако всему этому придется подождать до следующего выпуска «Игростроя»... LXF

К этому будем стремиться

Основные функции

В файле ingame.h определен ряд функций, делающих программирование игр простым и понятным даже для новичков. Все они являются обертками над соответствующими функциями библиотеки SDL.

  • screen (ширина экрана , высота экрана) Устанавливает экранное разрешение.

Пример: Вызов screen(640,480) переключит монитор в режим 640x480.

  • loadsprite (номер ячейки , “название файла”) Загружает спрайт (рисунок) в память и связывает его с указанными номером.

Пример: loadsprite(5, “cat.bmp”) загружает файл cat.bmp с изображением кота и ассоциирует его с номером 5.

  • sprite (номер ячейки, x, y, [a]) Отображает ранее загруженный в память спрайт на экране. Функция может быть вызвана только после screen().

Пример: sprite (5, 100,150) разместит кота на экран в точке с координатами x=100, y=150: Четвертый необязательный параметр регулирует прозрачность спрайта и меняется в пределах от 0 (непрозрачный) до 255 (полностью прозрачный).

  • colorfon(R, G, B); Закрашивает фон экрана произвольным цветом. R,G,B – значения его красной, зеленой и синей составляющей, соответственно.
  • loadmusic (название файла, номер ячейки с музыкой); Загружает в память музыку в формате MID, MOD, XM, IT, WAV и т.д.

Пример: loadmusic (“sintez.mod”, 5);

  • music (номер ячейки с музыкой); Проигрывает ранее загруженный музыкальный ролик.

Пример: music (5);

  • loadsound (название файла, номер ячейки со звуком); Загружает в память звук в формате WAV.

Пример: loadsound (“boom.wav”,1);

  • sound (номер ячейки со звуком); Проигрывает ранее загруженный звук.

Пример: sound (1);

  • box(объект1, координата Х объекта1, Y объекта1, объект2, координата Х объекта2, координата Y объекта2, );

Простая проверка столкновения объекта1 и объекта2 (учитывается только пересечение прямоугольников, ограничивающих спрайт). Пример:

if (box(1, bomb_x, bomb_y, 2, ship_x, ship_y) ) {
   sound(“boom.wav”); }
  • fx(); Основная и обязательная функция. Обрабатывает события, поступающие от пользователя и формирует изображение на экране вашего монитора.

Пример: while (GAME) { fx(); }

Предопределенные переменные

В ingame.h определен целый ряд переменных, которые с большой вероятностью понадобятся вам при разработке своей игры.

Следует отметить, что движок работает с числами с плавающей точкой. Это значит, что мы можем перемещать спрайт не только на целое число пикселей (скажем, 1), но и на дробное – например 0.02. Это дает возможность выводить очень медленно перемещающиеся спрайты (например, далекие облака).

Список предопределенных переменных:

  • x, y Координаты спрайта первого игрока (тип float)
  • x2, y2 Координаты спрайта второго игрока (тип float)
  • LEFT, RIGHT, UP, DOWN Флаг, равный 1, если нажата клавиша «стрелка влево/вправо/вверх/вниз» или «огонь» (пробел), соответственно, и 0 в противном случае
  • GAME Флаг, сбрасываемый в 0, если пользователь нажал клавишу Escape
Персональные инструменты
купить
подписаться
Яндекс.Метрика