Главная » Программирование игр под Android » Пример работы с Эйлеровой камерой – РАЗРАБОТКА ИГР ДЛЯ ОС ANDROID

0

Испытаем класс Eul егСатега, написав небольшую программу. Мы хотим поворачивать камеру вверх, вниз, влево и вправо, основываясь на прикосновениях пальца к экрану.

Мы также желаем перемещать ее вперед, если нажата кнопка. Наш мир следует наполнить ящиками. На рис. 11.10 изображена картина, которая предстанет перед глазами пользователя в начале работы.

Рис. 11.10. Простая сцена, содержащая 25 ящиков, точечный источник света и Эйлерову камеру с параметрами, заданными по умолчанию

Камера будет находиться в точке (0; 1; 3). В мире также будет располагаться белый точечный источник света в точке (3; 3; -3). Ящики размещаются в сетке с координатами (-4; 4) по оси х и (0; -8) по оси z, расстояние между ящиками равно 2.

Как камера будет реагировать на касания экрана пользователем? Мы хотим, чтобы камера поворачивалась вокруг оси у, если пользователь проведет пальцем по экрану горизонтально. Это эквивалентно повороту головы влево и вправо. Мы также желаем, чтобы камера поворачивалась вокруг оси х после того, как пользователь проведет по экрану вертикально. Это эквивалентно движению головы вверх и вниз. В дополнение мы бы хотели объединить эти два движения. Наиболее прямолинейный способ добиться этого – проверять, касается ли палец экрана, и, если это так, сравнивать координаты касания с последним сохраненным значением. Далее можем реализовать изменение угла поворота вокруг обеих осей, используя разницу по оси х для поворота по оси у и наоборот.

Мы также хотим, чтобы камера перемещалась вперед при нажатии кнопки, расположенной на экране. Это довольно просто. Мы просто вызываем метод Eul erCamera getDi recti on и умножаем полученный результат на скорость, с которой должна перемещаться камера, и на изменение времени. Как видите, мы снова реализовываем перемещение, основанное на времени. Единственное, что нам остается сделать, – нарисовать кнопку (я решил нарисовать кнопку размером 64 х 64 пиксела в нижнем левом углу экрана) и проверять, нажимает ли на нее пользователь.

Чтобы упростить реализацию, мы разрешим пользователю выполнять только одно действие за один раз – либо поворачивать камеру, либо перемещать ее.

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

Теперь, когда мы описали будущую программу, взглянем на класс EulerCameraScreen, реализацию класса GLScreen, которая находится внутри реализации класса GLGame, называющейся Eul erCameraTest (обыкновенной тестовой структуры). Код показан в листинге 11.10.

Листинг 11.10. Фрагменты теста EulerCameraTest.java, класс EulerCameraScreen

Мы начинаем с описания нескольких членов класса. Первые два хранят текстуры ящика и вершины текстуры куба. Мы будем генерировать эти вершины с помощью метода createCube, описанного в прошлом примере.

Следующий член класса – это PointLight, с которым мы уже знакомы, как и с экземпляром нашего нового класса Eul erCamera.

Следующие несколько членов нужны для отрисовки кнопки. Для нее мы используем отдельное изображение размером 64 х 64 пиксела. Нам также понадобятся экземпляры классов SpriteBatcher, Camera2D и TextureRegi on. Это означает, что мы объединим 3D- и 20-отрисовку в одном примере. Последние три члена используются для отслеживания текущей позиции прикосновения к экрану (touchPos) в координатах пользовательского интерфейса, а также последние известные точки прикосновений. Мы используем значения -1 для параметров lastX и lastY, чтобы сообщить, что пока не было ни одного прикосновения.

В конструкторе загружаем текстуру ящика и создаем вершины куба точно так же, как и в прошлом примере. Мы также создаем точечный источник освещения PointLight и устанавливаем его позицию равной (3; 3; -3). Экземпляр класса EulerCamera создается со стандартными параметрами – поле обзора 67°, соотношение сторон соответствует текущему разрешению экрана, расстояние ближней плоскости отсечения равно 1, а дальней 100. Наконец, перемещаем камеру в позицию (0; 1; 3), что показано на рис. 11.10.

В остальной части конструктора просто загружаем текстуру кнопки, а также создаем экземпляры классов SpriteBatcher, Camera2D и TextureRegi on, необходимые для отрисовки кнопки. Наконец, создаем экземпляр класса Vector2, благодаря чему можем преобразовывать координаты прикосновения к экрану к координатной системе экземпляра класса Camera2D, который используется для отрисовки элементов пользовательского интерфейса, точно так же, как и в игре Большой прыгун.

Методы createCube и resume совершенно не изменились с предыдущего примера, поэтому я не повторяю здесь весь их код.

В методе update  происходят поворот камеры и ее перемещение, которые основываются на событиях прикосновений к экрану. Первое, что мы делаем, – очищаем буфер этих событий с помощью вызова метода Input getTouchEvents. Далее получаем координаты текущего прикосновения первого пальца к экрану. Обратите внимание, если палец не прикасается к экрану, вызываемые методы просто вернут последнюю известную позицию экрана с индексом 0. Мы также преобразовываем координаты прикосновения к координатной системе пользовательского интерфейса. Это делается для того, чтобы проверить, нажал ли пользователь кнопку в левом нижнем углу.

После того как мы получим все эти значения, выполняется проверка на то, прикасается ли палец к экрану в данный момент. Если да, сначала проверяем, не нажата ли кнопка, которая заполняет все пространство от точки (0; 0) до точки (64; 64) двухмерной системы координат пользовательского интерфейса. Если это так, то мы получаем текущее направление камеры и, умножив на изменение времени, добавляем его к позиции камеры.

Поскольку мы работаем с единичным вектором, камера будет перемещаться на одну единицу расстояния в секунду.

Если же пользователь не коснулся кнопки, программа интерпретирует это прикосновение так, будто он провел по экрану пальцем. Чтобы работать в этом направлении дальше, нам нужно знать последнюю координату прикосновения к экрану. Во время первого прикосновения пользователя к экрану члены 1 astX и 1 astY будут равны -1. Это говорит о том, что в этот раз мы не можем вычислить разность между последней и текущей координатами прикосновения к экрану, поскольку у нас есть всего лишь один отсчет данных. Поэтому мы просто сохраняем текущие координаты и возвращаемся из метода updateO. Если координаты прикосновения уже сохранялись, просто находим разность между значениями координат по осям х и у для предыдущего и текущего прикосновений. Затем напрямую преобразовываем их к инкрементам углов поворота.

Чтобы несколько замедлить поворот камеры, полученную разность придется делить на 10. Единственное, что остается сделать, – вызвать метод EulerCamera. rotate , который соответственно изменит углы поворота камеры.

Наконец, если палец больше не касается экрана, устанавливаем значения параметров lastX и lastY равными -1, сообщая, что нам снова приходится ждать первого прикосновения к экрану перед тем, как осуществлять обработку события прикосновения.

Метод present  удивительно прост благодаря тому, что он содержит вызовы всех вспомогательных классов. Мы начинаем с привычных действий – очистки экрана и установки окна просмотра. Далее указываем классу Eul erCamera установить проекционную и видовую матрицы.

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

Следующий фрагмент кода просто рисует 25 кубов, расположенных в форме сетки, с помощью простого вложенного цикла for. Поскольку нам приходится умножать модельно-видовую матрицу на матрицу преобразования для того, чтобы поместить вершины куба на определенные позиции, мы также должны использовать методы glPushMatrix и glPopMatrix, чтобы не уничтожать матрицу камеры, которая также является модельно-видовой.

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

Отрисовка кнопки работает точно так же, как и отрисовка элементов пользовательского интерфейса в игре Большой прыгун. Мы приказываем экземпляру класса Camera2D установить окно просмотра и матрицы (на самом деле нам не понадобится повторно устанавливать окно просмотра, вы можете свободно отпимизировать этот метод) и указываем экземпляру класса SpriteBatcher, что мы собираемся отрисовать спрайт. Мы отрисовываем всю текстуру кнопки в точке (32; 32) в нашей системе координат размером (480 х 320), установленной с помощью gui Camera.

Наконец, мы просто отключаем несколько предыдущих состояний, которые подключили ранее, а также смешивание и текстурирование.

Остальная часть класса – это просто пустые методы pause О и dispose О. На рис. 11.11 показан результат работы этой небольшой программы.

Рис. 11.11. Простой пример, иллюстрирующий работу камеры для первого лица, мультитач для простоты не поддерживается

Довольно мило, не правда ли? Программа имеет небольшой объем благодаря нашим вспомогательным классам. Теперь неплохо было бы добавить поддержку мультитача. Вот небольшая подсказка: вместо использования опроса, как в предыдущем примере, применяйте реальные события прикосновения. При прикосновении пальца к экрану выполняйте проверку нажатия кнопки. Если это случилось, отмечайте ID указателя, связанный с ней так, что он не будет способен обрабатывать проведение пальцем по экрану, пока первый палец не оторвется от экрана. События прикосновения к экрану от всех остальных ID могут быть интерпретированы как проведение пальцем по экрану.

Источник: Mario Zechner / Марио Цехнер, «Программирование игр под Android», пер. Егор Сидорович, Евгений Зазноба, Издательство «Питер»

По теме:

  • Комментарии