LXF85:Ogre
Yaleks (обсуждение | вклад) (Новая: {{Цикл/Ogre}} == Ogre: Добавим вражьих роботов-умников == ''ЧАСТЬ 4: Наскучило бродить одному по бескрайним про...) |
Yaleks (обсуждение | вклад) |
||
(не показаны 2 промежуточные версии 1 участника) | |||
Строка 1: | Строка 1: | ||
{{Цикл/Ogre}} | {{Цикл/Ogre}} | ||
+ | |||
== Ogre: Добавим вражьих роботов-умников == | == Ogre: Добавим вражьих роботов-умников == | ||
− | ''ЧАСТЬ 4: Наскучило бродить одному по бескрайним просторам? '''Пол Хадсон''' подскажет вам, как добавить плохих | + | ''ЧАСТЬ 4: Наскучило бродить одному по бескрайним просторам? '''Пол Хадсон''' подскажет вам, как добавить плохих ребят…'' |
Солнце встает, освещая старый бревенчатый домик, а вода | Солнце встает, освещая старый бревенчатый домик, а вода | ||
− | плещется у краев покатого | + | плещется у краев покатого ландшафта — наступает новый |
день в игре Висельник Чед. За последние три урока мы создали нашему игроку живописный остров, где он может порезвиться. | день в игре Висельник Чед. За последние три урока мы создали нашему игроку живописный остров, где он может порезвиться. | ||
− | Логичный следующий | + | Логичный следующий шаг — населить остров роботами-убийцами. Как, |
вы в этом не уверены? Тогда пришлите нам запрос на создание учебника по игре «Сажаем цветочки», и мы посмотрим, что можно сделать, а | вы в этом не уверены? Тогда пришлите нам запрос на создание учебника по игре «Сажаем цветочки», и мы посмотрим, что можно сделать, а | ||
на данном уроке займемся роботами. Сотней здоровенных, вооруженных до зубов, злобных роботов. Да-с. | на данном уроке займемся роботами. Сотней здоровенных, вооруженных до зубов, злобных роботов. Да-с. | ||
Строка 16: | Строка 17: | ||
На сей раз мы создадим новый класс, отслеживающий перемещение роботов. Я не большой любитель объектно-ориентированного | На сей раз мы создадим новый класс, отслеживающий перемещение роботов. Я не большой любитель объектно-ориентированного | ||
− | + | программирования — обычно мои классы превращаются в штуки типа | |
struct; и я, скорее всего, не один такой. Кому не по душе моя манера | struct; и я, скорее всего, не один такой. Кому не по душе моя манера | ||
делать все переменные публичными, пишите письма на имя /dev/null. | делать все переменные публичными, пишите письма на имя /dev/null. | ||
+ | {{Врезка | ||
+ | |Заголовок=Кватернионы и вы | ||
+ | |Содержание=Рысканье, тангаж и крен (РТК) – известные как угловое вращение | ||
+ | Эйлера – так люди представляют себе перемещение в пространстве. Если у вас есть игрушечный самолетик и пара шампуров, то | ||
+ | вот как понять эти характеристики: | ||
+ | * Рысканье – глядя на самолет сверху вниз, проткните его через крышу и пол: он сможет вращаться только влево и вправо. | ||
+ | * Тангаж – глядя на самолет сбоку, проткните его с одного борта до другого: он сможет вращаться только вверх и вниз. | ||
+ | * Крен – глядя на самолет спереди, проткните его от носа до хвоста: он сможет вращаться только вправо или влево; учтите, это не то вращение, что при рысканье! | ||
+ | |||
+ | [[Изображение:Img 85 87 2.png|thumb|При приближении зеленой рамки к горизонтальной плоскости синяя рамка начинает вести себя как красная, и мы теряем степень свободы.]] | ||
+ | Проблема традиционного РТК-метода работы с 3D-пространством (кроме того, что жалко дырявить самолетик) – здесь иногда | ||
+ | случается складывание плоскостей. Такое происходит, когда | ||
+ | какой-либо поворот кратен 90 градусам: в результате на вид две | ||
+ | степени свободы превращаются в одну. Вам будет легче осознать, | ||
+ | в чем дело, если вы взглянете на рисунок справа: внешняя рамка | ||
+ | представляет тангаж, средняя – крен, а внутренняя – рысканье. | ||
+ | Если средняя рамка провернется еще влево, то есть попадет в одну | ||
+ | плоскость с внешней, то внутренняя рамка будет функционально | ||
+ | аналогична внешней рамке, и нам покажется, что степень свободы | ||
+ | потеряна. | ||
+ | |||
+ | Кватернионы решают эту проблему, определяя вектор (значения | ||
+ | X,Y,Z) плюс угол поворота вокруг этого вектора. Поэтому вместо | ||
+ | того, чтобы протыкать наш самолет в трех местах, вращая по | ||
+ | отдельности, мы протыкаем его произвольным образом. Такой | ||
+ | способ позволяет избегать слипания рамок и проводить гладкую | ||
+ | интерполяцию между точками – идеально при полетах с кинокамерой. | ||
+ | |Ширина=350px}} | ||
В процессе создания роботов вы познакомитесь с кватернионами | В процессе создания роботов вы познакомитесь с кватернионами | ||
(которые, наряду с ‘shazbat’, являются моим любимым словом), анимацией и Стандартной библиотекой шаблонов С++ (Standard Template | (которые, наряду с ‘shazbat’, являются моим любимым словом), анимацией и Стандартной библиотекой шаблонов С++ (Standard Template | ||
Library или STL). Если вы раньше не использовали STL, вам вполне | Library или STL). Если вы раньше не использовали STL, вам вполне | ||
простительно решить, что это плод труда двух комитетов из разных | простительно решить, что это плод труда двух комитетов из разных | ||
− | стран, говорящих на разных | + | стран, говорящих на разных языках — но, отстранившись от мелочей, |
вы поймете, как все просто. | вы поймете, как все просто. | ||
Строка 32: | Строка 61: | ||
Нам требуется, чтобы у робота была своя сущность (каркас робота) и | Нам требуется, чтобы у робота была своя сущность (каркас робота) и | ||
узел сцены, чтобы мы могли помещать его в сцену. Вспомните, как мы | узел сцены, чтобы мы могли помещать его в сцену. Вспомните, как мы | ||
− | передвигали игрока (LXF83): используя луч для нахождения высоты | + | передвигали игрока ([[LXF83:Ogre|LXF83]]): используя луч для нахождения высоты |
игрока над ландшафтом. Надо придумать что-то подобное для каждого из наших врагов, поэтому вместо указания позиций в chad.cpp применим метод SetPos(). | игрока над ландшафтом. Надо придумать что-то подобное для каждого из наших врагов, поэтому вместо указания позиций в chad.cpp применим метод SetPos(). | ||
Строка 81: | Строка 110: | ||
=== Стандартная библиотека шаблонов === | === Стандартная библиотека шаблонов === | ||
+ | [[Изображение:Img 85 87 1.png|thumb|250px|Ogre поставляется со всеми мыслимыми моделями – от греческих статуй до ниндзя, но у этого типа самые классные пушки!]] | ||
Теперь у нас хватает кода, чтобы населить остров врагами-роботами, | Теперь у нас хватает кода, чтобы населить остров врагами-роботами, | ||
но сначала надо придумать, как их хранить. Метод должен быть гибким: незачем объявлять переменную для каждого робота или заводить | но сначала надо придумать, как их хранить. Метод должен быть гибким: незачем объявлять переменную для каждого робота или заводить | ||
Строка 86: | Строка 116: | ||
запросу. Решение состоит в использовании STL: это коллекция стандартных абстрактных типов данных для C++. Пусть слово «абстрактные» вас не пугает: STL чрезвычайно полезна, а ее типы данных обычно легко представить. | запросу. Решение состоит в использовании STL: это коллекция стандартных абстрактных типов данных для C++. Пусть слово «абстрактные» вас не пугает: STL чрезвычайно полезна, а ее типы данных обычно легко представить. | ||
− | Для управления врагами нам потребуется тип данных «вектор» | + | Для управления врагами нам потребуется тип данных «вектор» - |
массив некоторых величин, в котором нас интересует только их | массив некоторых величин, в котором нас интересует только их | ||
значение. Добавление «вражеского» вектора потребует сделать два | значение. Добавление «вражеского» вектора потребует сделать два | ||
Строка 110: | Строка 140: | ||
врагов в вектор Enemies. Если вашей системе больше трех лет от роду, | врагов в вектор Enemies. Если вашей системе больше трех лет от роду, | ||
врагов лучше взять поменьше. | врагов лучше взять поменьше. | ||
− | Вот и все, что потребовалось для добавления | + | Вот и все, что потребовалось для добавления роботов — теперь |
скомпилируйте игру и запустите ее! | скомпилируйте игру и запустите ее! | ||
=== Двигаемся дальше === | === Двигаемся дальше === | ||
+ | {{Врезка | ||
+ | |Заголовок=Скорая помощь | ||
+ | |Содержание=Мы привыкли | ||
+ | перемещать | ||
+ | камеру, но в этот | ||
+ | раз я прикрепил ее | ||
+ | к собственному узлу | ||
+ | сцены и передвигал | ||
+ | его. Такой ход | ||
+ | позволит в будущем | ||
+ | проделывать | ||
+ | интересные | ||
+ | вещи, например, | ||
+ | вызывать метод | ||
+ | lookAt() для других | ||
+ | узлов, чтобы они | ||
+ | взглянули в камеру. | ||
+ | |Ширина=200px}} | ||
Наши роботы стоят столбом, напоминая батарейки из рекламы Duracell, | Наши роботы стоят столбом, напоминая батарейки из рекламы Duracell, | ||
которые демонстрируют, что другие уже рухнули. Попробуем их оживить: пусть выберут какой-то пункт назначения на карте и отправятся | которые демонстрируют, что другие уже рухнули. Попробуем их оживить: пусть выберут какой-то пункт назначения на карте и отправятся | ||
Строка 132: | Строка 180: | ||
void Update(Real time); | void Update(Real time); | ||
</source> | </source> | ||
+ | {{Врезка | ||
+ | |Заголовок=Скорая помощь | ||
+ | |Содержание=Если вы | ||
+ | обнаружили, | ||
+ | что анимация не | ||
+ | работает, проверьте, | ||
+ | вызывается ли | ||
+ | метод addTime() | ||
+ | для каждого робота | ||
+ | при вызове его | ||
+ | метода Update(). | ||
+ | Без этого анимация | ||
+ | обновляться | ||
+ | не будет: будет | ||
+ | проигрываться | ||
+ | один и тот же кадр. | ||
+ | |Ширина=200px}} | ||
Мы будем вызывать метод Update() для каждого робота каждый | Мы будем вызывать метод Update() для каждого робота каждый | ||
раз, как только начнется кадр, поэтому робот сможет перемещать сам | раз, как только начнется кадр, поэтому робот сможет перемещать сам | ||
Строка 174: | Строка 239: | ||
} | } | ||
</source> | </source> | ||
+ | [[Изображение:Img 85 88 1.jpg|thumb|250px|На прошлом уроке мы поработали неплохо: наши орды злодеев отбрасывают при движении реалистичные тени.]] | ||
Здесь STL применяется в большей степени, и наш код напоминает | Здесь STL применяется в большей степени, и наш код напоминает | ||
синтаксическую окрошку. На самом деле этот цикл проходит от начала до конца вектора, используя STL-итератор. Можно, конечно, получить прямой доступ к элементам вектора через индексы, но итераторы более предпочтительны. Для каждого врага в нашем векторе мы | синтаксическую окрошку. На самом деле этот цикл проходит от начала до конца вектора, используя STL-итератор. Можно, конечно, получить прямой доступ к элементам вектора через индексы, но итераторы более предпочтительны. Для каждого врага в нашем векторе мы | ||
вызываем метод Update() и посылаем отрезок времени, прошедший с | вызываем метод Update() и посылаем отрезок времени, прошедший с | ||
прошлого кадра. Именно тут наши роботы должны проделать всё, что | прошлого кадра. Именно тут наши роботы должны проделать всё, что | ||
− | им | + | им полагается — сейчас мы просто заставим их двигаться. |
Пора написать сам метод Update(). Вставьте следующий код в конец | Пора написать сам метод Update(). Вставьте следующий код в конец | ||
Строка 217: | Строка 283: | ||
Мы можем рассчитать длину вектора, вызвав метод normalise(), | Мы можем рассчитать длину вектора, вызвав метод normalise(), | ||
− | который вернет нормализованный | + | который вернет нормализованный вектор — имеющий то же направление, но длина его равна 1. Штука хорошая, но на самом-то деле нас |
интересует значение длины исходного вектора, которое также возвращается методом normalise и в нашем коде является расстоянием | интересует значение длины исходного вектора, которое также возвращается методом normalise и в нашем коде является расстоянием | ||
от робота до точки назначения. Сохраним это значение в переменной | от робота до точки назначения. Сохраним это значение в переменной | ||
dest. | dest. | ||
− | + | Теперь — важный момент: если расстояние до точки назначения | |
короче, чем расстояние, на которое собирается переместиться робот | короче, чем расстояние, на которое собирается переместиться робот | ||
(его скорость, помноженная на время, прошедшее с прошлого кадра), | (его скорость, помноженная на время, прошедшее с прошлого кадра), | ||
Строка 233: | Строка 299: | ||
нормализован, поэтому все будет работать. | нормализован, поэтому все будет работать. | ||
− | Вот и | + | Вот и все — запустите новый код и наслаждайтесь реалистичностью |
перемещений ваших роботов по ландшафту! | перемещений ваших роботов по ландшафту! | ||
=== Идем верным путем === | === Идем верным путем === | ||
− | Ну, пожалуй, | + | [[Изображение:Img 85 89 1.png|250px|thumb|Здесь всего три кадра, но можно видеть, что наш враг размахивает |
+ | руками в такт шагам, нечувствительный ко всему на свете.]] | ||
+ | Ну, пожалуй, «реалистичность» — слишком сильно сказано: на самом | ||
деле роботы просто скользят, по причине отсутствия кода для анимации. Да и вообще, нет ничего, обуславливающего должное направление их перемещения. Давайте это исправим! | деле роботы просто скользят, по причине отсутствия кода для анимации. Да и вообще, нет ничего, обуславливающего должное направление их перемещения. Давайте это исправим! | ||
Строка 259: | Строка 327: | ||
интеллекта: если робот приблизится к игроку на определенное расстояние, пусть остановится и посмотрит на игрока. По умолчанию такая | интеллекта: если робот приблизится к игроку на определенное расстояние, пусть остановится и посмотрит на игрока. По умолчанию такая | ||
опция установлена для каждого робота; вы скоро узнаете, зачем. | опция установлена для каждого робота; вы скоро узнаете, зачем. | ||
− | Осталось изменить метод Update(). Первое, что необходимо | + | |
+ | {{Врезка | ||
+ | |Заголовок=Скорая помощь | ||
+ | |Содержание=У нашего робота | ||
+ | имеются и | ||
+ | другие анимации, | ||
+ | например, ‘Shoot’ | ||
+ | [Стрелять] и | ||
+ | ‘Die’ [Умирать]. | ||
+ | Их можно | ||
+ | использовать | ||
+ | аналогично | ||
+ | анимациям ‘Idle’ | ||
+ | [Безделье] и ‘Walk’ | ||
+ | [Ходьба], вот и | ||
+ | попробуйте их! | ||
+ | |Ширина=150px}} | ||
+ | Осталось изменить метод Update(). Первое, что необходимо сделать — обновить анимацию робота, этим займется метод addTime() | ||
нашей переменной m_AnimationState(). Он принимает в качестве параметра время, прошедшее с прошлого кадра, которое мы уже знаем, | нашей переменной m_AnimationState(). Он принимает в качестве параметра время, прошедшее с прошлого кадра, которое мы уже знаем, | ||
поэтому поместите следующую строку в начале метода Update(): | поэтому поместите следующую строку в начале метода Update(): | ||
Строка 299: | Строка 384: | ||
} | } | ||
</source> | </source> | ||
+ | {{Врезка | ||
+ | |Заголовок=Домашнее задание | ||
+ | |Содержание= | ||
+ | * Назначьте каждому роботу персональную скорость. | ||
+ | * Ваши роботы идут в некотором направлении и смотрят на игрока, когда он в зоне досягаемости. Теперь заставьте их ходить за игроком по пятам! | ||
+ | * Более опытные программисты могут попробовать выставить направление следующего робота по предыдущему, а первый робот выбирает произвольное направление. | ||
+ | |Ширина=300px}} | ||
Итак, если робот невдалеке от игрока, мы заставляем его взглянуть, | Итак, если робот невдалеке от игрока, мы заставляем его взглянуть, | ||
если только он уже не глядит (чтобы избежать лишних вызовов функции). Задача заставить робота смотреть на игрока представляет собой | если только он уже не глядит (чтобы избежать лишних вызовов функции). Задача заставить робота смотреть на игрока представляет собой | ||
Строка 315: | Строка 407: | ||
Лимит на код в этом уроке исчерпан. Прокрутите свою игру: мы | Лимит на код в этом уроке исчерпан. Прокрутите свою игру: мы | ||
− | добавили врагов, передвижение, анимацию и простенький искусственный | + | добавили врагов, передвижение, анимацию и простенький искусственный интеллект — не так уж плохо для одного урока! |
---- | ---- | ||
<references /> | <references /> |
Текущая версия на 20:56, 30 ноября 2008
|
|
|
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
Содержание |
[править] Ogre: Добавим вражьих роботов-умников
ЧАСТЬ 4: Наскучило бродить одному по бескрайним просторам? Пол Хадсон подскажет вам, как добавить плохих ребят…
Солнце встает, освещая старый бревенчатый домик, а вода плещется у краев покатого ландшафта — наступает новый день в игре Висельник Чед. За последние три урока мы создали нашему игроку живописный остров, где он может порезвиться. Логичный следующий шаг — населить остров роботами-убийцами. Как, вы в этом не уверены? Тогда пришлите нам запрос на создание учебника по игре «Сажаем цветочки», и мы посмотрим, что можно сделать, а на данном уроке займемся роботами. Сотней здоровенных, вооруженных до зубов, злобных роботов. Да-с.
Наши роботы будут первым шажком на пути к искусственному интеллекту (ИИ), именно здесь и начинается настоящая потеха: неважно, как Ogre работает с 3D-графикой, сам по себе он нечеловечески скучен. Все, что выходит за рамки влияния Ogre, придется писать самим. Поверьте, это забавно!
На сей раз мы создадим новый класс, отслеживающий перемещение роботов. Я не большой любитель объектно-ориентированного программирования — обычно мои классы превращаются в штуки типа struct; и я, скорее всего, не один такой. Кому не по душе моя манера делать все переменные публичными, пишите письма на имя /dev/null.
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
В процессе создания роботов вы познакомитесь с кватернионами (которые, наряду с ‘shazbat’, являются моим любимым словом), анимацией и Стандартной библиотекой шаблонов С++ (Standard Template Library или STL). Если вы раньше не использовали STL, вам вполне простительно решить, что это плод труда двух комитетов из разных стран, говорящих на разных языках — но, отстранившись от мелочей, вы поймете, как все просто.
Наши враги будут управляться специальным классом, который я назову CChadEnemy, так что создайте файлы chademeny.h и chadenemy. cpp (да позаботьтесь о включении файла chadenemy.cpp в Makefile). Нам требуется, чтобы у робота была своя сущность (каркас робота) и узел сцены, чтобы мы могли помещать его в сцену. Вспомните, как мы передвигали игрока (LXF83): используя луч для нахождения высоты игрока над ландшафтом. Надо придумать что-то подобное для каждого из наших врагов, поэтому вместо указания позиций в chad.cpp применим метод SetPos().
Вот файл chad.h:
#include "Ogre." #include "OgreFrameListener.h" #include "OgreEventListeners.h" #include "OgreKeyEvent.h" using namespace Ogre; class CChadEnemy { public: SceneManager* m_SceneMgr; Entity* m_Entity; SceneNode* m_Node; int m_Speed; CChadEnemy(SceneManager* scenemgr); void SetPos(Vector3 dest); };
Каждый враг создается своим конструктором, CChadEnemy(). В нем будет происходить загрузка каркаса, создание узла сцены, затем добавление в менеджер сцены (вы заметили указатель на менеджер сцены в chad.h?). Каркас робота предоставляется Ogre и должен находится в вашем каталоге с медиа-ресурсами, но мы уменьшим размер робота вчетверо, вот этот код:
CChadEnemy::CChadEnemy(SceneManager* scenemgr) { m_SceneMgr = scenemgr; static int EnemyNum = 0; char enemyname[32]; sprintf (enemyname, "Robot %d", ++EnemyNum); m_Entity = m_SceneMgr->createEntity(enemyname,"robot.mesh"); m_Node = m_SceneMgr->getRootSceneNode()->createChildSceneNode(); m_Node->attachObject(m_Entity); m_Node->scale(0.25,0.25,0.25); m_Speed = 5; }
Строки с EnemyNum, enemyname и sprintf() раздражают своим уродством, но для Ogre это в порядке вещей. Проблема здесь в том, что каждой загружаемой сущности требуется дать уникальное имя, а достичь этого можно, отслеживая, сколько врагов уже создано с помощью переменной EnemyNum, и добавляя это значение к слову Robot. EnemyNum объявлена как статическая переменная, то есть ее разделяют все экземпляры класса.
Я не собираюсь печатать метод SetPos(), потому что по большей части он идентичен методу SetPos() для игрока; вы можете просто его скачать из исходного кода c web-сайта Linux Format[1].
[править] Стандартная библиотека шаблонов
Теперь у нас хватает кода, чтобы населить остров врагами-роботами, но сначала надо придумать, как их хранить. Метод должен быть гибким: незачем объявлять переменную для каждого робота или заводить статические массивы, потому что желательно создавать роботов по запросу. Решение состоит в использовании STL: это коллекция стандартных абстрактных типов данных для C++. Пусть слово «абстрактные» вас не пугает: STL чрезвычайно полезна, а ее типы данных обычно легко представить.
Для управления врагами нам потребуется тип данных «вектор» - массив некоторых величин, в котором нас интересует только их значение. Добавление «вражеского» вектора потребует сделать два изменения в chad.h. Вставьте следующие две строчки после директив #include:
#include "chadenemy.h" #include <vector>
Теперь вставьте эту строку в конце определения класса CChadGame:
std::vector<CChadEnemy*> Enemies;
Далее припишите к методу createOutdoorScene() следующий код:
for (int i = 0; i < 100; ++i) { CChadEnemy* enemy = new CChadEnemy(m_SceneMgr); enemy->SetPos(Vector3(rand() % 1000,0, rand() % 1000)); Enemies.push_back(enemy); }
Этот код создаст 100 новых врагов, задаст им произвольные позиции на карте (Y установлен равным 0: метод SetPos() потом переопределит это значение с учетом высоты местности), затем добавляет врагов в вектор Enemies. Если вашей системе больше трех лет от роду, врагов лучше взять поменьше. Вот и все, что потребовалось для добавления роботов — теперь скомпилируйте игру и запустите ее!
[править] Двигаемся дальше
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
Наши роботы стоят столбом, напоминая батарейки из рекламы Duracell, которые демонстрируют, что другие уже рухнули. Попробуем их оживить: пусть выберут какой-то пункт назначения на карте и отправятся туда, обуреваемые злыми намерениями. Для этого нам потребуется внести следующие изменения:
- Назначить каждому роботу точку назначения и направление.
- Сказать каждому роботу, сколько времени прошло с его последнего перемещения (поэтому они двигаются с постоянной скоростью, независимо от скорости вашего компьютера).
- Велеть роботам перемещаться при начале каждого кадра.
Мы можем разрешить первые два пункта, отредактировав файл chadenemy.h. Добавьте две строки после определения m_Speed:
Vector3 m_Direction; Vector3 m_Destination;
Также вам понадобится дописать определение следующего метода в определении класса:
void Update(Real time);
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
Мы будем вызывать метод Update() для каждого робота каждый раз, как только начнется кадр, поэтому робот сможет перемещать сам себя. Временной параметр сообщает роботам, сколько времени прошло с момента отрисовки последнего кадра. Ogre об этом позаботился: взгляните на метод CChadGame::frameStarted() в файле chad.cpp, и увидите следующее:
bool CChadGame::frameStarted(const FrameEvent& evt) {
Параметр FrameEvent сообщает множество характеристик текущего кадра, включая время, прошедшее между кадрами. Проблема состоит в том, что мы затем вызываем frameStartedOutside() или frameStartredInside() и не передаем этот параметр. Поэтому откройте файл chad.h и измените их, чтобы они соответствовали прототипам:
bool frameStartedOutside(const FrameEvent& evt); bool frameStartedInside(const FrameEvent& evt);
Вам также понадобится отредактировать файл chad.cpp. Метод frameStarted() необходимо подправить, чтобы он передавал параметр требуемому методу, например:
bool CChadGame::frameStarted(const FrameEvent& evt) { switch (scenemanager) { case ST_EXTERIOR_CLOSE: return frameStartedOutside(evt); break; case ST_INTERIOR: return frameStartedInside(evt); break; } return true; }
Каждый раз, когда кадр начинается вне дома, необходимо обновить всех наших роботов с помощью метода Update(). В части кода, получается, надо пройти в цикле по вектору Enemies() и передать данные о кадре, предоставляемые Ogre. Поэтому в конце метода frameStartedOutside() (перед строкой ‘return line’) добавьте небольшой цикл:
for (std::vector<CChadEnemy*>::iterator iter = Enemies.begin(); iter != Enemies.end(); ++iter) { CChadEnemy* enemy = (*iter); enemy->Update(evt.timeSinceLastFrame); }
Здесь STL применяется в большей степени, и наш код напоминает синтаксическую окрошку. На самом деле этот цикл проходит от начала до конца вектора, используя STL-итератор. Можно, конечно, получить прямой доступ к элементам вектора через индексы, но итераторы более предпочтительны. Для каждого врага в нашем векторе мы вызываем метод Update() и посылаем отрезок времени, прошедший с прошлого кадра. Именно тут наши роботы должны проделать всё, что им полагается — сейчас мы просто заставим их двигаться.
Пора написать сам метод Update(). Вставьте следующий код в конец файла chadenemy.cpp:
void CChadEnemy::Update(Real time) { if (m_Destination == Vector3::ZERO) { m_Destination = Vector3(rand() % 1000,0, rand() % 1000); m_Direction = m_Destination - m_Node->getPosition(); } else { Vector3 ourpos = m_Node->getPosition(); ourpos.y = 0.0f; m_Direction = m_Destination - ourpos; Real dist = m_Direction.normalise(); Real movespeed = m_Speed * time; if (dist < movespeed) { m_Destination = Vector3::ZERO; } else { // необходимо переместиться ближе к точке назначения Vector3 newpos = m_Direction * movespeed; SetPos(newpos); } } }
Код включает две ветви: если врагу уже задано направление движения, то он по нему и движется, если же нет, направление выбирается произвольно. Ветвь определяется в самом начале: если вектор m_Destination равен Vector::ZERO (по умолчанию, пустой вектор), то необходим выбор точки назначения. Зная эту точку, мы можем вычислить направление простым вычитанием координат текущей позиции (все векторные операции Ogre берет на себя).
[править] Пункт назначения: Чед
Если роботу задан путь, то мы берем его текущую позицию и точку назначения, затем пересчитываем направление. Это не обязательно, потому что направление использует числа с плавающей запятой: достаточно посчитать его один раз и забыть о нем. Но и вреда в этом нет: робот будет корректировать свою позицию при каждом кадре, и придет точно в заданный пункт независимо от расстояния до него.
Мы можем рассчитать длину вектора, вызвав метод normalise(), который вернет нормализованный вектор — имеющий то же направление, но длина его равна 1. Штука хорошая, но на самом-то деле нас интересует значение длины исходного вектора, которое также возвращается методом normalise и в нашем коде является расстоянием от робота до точки назначения. Сохраним это значение в переменной dest.
Теперь — важный момент: если расстояние до точки назначения короче, чем расстояние, на которое собирается переместиться робот (его скорость, помноженная на время, прошедшее с прошлого кадра), значит, он подобрался очень близко, и нам необходимо выбрать новое направление. Это можно сделать, установив вектор m_Destination равным Vector3::Zero, тогда при следующем вызове метода робот случайным образом выберет другую точку назначения.
Если расстояние до пункта назначения больше, чем величина перемещения робота, помножим направление на скорость робота и передвинем его на следующую позицию. Вектор направления уже был нормализован, поэтому все будет работать.
Вот и все — запустите новый код и наслаждайтесь реалистичностью перемещений ваших роботов по ландшафту!
[править] Идем верным путем
Ну, пожалуй, «реалистичность» — слишком сильно сказано: на самом деле роботы просто скользят, по причине отсутствия кода для анимации. Да и вообще, нет ничего, обуславливающего должное направление их перемещения. Давайте это исправим!
В файле chadenemy.h добавьте две строки, перед вектором m_Direction:
AnimationState* m_AnimationState; bool WatchingPlayer;
AnimationState представляет собой тип данных Ogre, ответственный за анимацию сущности: проигрывать ли ее бесконечно, и так далее. Мы хотим, чтобы наши роботы по умолчанию использовали анимацию ‘Idle’, поэтому скопируйте следующий код в конструктор класса CChadEnemy:
m_AnimationState = m_Entity->getAnimationState("Idle"); m_AnimationState->setLoop(true); m_AnimationState->setEnabled(true); WatchingPlayer = true;
Переменная WatchingPlayer будет первым кусочком искусственного интеллекта: если робот приблизится к игроку на определенное расстояние, пусть остановится и посмотрит на игрока. По умолчанию такая опция установлена для каждого робота; вы скоро узнаете, зачем.
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
Осталось изменить метод Update(). Первое, что необходимо сделать — обновить анимацию робота, этим займется метод addTime() нашей переменной m_AnimationState(). Он принимает в качестве параметра время, прошедшее с прошлого кадра, которое мы уже знаем, поэтому поместите следующую строку в начале метода Update():
m_AnimationState->addTime(time);
Далее нам необходимо поместить код, вычисляющий расстояние между текущим роботом и игроком и заставляющий робота предпринять соответствующее действие, если поблизости находится игрок: бросить вышеупомянутый злобный взгляд. Добавьте следующий код (после проверки Vector3::ZERO) внутри другого блока if:
Vector3 campos = m_SceneMgr->getSceneNode("camnode")->getPosition(); Vector3 ourpos = m_Node->getPosition(); Vector3 playerdist = ourpos - campos; if (playerdist.normalise() < 100) { if (!WatchingPlayer) { m_AnimationState = m_Entity->getAnimationState("Idle"); m_AnimationState->setLoop(true); m_AnimationState->setEnabled(true); WatchingPlayer = true; } Vector3 orient = m_Node->getOrientation() * Vector3::UNIT_X; Vector3 dir = campos - m_Node->getPosition(); dir.y = 0; Ogre::Quaternion quat = orient.getRotationTo(dir); m_Node->rotate(quat); } else { if (m_Destination == Vector3::ZERO) { // здесь почти ничего не изменилось SetPos(newpos); } // а это новый код if (WatchingPlayer) { m_AnimationState = m_Entity->getAnimationState("Walk"); m_AnimationState->setLoop(true); m_AnimationState->setEnabled(true); WatchingPlayer = false; } }
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
Итак, если робот невдалеке от игрока, мы заставляем его взглянуть, если только он уже не глядит (чтобы избежать лишних вызовов функции). Задача заставить робота смотреть на игрока представляет собой лишь вопрос получения ориентации робота, нахождению направляющего вектора между нами и роботом, а затем преобразованию его в кватернион, используя метод getRotationTo() вектора. Это позволит нам развернуть робота лицом к игроку, передав кватернион в метод rotate().
Если робот находится далеко, выполним проверку с вектором Vector3::ZERO, за которым следует много кода, заканчивающегося вызовом SetPos(). Тут все осталось без изменений, но после этого нам надо проверить, смотрел ли робот на предыдущем шаге на игрока, и если да, то заставить робота снова шагать. Теперь вы понимаете, почему все роботы по умолчанию видят игрока: первый раз при проходе по этому методу, его позиция будет установлена правильно, а анимация работать.
Лимит на код в этом уроке исчерпан. Прокрутите свою игру: мы добавили врагов, передвижение, анимацию и простенький искусственный интеллект — не так уж плохо для одного урока!
- ↑ Код этого урока можно найти на: http://www.linuxformat.co.uk/mag/hangingchad_lxf85.tar.gz