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

Создание ролевой компьютерной игры 8) Программируем главного героя-2


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

Создание ролевой компьютерной игры


8) Программируем главного героя-2

Насчет питерских вузов и программирования

На самом деле почти любой технический ВУЗ. В СПбГТИ(ТУ), например аж два факультета связаны с этим, хотя лучшими считаются ИТМО (его студенты не раз побеждали в международных олимпиадах по программированию) и Бонч (особенно по защите инфы и, соответственно по ее же взлому =))

По поводу вопроса о том, где учат программистов в Питере:
По-моему, два лучших места - это СПбГУ, математико-механический факультет и ИТМО, там несколько факультетов. Так же можно рассмотреть ПМ-ПУ в Университете.

Письма от шутников

куда писать процедуры и все остальное
Ярик

Я тут сделал ваш проигрователь который на сайте и вот что мне не ясно как сделать чтобы добавлялся весь альбом сразу а не лазить каждый раз в Delphi И не менять там музыку То что написано на сайте я делал не чего не получается.
Слава

Я хочу прислать вам на проверку свои исходники по вашим урокам, потому что паскаль при запуске (Run) выдаёт ошибки насчёт записей пас файлах про неизвесные значения и недаёт запускать!
Проверьте их и, если в них всё правильно пришлите ссылку где взять нармальный Паскаль который будет нармально устанавливаться.
А если неправильно я вас прошу показать в чём моя ошибка.
Константин.

С удовольствием помог бы всем, но свободное время есть исключительно на данную рассылку. Поэтому с ЛЮБЫМИ (это слово понятно?) вопросами просьба на сайт http://srt.starinet.com/begin/ , там вам всегда помогут и подскажут замечательные люди.
Особенно сурово и безжалостно :) я отношусь к письмам "а я хочу чтобы только вы"... Буду публиковать такие письма вместе с адресами в рассылке и еще отдавать их спамерам, предупреждаю.

ЕДИНСТВЕННОЕ исключение, для кого я нахожу время - если в письме говорится "а я сделал еще лучше, чем вы". Это - да.


Программируем главного героя-2

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

  procedure ShowHero(HeroNum: Integer);
  begin
  GoToXY(
  WINDOW_LEFT+Heroes[HeroNum].x-GameMap[CurMap].LocalMapLeft,
          
  WINDOW_TOP+Heroes[HeroNum].y-GameMap[CurMap].LocalMapTop );
  TextColor( White );
  Write( 'X' )
  end;

Герой выводится белым символом X. Чтобы процедура комплировалась нормально, в список подключаемых модулей раздела реализации надо добавить модуь Hero:

  implementation uses Hero,
  {$IFDEF DOS_GAME}
          CRT;
  {$ENDIF}

В каком месте программы надо выводить образ героя?

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

  unit Game;

  interface

  procedure ShowGame;

  implementation uses Map, LowLevel, Hero;

  { ----------------- }
  procedure ShowGame;
  begin
  ShowMap;
  ShowHero(CurHero);
  end;

  end.

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

  program LearningRPG;

  uses Map, LowLevel, Hero, Game;

  begin
  Randomize;

  VideoInitialize;
  MapGeneration(1);
  InitHeroes;

  ShowGame;
  readln;
  end.

Запустив эту программу, мы получим на экране уже что-то, напоминающее вид нормальной игры.

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

В первом приближении реализация управленческого цикла может выглядеть так (вставляем его после InitHeroes, вместо двух последних строк):

  while true do
    begin
    ShowGame;

    k := ReadKey;
    case k of
       #0: begin
           k := ReadKey;
           case k of
            ' K ' : MoveHero( -1,0 );
            ' M ' : MoveHero( +1,0 );
            ' H ' : MoveHero( 0,-1 );
            ' P ' : MoveHero( 0,+1 );
           end;
           end;

       #27 : break;

    end;
    end;

Рассмотрим этот код поподробнее. В начале бесконечного цикла происходит опрос клавиатуры, и в зависимости от нажатой клавиши происходит вызов той или иной функции программы. Значение #0 означает, что нажата специальная клавиша (функциональная или клавиша-стрелка), поэтому необходимо считать дополнительный клавиатурный код. Значение #27 соответствует клавише Escape, значения K, M, N, P - стрелкам "влево", "вправо", "вверх" и "вниз". Чтобы переместить героя по карте, надо вызвать процедуру MoveHero, которая получает в качестве параметров сдвиг относительно текущего положения героя по горизонтали и вертикали. Так, вызов MoveHero( +1,0 ) должен сдвинуть героя на карте на один тайл вправо (координата x увеличится на +1, а координата y не извенится).

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

Реализацию процедуры MoveHero разместим в модуле Game, не зависящем от платформы. Нам удастся обойтись уже готовыми функциями отрисовки, подготовленными в модуле LowLevel.

  procedure MoveHero( dx,dy: Integer );
  begin
  if not FreeTile( GameMap[CurMap].Cells[
  Heroes[CurHero].x+dx,Heroes[CurHero].y+dy].Tile ) then
     Exit;

  inc(Heroes[CurHero].x,dx);
  inc(Heroes[CurHero].y,dy);
  SetHeroVisible(CurHero);

  end;

Этот код достаточно тривиален - сначала проверяется, свободен ли тайл, в направлении которого выполняется перемещение героя. Если он свободен, происходит изменение координат героя. В новом месте уточняется, какие тайлы вокруг героя стали видимыми.

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

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

Исходный код текущей версии:

http://russianenterprisesolutions.com/sbo/download/1395.zip 3249 байтов

А также оригинальная версия программы на Си++ от подписчика Павла: http://russianenterprisesolutions.com/sbo/download/rgl.rar 18 kb с графикой.

И его замечание:

PS: да, хочу дать небольшой совет. При размещении основных важных объектов(и особенно "порталов" для перехода на другие уровни) нужно ставить их так, чтобы герой смог до них добраться - иначе примерно в 20% случаев он оказывается "запертым" на уровне - проверено на собственном опыте. Я обхожу это так - создаю "карту доступа"(двумерный массив с такими же размерами, как и сама игровая карта; элементы массива имеют тип bool), который показывает доступность/недоступность ячеек игровой карты. И размещаю объекты(монстры, etc) в соответствии с этой информацией. Сама функция создания карты доступа занимает несколько строк - можете посмотреть в исходниках.

Да, конечно, проблема тупика время от времени возникает.
Наш код - учебный, и что вы его развиваете - замечательно!

А вот комментарий Дмитрия:

Процесс создания игры продолжается, герой уже создан, и отображается на экране. Возникли следующие предложения:
1) характеристику "сила зрения" (поле VisLong) включить в список характеристик героя (массив Chars). В этом случае можно будет менять силу зрения героя как другие атрибуты, например, в случае, если его подвергли действию заклинания "Слепота" или он выпил бутылочку усилителя зрения или инфравидения.
2) при задании списка констант их можно описывать следующим образом: значение каждой следующей = значение предыдущей + 1. Т.е.:
statMin = 1;
statStr = statMin;
statDex = statStr+1;
statCon = statDex+1;
statInt = statCon+1;
statSightStr = statInt+1;
statHealth = statSightStr+1;
statMax = statHealth;
Плюсы - всегда известно минимальное и максимальное значение константы, легко модифицировать последовательность значений. например, при добавлении после statCon новой константы statWill (воля), добавлется одна строка statWill = statCon+1, и меняется следующая строка statInt = statWill+1. Остальные константы меняют свое значение автоматически. Минусы - надо более тщательно следить за правильной последовательностью констант и приращений. Например, если забыть изменить в предыдущем примере значение statInt - появятся две константы с разными именами и одинаковым значением.
В то же время такой подход удобен для циклической обработки всех значений. Например, я использовал такой подход для вывода характеристик героя:

    with FMain.mm_Stats.Lines do begin
      Clear;
      for i:=statMin to statMax do
        Add(Format( ' %10s %d ' ,[StatNames[i],C.Stats[i]]));
    end;

Этот цикл работает для любого количества характеристик героя (здесь я пользуюсь обозначением Stat вместо Chars). Метод вывода героя на экран помещен в LowLevel. В данном примере С - переменная героя (передается как параметр). Вывод осуществляется в компонент Memo (mm_Stats) главной формы (FMain)
3) Я отказался от конкретной записи для героя и обобщил на случай любого существа (Creature). То есть любой монстр характеризуется теми же характеристики, что и герой (но другими значениями этих характеристик!).
То есть описывается отдельный метод для вывода любого существа, и он используется как для вывода героя, так и для вывода монстра.
Прошу прощения, что пользуюсь отличающимися от Ваших обозначениями. Если мой вариант усложняет понимание, напишите - я буду изменять в соответствии с Вашими исходными текстами.

Полностью согласен с Дмитрием, но весь текст всего проекта у меня уже готов до самого конца, поэтому я не смогу внести в него эти коррективы :) Кто хочет, может учесть поправки самостоятельно, а я выложу ваш вариант кода тоже.

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

То, что мы сейчас делаем в текстовом виде, напоминаю, в будущем будет перенесено в Дельфи полноценно, с использованием графики, причем быстро и комфортно за счет правильной :) архитектуры всего приложения. А пока мы отлаживаем сам "движок" :-)

Вот кстати вариант питерского, как я понял :), программиста:

Врать не буду, начал учить язык уже четыре года назад, а на курс подписался больше из интереса (во что это вырастет). Результаты очень радуют. Хочется выразить Вам свое уважение. Я тоже занимаюсь подобным, правда в гораздо более узком кругу, зато мои уже вовсю в АПИ шпарят =Р.
Перевел вашу РПГ в OpenGL, а то кричат тут, мол, сложно это =).
Ничего подобного ЖЛ+АПИ=РУЛЕЗ. Аналогично и с ассемблером. Просто нужны навыки. А писать АПИшное приложение, на АСМе также просто, как и на Delphi. Добавил пару мелочей (звук и простенький эффект с днем/ночью (булева переменная "ночь"))
Еще раз большой Вам Респект =)
Будете в Питере, сообщите. С меня пиво (или два ;))

Хм. Пиво, это хорошо! Вот вариант на опенжл:

http://russianenterprisesolutions.com/sbo/download/ogl.rar 74 kb

Идеей со стринггридом оказались довольны не все. Вот что Александр пишет:

Идея со стринггридом - на мой взгляд, не очень хорошая, т.к., как мне кажется, программа с его использованием будет крайне медленной.
Я использую tImage + расчет экранных координат из координат массива клеток карты.
Графика - из "спрайтов" 32х32. Есть вариант под DelphiX - он вообще летает.
Для меня всё, что пока было опубликовано в Вашей рассылке - пройденный этап. ;-)
Квадратная зона видимости меня не устраивает категорически - использую круглую вычисляемую. Пока еще не сделал ограничение З.В. препятствиями. Делаю.
Моя основная головная боль - это инвентарь. Как хранить, как отображать, как с ним работать... Хотя и эта проблема решаема, при наличии лишней сотни часов.
Вторая проблема - хороший генератор лабиринта.Он должен быть заточен именно под мою игру, так что готовые не годятся...
Кстати на эту тему могу порекомендовать крайне интересный сайт - http://www.astrolog.org/labyrnth/algrithm.htm
Человек посвятил свою жизнь всяческим лабиринтам, их теории и практике. Много интересного.
А вообще, Ваша рассылка - качественная.
В отличии от многих других. :-(

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


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

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

Дизайн рассылки: Алексей Голубев - Web-дизайн и web-программирование


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

В избранное