Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Создание ролевой компьютерной игры 5) Добавляем средства визуализации карты


Информационный Канал Subscribe.Ru

 

5) Добавляем средства визуализации карты

Новости

Все анонсы по всем службам рассылок прошли - и нас теперь 7713 человек! Причем рост стабильно продолжается. Это хорошо. Цель - 10 тысяч :)

В последний раз напоминаю всем вновь присоединившимся (больше масштабных прибавлений не ожидается) - надо прочитать последние выпуски:

С Единицы

Общие принципы работы игровой программы

Перед программированием

Программируем карту


Вопросы

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

Дмитрий отметил, что русифицированная версия "Мории" не запускается. Об этом писали и другие, сначала я думал, что не запускается в XP SP2, но когда скачал архив - да, он распаковался с ошибкой и программа не запустилась. Дмитрий проявил настойчивость :) , за что ему благодарность, и теперь проверенный архив можно скачать по старому адресу http://russianenterprisesolutions.com/download/um.zip.

Кроме того, есть замечательный сайт http://nethack.ru/ целиком посвященный еще одной культовой "рогульке" НетХак (но она не про хакеров, а, конечно, по толкинским мотивам :). Правда, переведенного на русский, там вроде пока немного. Всего было два основных направления в roguelike-играх - Moria, NetHack, и лет десять назад добавился ADOM.

Спрашивали, почему выбрана Delphi/TurboPascal, ведь "про OpenGL говорят, что на Си проги будут действовать быстрее, потому что сама библиотека написана на Си".

а) Надо различать создание игры и создание движка для игры. Последнее я считаю глупым занятием, если только его авторы не собираются потом движок продавать (хотя все равно конкурировать с коллективами десятков математиков сложно, да и продать хоть что-то НА ПОРЯДОК СЛОЖНЕЕ, чем запрограммировать самый уникальный движок), или же у них нету собственных денег на лицензирование коммерческих движков. Хотя и опен-сорсных движков приличного качества достаточно.

б) Движок для 3D-игры реального времени и движок пошаговой Цивилизации - вещи очевидно разные. Для Цивилизации можно хоть на Бейсике писать, все равно будет шустрый :) А хороший 3D и на Си трудно, нужна куча ассемблерных вставок.
Мы НЕ будем делать 3D-движок реального времени, поэтому возможностей Delphi хватит с избытком.

в) На каком языке написана библиотека и из какой программы она вызывается, значения не имеет. Потому что все вызовы (интерфейс библиотеки) выполнены в едином стандарте, и функциям без разницы, из Си или Паскаля они вызываются. Они даже и не знают об этом. На скорость работы библиотечных функций, очевидно, форма их вызова никак не сказывается :) (если не принимать в расчет каких-нибудь долей процента из-за разных способов передачи параметров).

г) Вообще неправильно исходить из низкоуровневого быстродействия. Всю графическую работу сегодня берут на себя готовые библиотеки, а программная логика конкретной создаваемой игры отличается тем, что можно потратить месяц работы на вылизывание кода, или перевод его с Паскаля на Си, получив 5% выигрыша, а можно потратить неделю на то, чтобы ПОДУМАТЬ как следует и изменить сам АЛГОРИТМ работы прикладной программы так, что выигрыш составит 50% или 500%.

Анонсы

На сайте http://www.alex-world.nm.ru что-то организуется типа альянса рассылок по теме разработки комп. игр. Так, там есть HEROES 5 - НОВЫЕ ИДЕИ, ЧЕГО НАМ НЕ ХВАТАЕТ В ИГРАХ и др.

Здесь: http://www.frnet.narod.ru/ рассылка по веб-дизайну и веб-программированию.


Добавляем средства визуализации карты

Продолжаем это: Программируем карту

...В данной процедуре оказался не реализованным такой момент, как способ перемещения между пещерами. Мы договорились, что для этого будут задействованы специальные тайлы-ступеньки, однако таких входов-выходов должно быть немного. Мастера игростроения рекомендуют в качестве оптимального варианта размещать на карте два спуска вниз и один подъем. Последуем этому совету, добавив в конец процедуры следующий код (и описав дополнительную локальную переменную i):

  if MapLevel < MaxDungeonLevel then
    for i := 1 to 2 do
      begin
      FreeMapPoint(x,y);
      GameMap[CurMap].Cells[x,y].Tile := tileStairsDown;
      end;

  if MapLevel > 1 then
      begin
      FreeMapPoint(x,y);
      GameMap[CurMap].Cells[x,y].Tile := tileStairsUp;
      end;

Отметим, что упомянутая, но пока не реализованная процедура FreeMapPoint поиска свободной точки на карте будет нужна нам и в других точках программы - например, в поиске подходящего места для предметов, ловушек и т. п. Поэтому вынесем такой алгоритм в отдельную процедуру FreeMapPoint и поместим ее в модуль Map:

  procedure FreeMapPoint( var x,y: Integer );
  begin
  repeat
      x := random(MAP_WIDTH - LOCAL_MAP_WIDTH*2) +
  LOCAL_MAP_WIDTH;
      y := random(MAP_HEIGHT - LOCAL_MAP_HEIGHT*2) +
  LOCAL_MAP_HEIGHT;
  until FreeTile(GameMap[CurMap].Cells[x,y].Tile);
  end;

Здесь мы учли заполненные непроходимыми тайлами сдвиги LOCAL_MAP_WIDTH и LOCAL_MAP_HEIGHT по краям карты.

Так как при создании карты локации мы обратились к генератору случайных чисел, то сразу выполним его инициализацию в главной части программы, чтобы избежать повторений и одинаковых карт. Заодно добавим в главную программу ссылку на модуль Map и выполним компиляцию проекта, убедившись, что синтаксических ошибок нет.

  program LearningRPG;

  uses Map;

  begin
  Randomize;
  end.

Теперь все готово для вывода карты на экран. Для этого добавим в модуль Map процедуру отрисовки всей видимой части. Она будет очень простой - для каждой видимой ячейки карты вызывается процедура ее вывода.

  procedure ShowMap;
  var x,y: Integer;
  begin
  PrepareMap;
  for x := GameMap[CurMap].LocalMapLeft to
  GameMap[CurMap].LocalMapLeft + LOCAL_MAP_WIDTH - 1 do
  for y := GameMap[CurMap].LocalMapTop to
  GameMap[CurMap].LocalMapTop + LOCAL_MAP_HEIGHT - 1 do
      ShowCell(GameMap[CurMap].Cells[x,y],x,y);
  end;

Дополнительная процедура ShowCell добавлена умышленно, так как в игре нам наверняка понадобится возможность выводить (перерисовывать) отдельные элементы карты. Эта процедура будет относиться к "низкоуровневым" возможностям программы, зависящим от конкретной реализации и операционной системы. Где разместить ShowCell? Давайте подготовим новый модуль LowLevel, в котором будем хранить весь наш код, зависящий от реализации.

Процедура PrepareMap требуется нам для того, чтобы учесть особенности реализации графических функций перерисовки экрана. Так, в ДОС-е нам понадобится предварительно очищать экран от старой информации, накопленной на предыдущем игровом такте.

Каким образом разделять код, который будет относиться к ДОС-у и к Windows? Правильнее всего это сделать с помощью команд условной компиляции. Сформируем в каталоге проекта файл Defines.Inc, в котором поместим следующие строки:

  {$DEFINE DOS_GAME}
  { $DEFINE WIN_GAME}

  {$DEFINE RUSDOS_GAME}
  { $DEFINE RUSWIN_GAME}

Первые две строчки определяют платформу, для которой собирается проект, вторые две строчки задают, какой язык будет использоваться в программе для вывода всевозможных сообщений. Дело в том, что русские кодировки для ДОС-а и Windows различаются, поэтому нам придется дублировать все сообщения в двух кодировках (Alternative/IBM и Win1251). Данная возможность также будет крайне полезна при переносе нашей программы на другие языки - например, английский.

Обратите внимание, где поставлен пробел в инструкциях компилятору перед символом $. Если $ следует не сразу за фигурной скобкой, то он уже не воспринимается как инструкция, таким образом "включены" DOS_GAME и RUSDOS_GAME и "выключены" определения препроцессорных констант, подготовленных для Windows.

Добавим ссылку на файл определений в начало модуля LowLevel, и выделим в нем часть, связанную с ДОС-ом:

  {$I DEFINES.INC}

  unit LowLevel;

  interface

  procedure ShowCell(t: TMapCell; x,y: Integer);

  implementation

  {$IFDEF DOS_GAME}

  { ----------------- }
  procedure ShowCell(t: TMapCell; x,y: Integer);
  begin

  end;

  {$ENDIF}

  end.

Ссылку на модуль Map надо ввести в интерфйсном разделе:

interface uses Map;

Размещение ссылок на рабочие модули программы в интерфейсном разделе потенциально чревато неприятными ошибками, связанными с закольцованныаи ссылками. Например, если мы в дальнейшем определим в интерфейсе модуля LowLevel некий тип или константу, которые захотим использовать в интерфейсной части модуля Map, то получим запрещенную ситуацию - два интерфейсных раздела разных модулей ссылаются друг на друга:

  unit LowLevel;
  interface uses Map;
  ...

  unit Map;
  interface uses LowLevel;
  ...

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

Наш случай - исключение. Модуль LowLevel предназначен только для реализации низкоуровневых функций вывода на информации экран, зависящих от операционной системы, и поэтому на него достаточно ссылаться из "внутренности" всех других модулей - раздела Implementation.

Таким же образом добавим процедуру PrepareMap. Она будет состоять из одного вызова стандартной функции очистки окна:

  procedure PrepareMap;
  begin
  ClrScr;
  end;

Теперь укажем в заголовке реализации модуля Map ссылку на этот модуль:

implementation uses LowLevel;

В главной части программы теперь можно вызвать процедуру генерации карты (первого уровня пещеры) и вывода ее на экран. По завершении вывода подождем нажатия на клавишу Enter:

  program LearningRPG;

  uses Map;

  begin
  Randomize;
  MapGeneration(1);
  ShowMap;
  readln;
  end.

Перекомпилируем и запустим программу. Пока она, конечно, ничего не покажет, так как процедура ShowCell не содержит никакого кода, но тем не менее генерация карты должна выполниться успешно.

Далее - завершаем визуализацию карты и начинаем программировать главного героя


(c) 2004-2005 Сергей Бобровский bobrovsky@russianenterprisesolutions.com

Все предыдущие выпуски базового курса тут:
http://russianenterprisesolutions.com/sbo/

 

Subscribe.Ru
Поддержка подписчиков
Другие рассылки этой тематики
Другие рассылки этого автора
Подписан адрес:
Код этой рассылки: comp.soft.prog.prognull.game
Отписаться
Вспомнить пароль

В избранное