Меню сайта
Форма входа

Категории раздела
Уроки по созданию игр [38]
Программирование игр разной сложности
Игровые алгоритмы [24]
Алгоритмы, которые уже реализованы для разных жанров игр
Графика [5]
Учимся работать с графикой в Делфи
Мультимедиа [3]
Работа с мультимедийными возможностями Делфи
Другие статьи [18]
Статьи не вошедшие не в один из разделов
Ошибки [4]
Всевозможные ошибки и пути их решения
Четверг, 09.01.2025, 07:14
Приветствую Вас Гость

Статьи по программированию

Главная » Статьи » Уроки по созданию игр

Создание Ролевой игры РПГ на Паскале и Делфи. Урок 6

 

Урок 6. Добавляем средства визуализации карты-2

 

Во-первых, обращаю внимание на изменившийся дизайн. Координаты автора дизайна – в конце рассылки.

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

 

Вопросы

Один из главных. Turbo Pascal.

В Дельфи ПОКА этот код работать не будет. Ни в консольной, ни в другой версии – потому что для вывода на экран нам потребуются примитивные команды работы с текстовой видеопамятью TurboPascal, которые в Дельфи отсутствуют. Или вроде есть для Дельфи библиотека, которая позволяет эмулировать работу модулей CRT, DOS? Какие-то типа WinCtr, WinDos? Очень прошу, кто знает, подскажите плиз для тех, кто по каким-то причинам не может разобраться или задействовать TurboPascal. Есть для Дельфи библиотеки эмуляции текстовой dos-графики? Наибольшие трудности вызвали директивы условной компиляции. Естественно, так как ранее мы этого в Школе не проходили :)

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

А зачем тогда он нужен? Вот в нашем примере мы хотим, чтобы один и тот же исходный текст с минимальными модификациями работал бы (компилировался) в разных системах. Для этого в исходном тексте будут части, не имеющие отношения к конкретной операционной системе, а будут и зависимые от нее. Последние надо включать в исходный текст только с учетом выбранной целевой платформы исполнения (в зависимости от некоторых условий). Сами эти условия "включает" и "выключает" программист – надо сделать программу для Windows, он активизирует настройки для Windows; надо для Linux - активизирует для Linux. Сначала о настройках. Команда TP/Delphi {$DEFINE имя-константы} "включает" в программе константу с указанным именем. То есть считается, что такая константа определена.

{$DEFINE DOS_GAME}

Препроцессор теперь будет знать, что определена в проекте константа DOS_GAME. Сама по себе она ничего не значит, может быть либо определенной, либо не быть вообще. Далее препроцессор (он всегда работает ДО компилятора - компилятолр получает исходный текст, обработанный препроцессором) ищет в исходном тексте знакомые команды smile - все, что НЕ начинается с {$стандартная-команда-препроцессора...} он считает единым текстом, не нуждающемся в обработке. То есть препроцессору все равно, на Паскале, Си или еще чем-то написан исходный код, он понимает лишь команды своего препроцессорного языка. Это как бы дополнительный мета-язык обработки исходных текстов. Понимает препроцессор и условные операторы smile Это - пожалуй, его самая главная заслуга.

Основные нужные нам формы условных операторов препроцессора такие:

 

{$IFDEF имя-константы}

{$ENDIF}

{$IFDEF имя-константы}

 

Препроцессор выполняет их так. Встречая "IFDEF константа", он проверяет, была ли ранее свыше по тексту) определена указанная константа, и если да, то включает в результирующий I   11 пил"] текст часть текста, располагающуюся далее до команды ENDIF (по умолчанию любой текст программы, неохваченный командами препроцессора, целиком и без пений сразу выдается в результат).

Команда INDEF работает наоборот - включает следующую часть текста до ENDIF, если константа НЕ была определена.

Вот есть такой текст.

 

Implementation uses

{$IFDEF  DOS_GAME}

CRT;

{$IFENDIF}

 

Если ранее мы определили константу препроцессора DOS_GAME командой DEFINE, то данный условный оператор IFDEF включит строку с упоминанием модуля CRT в результирующий исходный текст. А если бы она не была определена (или если бы мы не пользовали команду IFNDEF), то результирующий текст получился бы таким (с ошибкой, так как без окончания):

 

implementation uses

 

Во всех модулях программы удобно использовать единый набор констант препроцессора, чтобы переопределив константу в одном месте, сразу получить нужную версию кода для компилятора. Мы собрали эти константы в файле Defines.Inc. Почему такое название? Просто такое выбрано :)

Defines - определения. Inc - от include, включать. Обратите внимание на расширение! Это не Defines.inc.TXT или Defines.Inc.Pas, а именно Defines.Inc - расширение .inc, скорее всего, в Windows не будет ни с чем ассоциировано.

Впрочем, ничто не мешает взять например название файла Defines.Pas и любое другое. Тогда текст примеров просто придется немного подправлять.

Значение содержимого стороннего файла осуществляется в текущий файл командой препроцессора {$ имя-файла}

 

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

Насчет модулей. Сейчас у нас три модуля - главная программа; модуль (файл) map.pas; модуль (файл) lowlеvel.pas. Когда я пишу "добавляем процедуру А в модуль map.pas", это значит, что в файл map.pas мы заносим код процедуры А. При этом занесение такое разделяется на две части:

Весь код процедуры мы размещаем в разделе implementation;

Заголовок процедуры мы размещаем в разделе interface.

Добавление процедуры ShowCcll в модуль LowLevel означает:

Добавили полное описание процедуры:

 

Unit LowLevel;

implementation

 

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

begin

end;

 

2. Добавили заголовок в интерфейсный раздел:

 

unit  LowLevel;

 

interface

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

 

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

Теперь перейдем к реализации процесса вывода таила карты на экран. Для этого, очевидно, нам потребуется выполнить некоторую предварительную инициализацию текстового/графического режима - чтобы например очистить экран, загрузить изображения и т. д. Создадим в модуле LowEevel процедуру Videolnitialize. Все, что она будет делать - это очищать экран. Данная деятельность потребует подключения стандартного в Turbo Pascal модуля CRT, ответственного за отрисовку в псевдографике, который нужно указать в заголовке реализации с учетом текущих настроек условной компиляции:

 

implementation  uses

{$IFDEF   D0S_GAME}

CRT;

{$ENDIF}

 

Сама процедура будет содержать только один вызов стандартной функции очистки экрана:

 

procedure Videolnitialize;

begin

ClrScr;

end;

 

Кроме того, в заголовок главной программы потребуется добавить ссылку на модуль LowLevel. В итоге она примет следующий вид:

 

program  LearningRPG;

uses Map,   LowLevel;

begin

Randomize;

Videolnitialize;

MapGeneration(1) ;

ShowMap;

readln;

end.

 

Отметим, что в данной главной программе никакие директивы условной компиляции не потребуются, так как для Delphi и Windows вся главная часть программы будет иметь совсем другой вид (только она одна будет сильно различаться). Соответствующая настройка проекта должна выполняться с помощью, например, утилиты-менеджера проекта. Мы до этого в свое время доберемся.

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

type  TTileRecord =   record

С:   Char;

Clr:   Integer

end;

 

const   TileRecords:   array[1..tileLast]   of TTileRecord =

(

(C:    ‘ . ‘   ;   Clr:Green),

(C:    ‘ _ ‘        ;   ClrrBrown),

(C:    ‘ _  ‘     ;   Clr:Brown),

:    '   л   '    ;   ClrrLightGray),

(С:    '    !    '    ;   ClrrLightGreen)

);

 

Объявление способа представления тайлов в виде константы имеет еще одно преимущество, иы захотим добавить в игру новый таил, компилятор при разборе модуля LowLevel означает ошибку. сообщив, что длина данного массива образов тайлов не соответствует максимальному числу тайлов (указанному в константе tileLast). Таким образом нам будет автоматически выдаваться напоминание о необходимости внести изменения в код программы.

  С какой части разместить это определение? Так, как оно привязано к ДОС-у и не используется ни в каких других модулях, кроме LowLevel, его правильнее всего ввести сразу за директивой implementation - точнее, после следующей за ней директивы условной компиляции {SIFDEF DOS_GAME}.

Чтобы программа компилировалась успешно, укажем в заголовке реализации ссылку на модуль Map:

 

implementation uses  Map,

{$IFDEF   DOS_GAME}

CRT;

{$ENDIF}

 

Ссылка на Map расположена в "независимой" от платформы части кода, потому что модуль Map не привязан к конкретной операционной системе.

Единственное, что нам остается сделать для отображения карты - это подготовить реализацию функции ShowCell. В текстовом режиме данная задача решается элементарно. Договоримся в начале окна вывода видимой части карты - допустим, это будет точка экрана с координатами (10,3), для чего опишем в начале ДОС-раздела реализации модуля LowLevel две константы:

 

Const    WINDOW_LEFT   =   10;

WINDOW_TOP  =   3;

 

К этим начальным координатам будем прибавлять координаты конкретного таила, предварительно задав его цвет, и затем выводить в нужную позицию окна с помощью стандартной функции GoToXY - с учетом сдвига видимой части окна, задаваемой переменными LocalMapLefVLocalMapTop. Цвет элемента сформируем вызовом стандартной процедуры TextColor.

 

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

begin

GoToXY (WINDOW_LEFT+x-GameMap[CurMap].LocalMapLeft,

WINDOW_TOP+y-GameMap[CurMap].LocalMapTop);

TextColor(   TileRecords[t.Tile].Clr   );

Write(   TileRecords[t.Tile].С   );

End;

 

Запустим программу - на экране появится изображение части карты! Каждый раз после нового запуска оно должно быть неповторимым.

Нажмем Enter, чтобы закрыть нашу программу. С выводом карты мы почти разобрались.

Почему почти? Потому, что пока мы не учитываем видимость тайлов, которая определяется значением флажка isVisible. Добавим соответствующую проверку - если таил невидим, то вместо символа таила выведем пробел:

 

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

begin

GoToXY( WINDOW_LEFT+x-GameMap[CurMap].LocalMapLeft,

WINDOW TOP+y-GameMap[CurMap].LocalMapTop );

TextColor ( TileRecords[t.Tile].Clr );

If t.isVisible then Write( TileRecords[t.Tile].С )

else Write(    '    '    );

end;

 

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

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

Категория: Уроки по созданию игр | Добавил: Armageddets (24.11.2012)
Просмотров: 1779 | Теги: программирование игр, как написать игру, Создание Ролевой игры РПГ на Паскал, урок по созданию игр, игровая карта, ролевая игра | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Наш опрос
Где Вам удобнее оставлять коментарии и задавать вопроссы?
Всего ответов: 24
Мини-чат
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Статистика

    Онлайн всего: 4
    Гостей: 4
    Пользователей: 0