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

LXF84:Ogre

Материал из Linuxformat
(Различия между версиями)
Перейти к: навигация, поиск
(Новая: {{Цикл/Ogre}} == Ogre: Освещаем новый дом == ''ЧАСТЬ 3: Как превратить травянистый холм в крепость в стиле Тюдор...)
 
м
Строка 1: Строка 1:
 
{{Цикл/Ogre}}
 
{{Цикл/Ogre}}
 +
 
== Ogre: Освещаем новый дом ==
 
== Ogre: Освещаем новый дом ==
''ЧАСТЬ 3: Как превратить травянистый холм в крепость в стиле Тюдоров и создать солнце и луну всего на четырех страницах? У '''Пола Хадсона''' есть ответ...''
+
''ЧАСТЬ 3: Как превратить травянистый холм в крепость в стиле Тюдоров и создать солнце и луну всего на четырех страницах? У '''Пола Хадсона''' есть ответ…''
  
В этот урок мы включили много интересного: наша задача – взять
+
В этот урок мы включили много интересного: наша задача — взять
 
пустой ландшафт из прошлого номера, построить дом на плато,
 
пустой ландшафт из прошлого номера, построить дом на плато,
 
добавить света и тени, и, самое интересное, позволить игроку
 
добавить света и тени, и, самое интересное, позволить игроку
гулять по дому. Легко? Ой, нет. А моя задача – как раз облегчить работу, поэтому приготовьтесь разогнать игру до скорости света!
+
гулять по дому. Легко? Ой, нет. А моя задача — как раз облегчить работу, поэтому приготовьтесь разогнать игру до скорости света!
  
 
Мы загружали ландшафт в игру Висельник Чед с помощью файла
 
Мы загружали ландшафт в игру Висельник Чед с помощью файла
Строка 16: Строка 17:
 
Переместите файл terrain.cfg из каталога media в ваш главный
 
Переместите файл terrain.cfg из каталога media в ваш главный
 
каталог, где размещен код. Затем переместите файлы terrain_detail.jpg,
 
каталог, где размещен код. Затем переместите файлы terrain_detail.jpg,
terrain.png и terrain_texture.jpg из media/materials/textures в ваш главный каталог. Учтите, я сказал «переместите», а не «скопируйте» – не
+
terrain.png и terrain_texture.jpg из media/materials/textures в ваш главный каталог. Учтите, я сказал «переместите», а не «скопируйте» — не
 
оставляйте оригиналы там, где они находятся, не то они будут читаться вместо ваших собственных файлов. Эти четыре файла определяют,
 
оставляйте оригиналы там, где они находятся, не то они будут читаться вместо ваших собственных файлов. Эти четыре файла определяют,
 
как выглядит и ведет себя ландшафт.
 
как выглядит и ведет себя ландшафт.
Строка 22: Строка 23:
 
Используемый нами менеджер сцены, ответственный за обработку неба и земли, создает ландшафт по двумерной карте высот (это
 
Используемый нами менеджер сцены, ответственный за обработку неба и земли, создает ландшафт по двумерной карте высот (это
 
полутоновой план ландшафта, на котором наивысшие точки показаны
 
полутоновой план ландшафта, на котором наивысшие точки показаны
белым цветом, а самые низкие – черным). В файле terrain.cfg указана
+
белым цветом, а самые низкие — черным). В файле terrain.cfg указана
 
карта высот terrain.png. Действительный цвет определяется файлом
 
карта высот terrain.png. Действительный цвет определяется файлом
 
terrain_texture.jpg, который «натягивается» на весь ландшафт. Наконец,
 
terrain_texture.jpg, который «натягивается» на весь ландшафт. Наконец,
Строка 33: Строка 34:
 
Gimp»). Вы также заметите, что я сменил цвет terrain_texture.
 
Gimp»). Вы также заметите, что я сменил цвет terrain_texture.
 
jpg на цвет травы, ну устал я от этой пустыни! Теперь откройте в текстовом редакторе файл terrain.cfg и найдите строчку #VertexNormal=Yes.
 
jpg на цвет травы, ну устал я от этой пустыни! Теперь откройте в текстовом редакторе файл terrain.cfg и найдите строчку #VertexNormal=Yes.
Знак # это комментарий, означающий, что VertexNormal отключен.
+
Знак # — это комментарий, означающий, что VertexNormal отключен.
Удалите #, чтобы включить опцию – это вынудит Ogre генерировать
+
Удалите #, чтобы включить опцию — это вынудит Ogre генерировать
 
нормали для нашего ландшафта, которые понадобятся нам позже
 
нормали для нашего ландшафта, которые понадобятся нам позже
 
(см. врезку «Зачем нужны нормали»). В файле resources.cfg
 
(см. врезку «Зачем нужны нормали»). В файле resources.cfg
 
проверьте, что в секции General указано FileSystem=., это заставит Ogre
 
проверьте, что в секции General указано FileSystem=., это заставит Ogre
 
считывать файлы ландшафта из вашего текущего каталога. Вперед!
 
считывать файлы ландшафта из вашего текущего каталога. Вперед!
Запустите нашу игру – вы увидите обширную площадку, здесь-то мы
+
Запустите нашу игру — вы увидите обширную площадку, здесь-то мы
и поставим...
+
и поставим…
  
 
=== Дом, который построил Пол ===
 
=== Дом, который построил Пол ===
Строка 58: Строка 59:
 
HouseNode->scale(0.25,0.125,0.25);
 
HouseNode->scale(0.25,0.125,0.25);
 
</source>
 
</source>
Файл tudorhouse.mesh – один из стандартных сеточных объектов,
+
Файл tudorhouse.mesh — один из стандартных сеточных объектов,
 
входящих в Ogre, и он выглядит великолепно. Заметим также, что дом
 
входящих в Ogre, и он выглядит великолепно. Заметим также, что дом
 
огромный, поэтому я использовал scale() и приспособил его размер к
 
огромный, поэтому я использовал scale() и приспособил его размер к
 
ландшафту. Вот и все, что требовалось для добавления дома в нашу
 
ландшафту. Вот и все, что требовалось для добавления дома в нашу
 
игру, поэтому перезапустите make и полюбуйтесь результатом. Нет,
 
игру, поэтому перезапустите make и полюбуйтесь результатом. Нет,
определения столкновений пока нет – оставим его на потом!
+
определения столкновений пока нет — оставим его на потом!
  
 
=== Небесное вторжение ===
 
=== Небесное вторжение ===
Строка 83: Строка 84:
 
три типа теней и три типа света. Разница между тенями заключается
 
три типа теней и три типа света. Разница между тенями заключается
 
в скорости: тень низкого качества прорисовывается быстрее всего.
 
в скорости: тень низкого качества прорисовывается быстрее всего.
Первый тип – SHADOWTYPE_TEXTURE_MODULATIVE, использующий
+
Первый тип — SHADOWTYPE_TEXTURE_MODULATIVE, использующий
 
простую текстуру для создания теней в нужных местах. На практике
 
простую текстуру для создания теней в нужных местах. На практике
тени получаются грубоватые – сгодятся только для тех, у кого слабая видеокарта, все остальные в восторг не придут. Следующий по
+
тени получаются грубоватые — сгодятся только для тех, у кого слабая видеокарта, все остальные в восторг не придут. Следующий по
качеству тип – SHADOWTYPE_STENCIL_MODULATIVE. Тени выглядят
+
качеству тип — SHADOWTYPE_STENCIL_MODULATIVE. Тени выглядят
 
более привлекательно, но создаются в один проход, поэтому результат не идеален. Наконец, SHADOWTYPE_STENCIL_ADDITIVE. Тут тени
 
более привлекательно, но создаются в один проход, поэтому результат не идеален. Наконец, SHADOWTYPE_STENCIL_ADDITIVE. Тут тени
 
выглядят превосходно, для каждого источника света построение осуществляется за отдельный проход, поэтому пересечение теней от двух
 
выглядят превосходно, для каждого источника света построение осуществляется за отдельный проход, поэтому пересечение теней от двух
Строка 93: Строка 94:
  
 
Каждый из трех типов источников характеризуется своим способом
 
Каждый из трех типов источников характеризуется своим способом
освещения. Точечный источник излучает свет как Солнце – одинаково
+
освещения. Точечный источник излучает свет как Солнце — одинаково
 
во всех направлениях, из определенной точки. Источник направленного света излучает свет в одном направлении и не имеет начальной
 
во всех направлениях, из определенной точки. Источник направленного света излучает свет в одном направлении и не имеет начальной
 
точки. С нашей позиции на Земле солнце выглядит направленным
 
точки. С нашей позиции на Земле солнце выглядит направленным
Строка 102: Строка 103:
  
 
Оба наших источника, солнце и луна, находятся очень далеко, поэтому они могут считаться источниками направленного света.
 
Оба наших источника, солнце и луна, находятся очень далеко, поэтому они могут считаться источниками направленного света.
Не будем пренебрегать деталями – выберем опцию SHADOWTYPE_STENCIL_ADDITIVE, чтобы тени хорошо смотрелись. В последующем
+
Не будем пренебрегать деталями — выберем опцию SHADOWTYPE_STENCIL_ADDITIVE, чтобы тени хорошо смотрелись. В последующем
 
коде немного приглушим рассеянное освещение, чтобы заметнее стали дневной и ночной источники света.
 
коде немного приглушим рассеянное освещение, чтобы заметнее стали дневной и ночной источники света.
  
Вот код – поместите его в метод createScene():
+
Вот код — поместите его в метод createScene():
 
<source lang="cpp">
 
<source lang="cpp">
 
m_SceneMgr->setAmbientLight( ColourValue(0.35, 0.35, 0.35) );
 
m_SceneMgr->setAmbientLight( ColourValue(0.35, 0.35, 0.35) );
Строка 137: Строка 138:
 
крепость не похоже, правда? Сейчас мы это изменим, соорудив внутри заведомо неприветливую обстановку. На последних трех уроках мы
 
крепость не похоже, правда? Сейчас мы это изменим, соорудив внутри заведомо неприветливую обстановку. На последних трех уроках мы
 
играли в песочнице менеджера сцен Ogre для открытого ландшафта,
 
играли в песочнице менеджера сцен Ogre для открытого ландшафта,
но если наши персонажи намерены разгуливать по зданию, потребуется еще один менеджер сцены – BSP.
+
но если наши персонажи намерены разгуливать по зданию, потребуется еще один менеджер сцены — BSP.
  
 
BSP означает binary space partition [двоичное разбиение пространства] и позволяет очень быстро загружать и обрабатывать закрытые
 
BSP означает binary space partition [двоичное разбиение пространства] и позволяет очень быстро загружать и обрабатывать закрытые
Строка 179: Строка 180:
 
scenemanager = ST_EXTERIOR_CLOSE;
 
scenemanager = ST_EXTERIOR_CLOSE;
 
</source>
 
</source>
Метод frameStartedInside() новый, но ничего особенного не делает
+
Метод frameStartedInside() новый, но ничего особенного не делает -
 
в данный момент он должен представлять урезанную версию метода
 
в данный момент он должен представлять урезанную версию метода
 
frameStartedOutside() и обрабатывать простой ввод от клавиатуры. Вот
 
frameStartedOutside() и обрабатывать простой ввод от клавиатуры. Вот
Строка 199: Строка 200:
 
}
 
}
 
</source>
 
</source>
Вы заметите, что переменная playerspeed умножена на пять – дело
+
Вы заметите, что переменная playerspeed умножена на пять — дело
 
в том, что карта Quake огромна, и прогулка с прежней скоростью превратилась бы в вечность. Если такое решение вы находите примитивным, попробуйте увеличить ландшафт, удалив вызов scale() для дома,
 
в том, что карта Quake огромна, и прогулка с прежней скоростью превратилась бы в вечность. Если такое решение вы находите примитивным, попробуйте увеличить ландшафт, удалив вызов scale() для дома,
 
а затем выберите значение скорости, пригодное везде.
 
а затем выберите значение скорости, пригодное везде.
Строка 238: Строка 239:
 
к камере. Метод getSuggestedViewport() считывает произвольную начальную позицию игрока на карте и устанавливает камеру в эту
 
к камере. Метод getSuggestedViewport() считывает произвольную начальную позицию игрока на карте и устанавливает камеру в эту
 
точку. Нам необходимо установить оси камеры pitch и yaw потому,
 
точку. Нам необходимо установить оси камеры pitch и yaw потому,
что Quake использует для плоскости пола координаты Х и Y, а Z – для
+
что Quake использует для плоскости пола координаты Х и Y, а Z — для
высоты, а мы обычно используем для пола X и Z и Y – для высоты.
+
высоты, а мы обычно используем для пола X и Z и Y — для высоты.
  
 
Мы еще не закончили: понадобится добавить две строки в начало
 
Мы еще не закончили: понадобится добавить две строки в начало
Строка 252: Строка 253:
 
CChadGame() (который находится в начале chad.cpp) заменен на
 
CChadGame() (который находится в начале chad.cpp) заменен на
 
createOutdoorScene(). Ну вот и все: запустите make, затем chad.
 
createOutdoorScene(). Ну вот и все: запустите make, затем chad.
Посмотрим, заметите ли вы разницу....
+
Посмотрим, заметите ли вы разницу….
  
 
=== Сложный вопрос ===
 
=== Сложный вопрос ===
ОК, разницы нет – по крайней мере, с точки зрения игрока. Это
+
ОК, разницы нет — по крайней мере, с точки зрения игрока. Это
 
потому, что мы написали код обработки для закрытой сцены, но не
 
потому, что мы написали код обработки для закрытой сцены, но не
 
написали кода, загружающего эту сцену. Вы вольны написать код,
 
написали кода, загружающего эту сцену. Вы вольны написать код,
Строка 267: Строка 268:
 
области просмотра, расположен в методах create*Scene(), поэтому
 
области просмотра, расположен в методах create*Scene(), поэтому
 
о них беспокоиться не надо. Все, что нам надо сделать, это вызвать
 
о них беспокоиться не надо. Все, что нам надо сделать, это вызвать
требуемый метод create*Scene(),например, так:
+
требуемый метод create*Scene(), например, так:
 
<source lang="cpp">
 
<source lang="cpp">
 
if (m_InputReader->isKeyDown(KC_F1)) createIndoorScene();
 
if (m_InputReader->isKeyDown(KC_F1)) createIndoorScene();
Строка 280: Строка 281:
 
Мы рассмотрели в этом руководстве много нового. Труднее всего
 
Мы рассмотрели в этом руководстве много нового. Труднее всего
 
уместить в голове переход от одного менеджера сцены к нескольким;
 
уместить в голове переход от одного менеджера сцены к нескольким;
все остальное сравнительно просто! Я надеюсь, что вам понравилось, как легко Ogre создает освещение и тени и работает с уровнями BSP, хотя покамест некоторые недостатки игры могут и раздражать – отсутствие обнаружения столкновений, плохой ввод, небо, на
+
все остальное сравнительно просто! Я надеюсь, что вам понравилось, как легко Ogre создает освещение и тени и работает с уровнями BSP, хотя покамест некоторые недостатки игры могут и раздражать — отсутствие обнаружения столкновений, плохой ввод, небо, на
 
котором не сказывается освещение, и так далее. Часть недостатков
 
котором не сказывается освещение, и так далее. Часть недостатков
 
вы можете исправить сами, ведь это руководство написано для того,
 
вы можете исправить сами, ведь это руководство написано для того,
 
чтобы игру программировали вы, а не я. Но с остальными мы разберемся вместе. До следующего раза!
 
чтобы игру программировали вы, а не я. Но с остальными мы разберемся вместе. До следующего раза!

Версия 21:22, 22 ноября 2008

Содержание

Ogre: Освещаем новый дом

ЧАСТЬ 3: Как превратить травянистый холм в крепость в стиле Тюдоров и создать солнце и луну всего на четырех страницах? У Пола Хадсона есть ответ…

В этот урок мы включили много интересного: наша задача — взять пустой ландшафт из прошлого номера, построить дом на плато, добавить света и тени, и, самое интересное, позволить игроку гулять по дому. Легко? Ой, нет. А моя задача — как раз облегчить работу, поэтому приготовьтесь разогнать игру до скорости света!

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

Переместите файл terrain.cfg из каталога media в ваш главный каталог, где размещен код. Затем переместите файлы terrain_detail.jpg, terrain.png и terrain_texture.jpg из media/materials/textures в ваш главный каталог. Учтите, я сказал «переместите», а не «скопируйте» — не оставляйте оригиналы там, где они находятся, не то они будут читаться вместо ваших собственных файлов. Эти четыре файла определяют, как выглядит и ведет себя ландшафт.

Используемый нами менеджер сцены, ответственный за обработку неба и земли, создает ландшафт по двумерной карте высот (это полутоновой план ландшафта, на котором наивысшие точки показаны белым цветом, а самые низкие — черным). В файле terrain.cfg указана карта высот terrain.png. Действительный цвет определяется файлом terrain_texture.jpg, который «натягивается» на весь ландшафт. Наконец, файл terrain_detail.jpg обеспечивает детали, которые будут расположены поверх terrain_texture.jpg, чтобы текстура выглядела сложнее, чем она есть на самом деле.

Чего нам не хватает, так это места для нашей постройки. В моей версии terrain.png (она находится на диске) я подредактировал карту, чтоб выделить пространство для здания (см. «Создание карты высот в Gimp»). Вы также заметите, что я сменил цвет terrain_texture. jpg на цвет травы, ну устал я от этой пустыни! Теперь откройте в текстовом редакторе файл terrain.cfg и найдите строчку #VertexNormal=Yes. Знак # — это комментарий, означающий, что VertexNormal отключен. Удалите #, чтобы включить опцию — это вынудит Ogre генерировать нормали для нашего ландшафта, которые понадобятся нам позже (см. врезку «Зачем нужны нормали»). В файле resources.cfg проверьте, что в секции General указано FileSystem=., это заставит Ogre считывать файлы ландшафта из вашего текущего каталога. Вперед! Запустите нашу игру — вы увидите обширную площадку, здесь-то мы и поставим…

Дом, который построил Пол

В LXF83 я писал, что в игре Висельник Чед предусмотрено наличие зданий и возможность игроков входить в них, а там, возможно, вступать в борьбу. Теперь, когда мы разровняли место, пора строить домик в тюдоровском стиле. Чтобы создать сетку дома, нам требуется объект Entity, представляющий наш дом, и SceneNode (оболочка объекта, которая позволит позиционировать дом в пространстве). Мы ставим дом раз навсегда, двигаться ему не надо, поэтому просто объявим Entity в chad.h. Добавьте строку в chad.h сразу за определением m_OceanFlowNum:

Entity* HouseEntity

Теперь добавьте этот код в конец метода createScene() файла chad.cpp:

HouseEntity = m_SceneMgr->createEntity("house", "tudorhouse.mesh");
SceneNode* HouseNode = m_SceneMgr->getRootSceneNode()-> createChildSceneNode("HouseNode");
HouseNode->attachObject(HouseEntity);
HouseNode->translate(1100,137, 500);
HouseNode->scale(0.25,0.125,0.25);

Файл tudorhouse.mesh — один из стандартных сеточных объектов, входящих в Ogre, и он выглядит великолепно. Заметим также, что дом огромный, поэтому я использовал scale() и приспособил его размер к ландшафту. Вот и все, что требовалось для добавления дома в нашу игру, поэтому перезапустите make и полюбуйтесь результатом. Нет, определения столкновений пока нет — оставим его на потом!

Небесное вторжение

Сейчас свет в нашей сцене рассеянный, и у сцены скучный и безжизненный вид. Добавлю-ка я немного простых источников, чтобы вы увидели, как работают свет и тени. Упор сделан на слове «простые», потому что Ogre плоховато работает с освещением неба и земли.

Потребуется четыре переменных для работы со светом в chad.h; добавим их в конец класса CChadGame:

Light* m_SunLight;
Light* m_MoonLight;
double m_SunY;
double m_SunZ;

Да, мы собираемся создать два света: один для солнца, второй для луны. Для получения простого эффекта смены дня и ночи нам надо вращать два источника света по кругу, чтобы свет плавно перемещался по ландшафту. Также необходимо включить тени. У Ogre есть три типа теней и три типа света. Разница между тенями заключается в скорости: тень низкого качества прорисовывается быстрее всего. Первый тип — SHADOWTYPE_TEXTURE_MODULATIVE, использующий простую текстуру для создания теней в нужных местах. На практике тени получаются грубоватые — сгодятся только для тех, у кого слабая видеокарта, все остальные в восторг не придут. Следующий по качеству тип — SHADOWTYPE_STENCIL_MODULATIVE. Тени выглядят более привлекательно, но создаются в один проход, поэтому результат не идеален. Наконец, SHADOWTYPE_STENCIL_ADDITIVE. Тут тени выглядят превосходно, для каждого источника света построение осуществляется за отдельный проход, поэтому пересечение теней от двух источников будет выглядеть темнее, чем остальные части тени. Как вы понимаете, это довольно сложно, но заманчиво!

Каждый из трех типов источников характеризуется своим способом освещения. Точечный источник излучает свет как Солнце — одинаково во всех направлениях, из определенной точки. Источник направленного света излучает свет в одном направлении и не имеет начальной точки. С нашей позиции на Земле солнце выглядит направленным источником, потому что мы видим его свет, исходящий из одного направления, но не видим его в других направлениях. Наконец, существуют источники узконаправленного света, типа софитов: у них есть начальная точка, направление, их свет слабеет с расстоянием, ширину угла освещения вы назначаете сами.

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

Вот код — поместите его в метод createScene():

m_SceneMgr->setAmbientLight( ColourValue(0.35, 0.35, 0.35) );
m_SceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_ADDITIVE);
m_SunLight = m_SceneMgr->createLight("Sun");
m_SunLight->setType(Light::LT_DIRECTIONAL);
m_SunLight->setDiffuseColour(1.0, 1.0, 1.0);
m_SunLight->setSpecularColour(1.0, 1.0, 1.0);
m_SunLight->setDirection(Vector3(0, sin(m_SunY), sin(m_SunZ)));
m_MoonLight = m_SceneMgr->createLight("Moon");
m_MoonLight->setType(Light::LT_DIRECTIONAL);
m_MoonLight->setDiffuseColour(0.3, 0.3, 0.5);
m_MoonLight->setSpecularColour(0.0, 0.0, 0.0);
m_MoonLight->setDirection(Vector3(0, -sin(m_SunY), sin(m_SunZ)));

Привести луну и солнце в движение можно, отредактировав метод frameStarted(), чтобы метод setDirection() вызывался для каждого источника. Необходимо также изменить переменные m_SunY и m_SunX, заставив их медленно увеличиваться. Вставьте этот код в начало метода frameStarted():

m_SunLight->setDirection(Vector3(0, sin(m_SunY), sin(m_SunZ)));
m_MoonLight->setDirection(Vector3(0, -sin(m_SunY), -sin(m_SunZ)));
m_SunY += 0.001;
m_SunZ += 0.001;

Теперь вы должны увидеть, что здание отбрасывает тень.

Похождения бравого солдата Квейка

Вы помните, что я собирался строить «Тюдоровскую крепость», но пока что мы имеем только невинного вида домик на плоской траве. На крепость не похоже, правда? Сейчас мы это изменим, соорудив внутри заведомо неприветливую обстановку. На последних трех уроках мы играли в песочнице менеджера сцен Ogre для открытого ландшафта, но если наши персонажи намерены разгуливать по зданию, потребуется еще один менеджер сцены — BSP.

BSP означает binary space partition [двоичное разбиение пространства] и позволяет очень быстро загружать и обрабатывать закрытые пространства. Карты BSP используется во многих играх, главным образом в тех, что используют движок Quake, включая Jedi Knight, Soldier of Fortune, Half-life. Проблема с BSP состоит в том, что он не умеет хорошо обрабатывать открытые пространства (включая наш ландшафт), поэтому текущий менеджер сцены тоже придется оставить.

Добавление нового менеджера сцены вводит интересные осложнения в наш игровой движок. Во-первых, необходимо отредактировать файл resources.cfg, чтобы использовался файл карты Quake 3. Сотни карт доступны бесплатно через сеть, но на самом деле демо-версии Ogre уже поставляются с очень красивой картой Chiroptera (доступа для скачивания по адресу http://simland.planetquake.gamespy.com/pages/q3maps/chiroptera.htm), ею мы и воспользуемся.

Во-вторых, необходимо разделить методы createScene() и frameStarted() на CreateIndoorScene(), createOutdoorScene(), frameStartedInside(), frameStartedOutside(). Проще всего это сделать, переименовав createScene() и frameStarted(), например, как createOutdoorScene() и frameStartedOutside(), а затем создав заглушки для createIndoorScene() и frameStartedIndoor(). Также потребуется объявить новые методы в chad.h. Сделав это, добавьте строчку в chad.h в конце класса CChadGame:

int scenemanager;

Переменная будет показывать, снаружи мы или внутри. Теперь можно написать новый метод frameStarted() для автоматического вызова нужного «подметода», нечто вроде такого:

bool CChadGame::frameStarted(const FrameEvent& evt) {
switch (scenemanager) {
case ST_EXTERIOR_CLOSE:
return frameStartedOutside();
break;
case ST_INTERIOR:
return frameStartedInside();
break;
}
return true;
}

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

scenemanager = ST_EXTERIOR_CLOSE;

Метод frameStartedInside() новый, но ничего особенного не делает - в данный момент он должен представлять урезанную версию метода frameStartedOutside() и обрабатывать простой ввод от клавиатуры. Вот пример подобного кода:

bool CChadGame::frameStartedInside() {
m_InputReader->capture();
if(m_InputReader->isKeyDown(KC_ESCAPE)) return false;
Vector3 translateVector = Vector3::ZERO;
float playerspeed = m_Player->getSpeed();
if (m_InputReader->isKeyDown(KC_W)) translateVector.z =-playerspeed * 5;
if (m_InputReader->isKeyDown(KC_S)) translateVector.z =+playerspeed * 5;
if (m_InputReader->isKeyDown(KC_A)) translateVector.x =-playerspeed * 5;
if (m_InputReader->isKeyDown(KC_D)) translateVector.x =+playerspeed * 5;
if (m_InputReader->isKeyDown(KC_F1)) createIndoorScene();
if (m_InputReader->isKeyDown(KC_F2)) createOutdoorScene();
m_Camera->moveRelative(translateVector);
return true;
}

Вы заметите, что переменная playerspeed умножена на пять — дело в том, что карта Quake огромна, и прогулка с прежней скоростью превратилась бы в вечность. Если такое решение вы находите примитивным, попробуйте увеличить ландшафт, удалив вызов scale() для дома, а затем выберите значение скорости, пригодное везде.

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

void CChadGame::createIndoorScene() {
scenemanager = ST_INTERIOR;
if (m_SceneMgr != NULL) {
m_Ogre->getAutoCreatedWindow()->removeAllViewports();
m_SceneMgr->destroyAllCameras();
}
m_SceneMgr = m_Ogre->createSceneManager("BspSceneManager");
ResourceGroupManager::getSingleton().linkWorldGeometryToResourceGroup(
ResourceGroupManager::getSingleton().getWorldResourceGroupName(), "maps/chiropteradm.bsp", m_SceneMgr);
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
ResourceGroupManager::getSingleton().clearResourceGroup(ResourceGroupManager::getSingleton().getWorldResourceGroupName());
ResourceGroupManager::getSingleton().loadResourceGroup(ResourceGroupManager::getSingleton().getWorldResourceGroupName(), false, true);
m_Camera = m_SceneMgr->createCamera("Player Cam");
m_Camera->setNearClipDistance(4);
m_Camera->setFarClipDistance(4000);
m_Viewport = m_Ogre->getAutoCreatedWindow()->addViewport(m_Camera);
m_Viewport->setBackgroundColour(ColourValue(0, 0, 0));
ViewPoint vp = m_SceneMgr->getSuggestedViewpoint(true);
m_Camera->setPosition(vp.position);
m_Camera->pitch(Degree(90));
m_Camera->rotate(vp.orientation);
m_Camera->setFixedYawAxis(true, Vector3::UNIT_Z);
}

Установка значений «ближней» и «дальней» дистанций обрезания необходима, потому что наша камера работает внутри замкнутой области, и нужно фокусироваться на вещах, расположенных близко к камере. Метод getSuggestedViewport() считывает произвольную начальную позицию игрока на карте и устанавливает камеру в эту точку. Нам необходимо установить оси камеры pitch и yaw потому, что Quake использует для плоскости пола координаты Х и Y, а Z — для высоты, а мы обычно используем для пола X и Z и Y — для высоты.

Мы еще не закончили: понадобится добавить две строки в начало метода createOutdoorScene(), чтобы Ogre обновлял все свои ресурсы при загрузке сцены в открытом пространстве. Без них закрытая сцена обновит ресурсы и выгрузит все ресурсы открытой сцены. Итак, добавляем две строки:

ResourceGroupManager::getSingleton().clearResourceGroup(ResourceGroupManager::getSingleton().getWorldResourceGroupName());
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

Наконец, проверим, что вызов createScene() в конструкторе CChadGame() (который находится в начале chad.cpp) заменен на createOutdoorScene(). Ну вот и все: запустите make, затем chad. Посмотрим, заметите ли вы разницу….

Сложный вопрос

ОК, разницы нет — по крайней мере, с точки зрения игрока. Это потому, что мы написали код обработки для закрытой сцены, но не написали кода, загружающего эту сцену. Вы вольны написать код, способный обнаруживать, что игрок входит в дверь дома, а мы напишем более простую (лишь бы работала) «клавишную реализацию переключения сцен», которую можно использовать в любом месте ландшафта.

У нас уже есть функции обработки клавиатуры frameStaretd*(), поэтому остается добавить в них поддержку двух дополнительных клавиш: F1 (для загрузки закрытой сцены) и F2 (для загрузки открытой сцены). Код, который загружает и выгружает ресурсы, камеры и области просмотра, расположен в методах create*Scene(), поэтому о них беспокоиться не надо. Все, что нам надо сделать, это вызвать требуемый метод create*Scene(), например, так:

if (m_InputReader->isKeyDown(KC_F1)) createIndoorScene();
if (m_InputReader->isKeyDown(KC_F2)) createOutdoorScene();

Поместите эти две строчки вместе с остальными вызовами isKeyDown(), перезапустите make, затем саму игру. На этот раз вы должны попасть на карту Quake и исследовать ваш новый интерьер, просто нажав клавишу F1 и пару секунд подождав, пока загрузятся необходимые ресурсы Ogre.

Мы рассмотрели в этом руководстве много нового. Труднее всего уместить в голове переход от одного менеджера сцены к нескольким; все остальное сравнительно просто! Я надеюсь, что вам понравилось, как легко Ogre создает освещение и тени и работает с уровнями BSP, хотя покамест некоторые недостатки игры могут и раздражать — отсутствие обнаружения столкновений, плохой ввод, небо, на котором не сказывается освещение, и так далее. Часть недостатков вы можете исправить сами, ведь это руководство написано для того, чтобы игру программировали вы, а не я. Но с остальными мы разберемся вместе. До следующего раза!

Персональные инструменты
купить
подписаться
Яндекс.Метрика