Blender GameKit 2/SubRacer

Материал из Blender3D.

Перейти к: навигация, поиск

Содержание

Подводный гонщик

Автор: Cristen Wartmann
Перевод: Азовцев Юрий

В игре "SubRacer" используются современные разработки сделанные в рамках проекта Apricot. Среди них GLSL Материалы (карты нормалей, карты каустики, карты отражений), GLSL туман (лучше выглядящий и более настраиваемый чем обычный BGE туман) и GLSL Тени.

Идея игры, концепт, игровая логика, физика, скрипты, корабль, HUD и кабина, ворота, мины и спецэффекты были сделаны мной Кристеном Вартманом (Cristen Wartmann).

Окружающее пространство уровня (камни, песчаное дно, растения, древние колонны) и дизайн корабля были сделаны Кристофером Плюшем (Christopher Plush) aka blengine'. Спасибо тебе, Крис!

В начале игра планировалась как современный симулятор подводной лодки, где вы выполняете миссии перемещаясь в под водой. Но по ходу вопрощения она все больше и больше превращалась в подводную-гоночную-аркаду и дизайн батискафа становился все больше похож на космический корабль. В конце концов я изменил идею на то что есть сейчас. Я доволен уровнем геймплея, который удалось получить за такой короткий период времени. Нам удалось достичь главной цели - вы точно получите удовольствие проведя некоторое время за управлением кораблем. Кроме этого, игра демонстрирует многие вещи, характерные и для других игр. Например, HUD (Head Up Display - экран вида сверху, карта), виды из различных камер, программные скрипты для тайминга и компановки работы элементов.

Сейчас самое время загрузить игру с диска, прилагающегося к книге (Blends/Subracer/Subracer_packed.blend) и немного поплавать вокруг. Вам нужно будет проследовать через ворота в определенном порядке для успешного прохождения уровня. Индикатор в центре HUD укажет какие из ворот следующие, укажет направление к ним и если вы двигаетесь в нужную сторону индикатор будет зеленым, если в направлении от нужных ворот - индикатор будет красным. Собирайте ящики, они дадут вам 100 юнитов турбо-топлива. После завершения прохождения уровня ваше время будет показано в поле "R-TIME". Помните, что без ускорения кораблем сложно управлять. При медленных маневрах используйте небольшие включения ускорителей для удержания корабля на нужном курсе.

Клавиши управления кораблем
Клавиши Описание
Клавиши со стрелками Поворот корабля вправо/влево и подъем/опускание носа (пилотный способ)
W Ускорение вперед
Q Турбо-ускорители (работают если есть турбо-топливо, спострите HUD)
A/D Поворот корбаля вокруг продольной оси. Не всегда нужен, но может спасти вас в некоторых ситуациях
Пробел Выстрел из ультра-звуковой пушки для уничтожения мин
R Перезапуск игры
F1 Вид из кабины корабля
F2 Вид с позиции за кораблем
image:GK2_note.png Игра создана с применением продвинутой системы GLSL материалов и освещения. Если ваша видеокарта не поддерживает эту технологию вы можете выключить GLSL (Texture Face Material) или ее часть (GLSL Material Settings) в меню "Game". Но в таком случае игра будет выглядеть менее привлекательно.

Настройка корабля

Корабль состоит из различных объектов. Для общего представления посмотрите на иллюстрацию (racer-1).

Иллюстрация (racer-1). Конструкция корабля
Иллюстрация (racer-1). Конструкция корабля

Главный объект корабля всего лишь невидимая клетка, плотно окружающая меш корабля, который вы видите в игре. Это сделано для уменьшения нагрузки на систему расчета столкновени‎й игрового движка. Мы использовали в качестве типа границ объекта "Triangle Mesh" (треугольный меш) (смотрите иллюстрацию (racer-2)). Таким образом мы можем цепляться баками на концах крыльев за другие объекты, например. Корабль, который вы видите в игре, имеет намного больше граней, но для всех них свойство collision выключено.

Вы также можете видеть две камеры и два источника света. Один расположен сверху для создания тени от корабля на поверхности дна, второй выступает в роли переднего осветительного прожектора самого корабля. Тень от корабля очень важна, для оценки расстояние от корабля до дна на глаз. Конечно, она выглядит не очень реалистично, но глобальное освещение стоило бы очень дорого. В задней части ускорителей вы можете заметить три пустышки (empties) которые создают выхлопной след от двигателей используй Актуатор AddObject. Таким же образом работают еще две пустышки расположенные впереди корабля и действующие в роли пушек.

Иллюстрация (racer-2). Система физики и Параметры Корабля
Иллюстрация (racer-2). Система физики и Параметры Корабля

В качестве значения Свойств Физики для корабля используется "Rigid Body", благодаря чему столкновениях и при действии гравитации корабль ведет себя как твердое тело. Значение параметра "Mass:" установлено равным 5, что дает большую инерцию чем у других предметов. Как вы можете заметить, не всегда требуется использовать реальный вес предметов, мы больше хотим сделать приятный вид и геймплей, чем создать реалистичную симуляцию. Я использовал достаточно большое значение для параметров Dump и RotDump для симуляции силы трения в воде. Для корабля установлено свойство "Actor" благодаря чему Сенсор Near может видеть его. Это используется для активации мин. Я так же включил функцию "No Sleeping", мы же не хотим видеть корабль лениво спящем на поверхности дна.

У нашего корабля большое количество Параметров. Параметр "uboot" - просто маркер для других объектов для определения соударений именно с кораблем что бы они могли реагировать на эти соударения правильно. Другие параметры действительно содержат значения. Параметры "turbo", "damage", "head" и "incl" используются для хранения значений, использующихся в функциях. Например, параметр "turbo" используется для принятия решения осталось ли у вас достаточно турбо-топлива для использования ускорения. Так же значение этого параметра используется при отображении информации на HUD. Параметр "next" используется для хранения количества ворот, которые осталось пройти. Параметр "time" - это таймер, значение которого сохраняется в параметр "roundtime" каждый раз, когда вы полностью заканчиваете уровень. Количество пройденных раундов храниться в параметре "round".

Как вы можете увидеть на иллюстрации (racer-3) логика включает в себя большое количество Логических Блоков. Но не так много как настройках завершенного персонажа, например, в "Yo Frankie!".

Иллюстрация racer-3. Логические Блоки
Иллюстрация racer-3. Логические Блоки

Сенсоры

Большинство Сенсоров, использующихся для управления кораблем - Клавиатурные Сенсоры (Keyboard Sensors). Затем идут два Сенсора Соударений (Collision Sensors) для определения соударений с другими объектами и "Ray Sensor" - фиксирующий появление других объектов в радиусе действия сонара и воспроизводящий характерный звук по мере приближения объекта. Два Сенсора типа Message реагируют на сообщения если найден новый контейнер с турбо-топливом и при прохождении кораблем очередных ворот. Как вы можете заметить по блоку "GateMess" я решил не давать кораблю возможность определять прошел ли он через ворота, а настроил ворота определять это событие и затем посылать кораблю соответствующее сообщение. Такой подход просто дело вкуса, но он точно снизит сложность логики корабля. В многопользовательской игре этот подход даст возможность использовать сообщения для сравнения кораблей игроков и их результатов.

Контроллеры

Большинство контроллеров - простые Контроллеры AND и они делают лишь одно - передают импульсы от Сенсоров к Актуаторам. Как вы видите, они имеют только одно входящее подключение. Второй сверху контроллер - это NAND Контроллер. Он используется для "зажигания" Актуатора Motion когда клавиша W соответствующая движению вперед НЕ нажата. Я вернусь к этому моменту чуть позже. Здесь есть один Контроллер Expression в строке выражения которого написано "TurboQ and turbo>0.0", что дает возможность использовать турбо-ускорение только если у игрока достаточно турбо-топлива.

Последний но не менее важный контроллер - Контроллер Python. Некоторый объем функционала этого скрипта мог бы быть выполнен стандартными Логическими Блоками, но это бы привело к значительному усложнения логики корабля, что в свою очередь затруднило бы возможность понимания и поддержки. Некоторые же части этого скрипта в принципе не возможно реализовать стандартными Логическими Блоками. Например, расчет угла поворота к следующим воротам. Скрипты "Gun" и "Exhaust" простые скрипты для добавления пуль и выброса "частиц", но они превосходят ограничения AddObject Актуатора. Другие скрипты несколько более сложные. В принципе, их можно бы было объединить в один скрипт, но это бы так же привело к усложнения понимания и поддержки большого скрипта.

Актуаторы

Большинство актуаторов простые Motion Актуаторы перемещающие и вращающие кораблю, напрямую связанны с Keyboard Сенсорами отслеживающими нажатие соответствующих клавиш. Здесь, так же, есть Актуатор "Buoyancy", который используется для придания кораблю некоторой поднимающей силы, что бы он начинал падать на дно под действием гравитации слишком быстро.

Иллюстрация (racer-4). Логические блоки для управления кораблем
Иллюстрация (racer-4). Логические блоки для управления кораблем

Актуаторы отвечающие за движение корабля используют новый тип "Servo Control". Этот тип актуаторов дает возможность придать кораблю максимальную заданную скорость используя силы и избавляет от необходимости обрабатывать ситуации коллизий и damping. Используя "Limit Y" в Актуаторе "Fwd" мы можем контролировать как быстро корабль может разгоняться. Актуатор "StopSlide" предотвращает корабль от слишком сильного скольжения в стороны (в доль собственной оси X), что сделало бы управление кораблем практически невозможным. Это повторяет (практически точно) динамику воды и аэродинамику в реальности , где корабль имеет меньшее сопротивление вдоль центральной линии и большее сопротивление вызванное плавниками вдоль поперечной.

Актуаторы Property добавляют параметры учета повреждений и турбо-ускорения. Актуаторы Message посылают информацию на приборную панель корабля и на HUD экран.

Пушки

Как я уже говорил ранее, у нас есть две Пустышки (Empties), связанные с кораблем и являющиеся его потомками. Они представляют собой пушки нашего корабля. Выхлоп турбин сделан таким же образом.

Как вы можете заметить на иллюстрации, Сенсор Клавиатуры корабля (объект "UBoot") связан с Python Контроллером (смотрите иллюстрация racer-gun), а контроллер, в свою очередь, связан с Актуатором "Add Object", который редактирует объект для каждой Пустышки, представляющей собой пушку.


  # Gun script
  # This script takes the velocity of the ship into account for firing the cannons
  # also uses instantAddObject to prevent 1 frame lag of the Add Object Actuator
  
  import GameLogic
  
  cont = GameLogic.getCurrentController()
  me   = cont.getOwner()
  
  fire = cont.getSensor("Fire")
  g1 = cont.getActuator("G1")
  g2 = cont.getActuator("G2")
  
  if fire.isPositive():
  	ys = me.getLinearVelocity(1)[1]
  	g1.setLinearVelocity(0,30+ys,0)
  	g2.setLinearVelocity(0,30+ys,0)
  	g1.instantAddObject()
  	g2.instantAddObject()
Листинг (racer-gun). Скрипт управления пушками

Для чего мы здесь используем Python-скрипт? Есть две причины:

  1. Механизм Add Object имеет задержку как минимум в один кадр, это незаметно (такая задержка заметна только для реактивного выхлопа), но может привести к ситуации когда корабль, особенно если он движется быстро, столкнется со своей же пулей.
  2. Мы можем придать пуле начальную скорость равную скорости корабля, плюс скорость вылета самой пули

Мы используем функцию instantAddObj() (в скрипте строки 18-19) для исключения возможности задержки при срабатывании Актуатора. Эта функция вызывает Актуатор немедленно и создает объект указанный в Актуаторе (в данном случае объект "part", который должен существовать в скрытом слое). Объект будет иметь время жизни 200 кадров, как указанно в поле "Time:".

В строке 15 вы получает текущую продольную скорость корабля и добавляем эту скорость в строках 16-17 к скорости самой пули (в нашем случае 30). Функция setLinearVelocity() задает скорость путем передачи значения в поле "linV" в Актуаторе.

Объекты присутствующие в игре

Ящик с турбо-топливом

Логика ящика с турбо топливом довольно проста. Верхняя строка логических блоков отвечает за обычное вращение ящика. Когда объект с Параметром "uboot" сталкивается с ящиком (у которого в настроках физических параметров включен параметр "Ghost" для исключения воздействия на корабль) посылается сообщение, интерпретируемое кораблем как получение дополнительных 100 "литров" турбо топлива, затем объект-ящик удаляется из сцены (End Object).

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

Вы можете заметить что по всему уровню где должны находиться ящики присутствуют пустышки. При начале игры и при завершении раунда посылается сообщение "Init", приводит к удалению существующих ящиков и созданию новых в местах расположения Пустышек. Такой подход работает благодаря наличию задержки в один кадр между получением сообщения и выполнением создания новых объектов. Благодаря этому мы можем быть уверенны что новые объекты не будут уничтожены вместе с оставшимися после предыдущего раунда.

Мины

Мины состоят из нескольких объектов - самой мины, двух кусков цепей (благодаря чему для них можно сделать анимацию движения по волнам) и якорного блока. Логика для мин в целом состоит из использования Сенсора Near (рядом), который работает как бесконтактный детонатор, реагирующий лишь на объекты с Параметром "uboot". Что же происходит при срабатывании Сенсора Near?

Сначала, проигрывается звук взрыва. Затем, убираются объекты мины и цепи. Нижняя часть цепи заменяется (используя Актуатор "Replace Mesh", имеющий тип Edit Object) мешем цепи лежащей на поверхности дна. Затем добавляется объект - огненный шар и объект создающий ударную волну.

Объект создающий ударную волну представляет из себя обычную сферу с текстурой, быстро маштабирующуюся по всем направлениям и любой объект с включенной физикой будет выброшен с сторону этой сферой. Если вы зададите сфере параметр "uboot" и сделаете ее достаточно большой, то получите хорошую цепочку действий.

Ворота

Ворота в игре так же имеют достаточно простую логику. Если вы посмотрите на Логический Блоки (я убрал из иллюстрации логически блоки отвечающие за вращение ворот) то заметите что логика опять распределена по разным частям ворот. Сами ворота имеют Сенсор Always, Контроллер Python и Актуатор Message. С контроллером так же связанны Сенсор Always от экрана с номером ворот и Сенсор Collision от зеленой "энергетической" поверхности ворот.

Сенсор "Init" срабатывает один раз при старте игры и выполняет скрипт для регистрации данных ворот среди глобальных переменных (в скрипте строки 15-23). Затем начинается игра, все объекты-ворота перечислены в Python-Словаре , где к ним можно обратиться по их уникальному имени. Кроме этого, кран с номером ворот заполняется именем текущих ворот.

  # This handles the gates
  
  import GameLogic
  
  me = GameLogic.getCurrentController().getOwner()
  cont = GameLogic.getCurrentController()
  
  init     = cont.getSensor("Init")
  nr       = cont.getSensor("Nr")
  through  = cont.getSensor("Through")
  gate     = cont.getActuator("GateMess")
  
  # the (random number) of gates are registering themselves into a global variable
  # be shure to name the gates Gate.000...Gate.XXX in the correct order!
  if init.isPositive():
  	# set the visible gate name
  	nr.getOwner().Text = me.name[2:]
  	try:
  		GameLogic.gates[me.name]=me
  	except:
  		# first gate?
  		GameLogic.gates={}
  		GameLogic.gates[me.name]=me
  	
  
  # ship has passed the gate, send message to the ship	
  if through.isPositive():
  	gate.setBody(me.name)
  	GameLogic.addActiveActuator(gate,1)
  	
Листинг (racer-gate). Скрипт инициализации ворот

Когда корабль (или любой другой объект с параметром "uboot") проходит сквозь энергетическое поле внутри ворот ("Ship Sensor") посылается сообщение с именем ворот (строки скрипта 26-29). В дальнейшем, это сообщение используется скриптом корабля для определения следующих ворот и подсчета раундов и времени.

GLSL туман

Для получения приятного подводного вида с убывающим синим оттенком объектов в далеке мы можем использовать стандартный туман (mist) из Разделе World в Окне Кнопок. С небольшими настройками он будет выглядеть довольно хорошо. Но у стандартного тумана есть недостаток - он не слишком хорошо работает с материалами в режиме сложения (метод addition), а так же имеет некоторые проблемы с alpha-поверхностями. Именно по этим причинам я решил использовать GLSL-туман, который на самом деле является обычным Node-материалом. Кроме совместимости с многослойными материалами у нас появляется возможность сделать многоцветный туман и прочие продвинутые вещи. На DVD с "Yo Frankie!" есть урок, в котором Пабло (Pablo Vazquez) объясняет как это сделать. Еще одним преимуществом является то, что вы можете исключить конкретный объект из воздействия тумана.

Туман реализован группой нодов "Mist", которую вы можете импортировать в свою сцену.

Для использования Node-материалов сначала вы должны настроить обычные материалы, как вы делали это раньше. Затем нажать кнопку "Nodes" на панели "Links and Pipeline" в Разделе Materials (F5) в Окне Кнопок.

Затем, переключите одно из окон в тип "Node Editor" и в Ноде "Input" выберите ваш основной материал. После этого при рендеринге (F12) или при запуске игрового движка (Клавиша P) на первый взгляд ничего не изменилось. Но на самом деле теперь используется система материалов с Нодами (Node Material System). Вернитесь в окно Node Editor, разорвите связь между Нодами Input и Output и добавьте между ними группу Mist, которую вы импортировали из сцены с диска к этой книге.

Соедините желтые коннекторы с именем Color на Input Ноде и Нод-группе "Mist". Затем так же соедините между собой коннекторы Color группы "Mist" и нода Output. В окне 3D-вида эффект должен быть заметен сразу же. Если изменений нет - убедитесь что у вас включен параметр "GLSL Materials" в меню "Game".

Эту процедуру вам нужно будет повторить для каждого материала на который должен влиять туман. Если вы откроете Группу "Mist" то сможете увидеть как получен этот эффект. Степень прозрачности тумана должна зависеть от расстояния между камерой и объектом. Чем дальше объект тем более синим (либо другого цвета для тругих типов тумана) он становится. Это расстояние мы получаем из Нода "Camera Data", параметра "View Distance". Конечно, значение этого параметра может быть очень большим и зависит от размеров всей сцены. Вероятно нам потребуется сократить его до необходимой степени для дальнейшего использования. Это делается с помощью нода "Mapping". Обратите внимание на множитель "0.01" на третьем месте (координата по оси Z) в строке "Size", это означает что значение параметра View Dastance будет делиться на 100. Но почему ось "Z"? Потому что камера в Blender всегда смотрит вдоль локальной оси Z.

Дальше, мы пропускаем полученное значение через Нод "Color Ramp", который укладывает значение в диапазоне от 0 до 1.0 и может использоваться для тонкой настройки внешнего вида тумана. Дальше в ноде "Mix" оригинальный цвет материала (Сolor1) смешивается с "засиненным" цветом (Color2) взятым из Нода "RGB". Степень смешения контролируется значением, полученным из нода "ColorRamp" (вход Fac). Вот и все!

image:GK2_note.png Для наилучшего эффекта вам следует выставить цвет окружения (World) в точности таким же, какой выбран в Ноде "RGB". Что бы это сделать воспользуйтесь инструментом "Sample" при выборе цвета окружения в Разделе World в Окне Кнопок. Выберите этот инструмент и щелкните по цветной области нода RGB.
Личные инструменты