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

LXF86:Учебники:Ogre

Материал из Linuxformat
(Различия между версиями)
Перейти к: навигация, поиск
м (Перенаправление на LXF86:Ogre)
 
(не показаны 2 промежуточные версии 2 участников)
Строка 1: Строка 1:
== Ogre: Лазеры и звук ==
+
#REDIRECT [[LXF86:Ogre]]
 
+
''ЧАСТЬ 5: Последний урок в данной серии – музыка для ушей '''Пола Хадсона''': под такую сподручно убивать роботов.''
+
 
+
На данном этапе наша игра содержит все базовые элементы стрелялки от первого лица, но имеет легкий недостаток: п
+
одстрелить-то вы никого и не можете. Пожалуй, это скорее тяжелый недостаток, если учесть, что Висельник Чед для стрельбы и задуман. Не хватает также звука и музыки, да и прицела оружия, чтоб видеть, куда мы стреляем. А фанаты С++, наверно, заметили, что отсутствует какое-либо высвобождение памяти.
+
 
+
Изящно завершим Висельника Чеда: реализуем все эти элементы на следующих четырех страницах, и притом запросто – обещаю!
+
 
+
=== Включаем громкость ===
+
 
+
Имя Ogre не дает забыть о сильных сторонах программы: это акроним, означающий Объектно-ориентированный Графический Движок Рендеринга [Object-Oriented Graphics Rendering Engine]. Звук – как для эффектов, так и фоновый – не принимается в расчет и, согласно разработчикам Ogre, приниматься не будет. Но это не проблема, благодаря библиотеке SDL и ее расширению SDL_Mixer: вместе они позаботились о поддержке аудио. Если вы следили за нашими уроками с LXF82, то уже установили библиотеки libsdl-devel и libsdl-mixer-devel; а те, кто этот номер пропустил, пусть начнут с их установки, иначе код данного урока работать не будет. Прежде всего, надо изменить файл chad.h, объявив в нем звуковые файлы стрельбы (я использую laser1.wav) и музыкального фона (tipperary.mp3). В SDL-терминах это Mix_Chunk и Mix_Music соответственно, поэтому добавьте две строки в конец класса CChadGame:
+
Mix_Chunk* m_MixFire;
+
Mix_Music* m_Music;
+
 
+
Загрузка нашего аудиоматериала осуществляется в файле chad. cpp, в методе initialise(). В конец этого метода (т
+
.е. после установки m_SceneMgr в NULL), добавьте следующие четыре строки:
+
SDL_Init(SDL_INIT_AUDIO);
+
Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 2048);
+
m_MixFire = Mix_LoadWAV(“laser1.wav”);
+
m_Music = Mix_LoadMUS(“tipperary.mp3”);
+
 
+
Первая строка инициирует поддержку звука, потому она и идет первой. Функция SDL_Init() сообщает SDL, какие части вы хотите использовать – графику, звук, ввод, таймеры и т.д., обычно через передачу списка констант, объединенных оператором ИЛИ – например, SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_CDROM. Для инициализации всех доступных в библиотеке подсистем (это изрядная расточительность, если вы не намерены все их использовать!), просто укажите SDL_INIT_EVERYTHING. Инициализировав звуковую подсистему SDL, можно открывать звуковое устройство. Это делает функция Mix_OpenAudio(): у нее четыре параметра, определяющих свойства звука. Первый параметр – частота дискретизации: 44100 соответствует CD-качеству; чтобы игра лучше работала на старых компьютерах, попробуйте уменьшить ее до 22050. Второй параметр – формат сэмпла (AUDIO_S16SYS означает 16 бит, какой байт старший – определяется системой), третий – количество каналов (1 для моно, 2 для стерео), а четвертый определяет размер буфера для проигрывания звука. Вам эти параметры ни о чем не говорят? Можете их проигнорировать. Просто скопируйте и вставьте приведенную мной строку кода и больше о ней не вспоминайте. Магия!
+
 
+
=== Запускаем звуковые файлы ===
+
 
+
Настроив звуковую систему, мы, наконец, можем заказывать наши звук и музыку. SDL_Mixer берет на себя их загрузку, а вам остается сделать два вызова функций Mix_LoadWAV() и Mix_LoadMSU(). Они принимают имя загружаемого файла и автоматически обрабатывают множество популярных форматов – WAV, MP3, OGG, MID и MOD, но если ваш дистрибутив не поддерживает формат MP3, то SDL, скорее всего, не сможет его проиграть. Кому интересно, общедоступную запись tipperary.mp3 я нашел в Сети – она совершенно не подходит для игры [«Путь далекий до Типперери» – популярная песенка английских солдат времен I Мировой войны, – прим. ред.], поэтому вы уж сами подберите нужный файл! Чтобы покончить с поддержкой звука, остается еще два шага. Добавьте в методе frameStarted() следующие три строки кода:
+
if (!Mix_PlayingMusic()) {
+
  Mix_PlayMusic(m_Music, 0);
+
}
+
 
+
Я не собираюсь вас унижать, объясняя этот код, кроме 0 в конце: это число повторов нашей мелодии [0 значит, что она будет проиграна всего один раз, без повтора, – прим. ред.]. Добавление звука лазера потребует немного мозгов, поскольку потребуется определить метод mousePressed(). В настоящий момент он пуст и сидит в chad.h. Заменим «заглушку» в chad.h на прототип и напишем реализацию этого метода в chad.cpp (чтобы лазер зазвучал). В chad.h, превратим строку....
+
void mousePressed(MouseEvent* e) { }
+
 
+
... в...
+
 
+
void mousePressed(MouseEvent* e);
+
 
+
Тело этого метода надо поместить где-то в файле chad.cpp:
+
void CChadGame::mousePressed(MouseEvent* e) {
+
  Mix_PlayChannel(-1, m_MixFire, 0);
+
}
+
 
+
Звук лазера теперь будет раздаваться при каждом нажатии кнопки мыши – не сногсшибательно, но начало хорошее! Можете скомпилировать свой код и насладиться звуками лазера.
+
 
+
=== Прицел ===
+
 
+
Если вы не снайпер сразу после дембеля, то вряд ли поражение цели на дальней дистанции покажется вам несложным. Для упрощения этой задачи многие игры содержат на экране небольшой прицел. Добавим и мы прицел в виде точки в игру Висельник Чед. Для этого необходимо проделать три шага: 1 Создать материал, который даст имя файлу. 2 Создать слой, который использует материал, и позиционировать его на экране. 3 Отобразить слой. Первые два пункта реализуются через систему скриптов Ogre; но для последнего шага придется написать код на С++. Начнем с материала. Сохраните следующий ‘код’ как target.material:
+
material Chad/TargetSights
+
{
+
            technique
+
            {
+
                      pass
+
                      {
+
                            lighting off
+
                            scene_blend alpha_blend
+
                            texture_unit
+
                            {
+
                                        texture terrain_detail.jpg
+
                            }
+
                      }
+
            }
+
}
+
 
+
Заметили? Я использовал для прицела текстуру terrain_detail.jpg, но только потому, что прицел очень мал: игроки увидят лишь небольшую серую точку. Вы можете взять свою картинку, но пока сойдет и эта. Следующий шаг – определить слой, который принимает материал и помещает его на экранной панели. Затем можно пристроить эту панель на экране, используя координату относительно левого верхнего угла, а также ширину и высоту. В любом случае, вот код – сохраните его в файл target.overlay:
+
chadtarget
+
{
+
            zorder 650
+
            container Panel(chadsight)
+
            {
+
                      metrics_mode relative
+
                      left 0.495
+
                      top 0.495
+
              width 0.004
+
              height 0.007
+
              transparent false
+
              material Chad/
+
TargetSights
+
            }
+
}
+
 
+
Параметр zorder определяет, где панель отобразится на экране, в терминах глубины, то есть мы можем (если пожелаем) задать способ расположения элементов по слоям. В Ogre его максимальное значение 650 (прицел на вершине стека). Последний шаг – создание слоя, он займет всего две строки. Добавьте такой код в конец метода createOutdoorScene():
+
Overlay *TargetSight = (Overlay*)OverlayManager::getSingleton().
+
getByName(“chadtarget”);
+
TargetSight->show();
+
 
+
Код загружает слой с именем, определенным в target.overlay, а затем отображает его. Не надо беспокоиться о потере указателя на слой – Ogre автоматически удерживает его посреди экрана, как определено в файле. Наши три шага проделаны; запустите игру и загляните в прицел. Пусть программировать было скучновато, но зато как удобно теперь целиться!
+
 
+
=== Стреляем на поражение ===
+
 
+
Настает главное событие этого урока: отстрел роботов, которые резвились в прошлом номере. Правду сказать, я не особо хотел отягчать насилием Висельника Чеда, но Ребекка – спец по насилию в нашей команде – отказалась плодить опечатки, пока мы не разнесем когонибудь на куски. Пусть будет так. У нас уже есть метод mousePressed() для проигрывания звука лазера, поэтому код для стрельбы подойдет именно сюда. Стрелять будем так: с позиции камеры проводим луч, аналогично тому, как мы делали для определения высоты игрока над уровнем земли. Это непростая геометрическая задача, но, к счастью, Ogre все делает сам, одним методом: getCameraToViewportRay(), который преобразует позицию на экране в позицию в нашем мире и позволяет пустить луч из положения камеры. При необходимости выбирать объекты мышью, можно было бы использовать указатель на объект-событие, передаваемый методу mousePressed(), но мы хотим просто пустить луч через центр экрана, и поэтому используем для координат X и Y значения 0.5. Вот код улучшенного метода mousePressed():
+
void CChadGame::mousePressed(MouseEvent* e) {
+
          Mix_PlayChannel(-1, m_MixFire, 0);
+
          Ray mouseray = m_Camera->getCameraToViewportRay(0.5,
+
  0.5);
+
          RaySceneQuery* scenequery = m_SceneMgr
+
->createRayQuery(Ray());
+
          scenequery->setRay(mouseray);
+
          RaySceneQueryResult &result = scenequery->execute();
+
          if (!result.empty()) {
+
              for (unsigned int i = 0; i < result.size(); ++i) {
+
              RaySceneQueryResultEntry &re = result[i];
+
              if (re.movable && re.movable->getMovableType() ==
+
“Entity”) {
+
                          Entity *ent = (Entity*)(re.movable);
+
                          String name = ent->getName();
+
                          if (name == “water”) continue; // игнорируем воду
+
                          for (unsigned int j = 0; j < Enemies.size(); ++j) {
+
                                        if (Enemies[j]->m_EnemyName ==
+
  name) {
+
                                                      Enemies[j]->Hit();
+
                                                      return;
+
                                                      }
+
                                        }
+
                          }
+
                  }
+
          }
+
  }
+
 
+
Послав луч, я прошелся в цикле по откликам в поисках сущностей (в отличие от
+
элементов ландшафта), а затем отсек водную поверхность. Остаются только роботы; получим имя жертвы и найдем в
+
списке роботов соответствующий объект, а затем вызовем его метод Hit(). Те, кто следил за нашими уроками с самого начала, возможно, воскликнет: у наших врагов нет ни имени, ни метода Hit()! Исправим это: откройте файл chadenemy.h и добавьте эти строки до объявления m_Speed:
+
char m_EnemyName[32];
+
bool m_IsDead
+
 
+
Теперь добавьте следующие две строчки после метода Update():
+
void SetAnimation(String animation, bool loop);
+
void Hit();
+
 
+
Метод SetAnimation() я вставил, потому что мне было тошно писать три строчки кода для выполнения одной простой вещи. Можете игнорировать его, если хотите.
+
 
+
Мы уже устанавливали имена врагов в конструкторе (файл chadenemy.cpp), но использовали временную локальную пере
+
менную. Теперь, когда у нас есть m_EnemyName, мы можем хранить ее там, чтобы найти правильный объект сцены, поп
+
ав в робота. Просто замените следующие три строки кода…
+
char enemyname[32];
+
sprintf(enemyname, “Robot %d”, ++EnemyNum);
+
m_Entity = m_SceneMgr->createEntity(enemyname, “robot.
+
mesh”);
+
 
+
... на следующие две...
+
sprintf(m_EnemyName, “Robot %d”, ++EnemyNum);
+
m_Entity = m_SceneMgr->createEntity(m_EnemyName, “robot.
+
mesh”);
+
 
+
Теперь нужно написать метод Hit(), изменить анимацию робота и
+
установить переменную m_IsDead в значение true, например, так:
+
void CChadEnemy::Hit() {
+
            if (!m_IsDead) {
+
                      m_AnimationState->setEnabled(false);
+
                      SetAnimation(“Die”, false);
+
                      m_IsDead = true;
+
            }
+
}
+
 
+
 
+
----
+
 
+
=== Наш эксперт ===
+
Пол Хадсон
+
написал три книги по Linux и одну по PHP, он также поддерживает на SourceForge два проекта на Mono по лицензии
+
GPL. Пол любит Emacs.
+

Текущая версия на 17:32, 24 марта 2008

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