Главная » Программирование игр под Android » КЛАСС WORLDRENDERER DROID INVADERS

0

 

Перечислим все, что нам необходимо отрисовать в 3D: корабль – мы сделаем это, используя модель и текстуру корабля и применив освещение; захватчики – это выполним, применив модель и текстуру захватчика и опять же задействовав освещение; выстрелы на поле боя – сделаем это, основываясь на модели выстрела; в этот раз без текстур, но с освещением; щиты – выполним это, основываясь на модели щита, опять же без текстурирования, но с использованием освещения и прозрачности (см. рис. 12.3); взрывы на месте модели корабля или захватчика – они, конечно же, не освещаются.

Мы уже знаем, как написать код для первых четырех элементов нашего списка. Что же делать со взрывами?

Оказывается, можно использовать SpriteBatcher. Основываясь на времени состояния взрывающегося корабля или захватчика, мы можем получить текстурный регион из экземпляра класса Animation, хранящего анимацию взрыва (смотрите класс Assets). Класс SpriteBatcher может отрисовывать лишь текстурированные прямоугольники в плоскости ху, поэтому нам придется найти способ переместить прямоугольник на произвольную позицию в пространстве (ту, где находится взрывающийся корабль игрока или захватчика). Мы можем с легкостью сделать это, используя метод gl Trans 1atef  на видовой матрице перед отрисовкой прямоугольника с помощью экземпляра класса SpriteBatcher.

Создание начальных условий для отрисовки прочих объектов не составляет труда. У нас есть направленный источник света, исходящий из правого верхнего угла, а также подсветка, немного освещающая все объекты вне зависимости от их ориентации. Камера располагается немного выше за кораблем. Она смотрит в точку, расположенную перед кораблем. Мы будем использовать камеру LookAtCamera.

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

Чтобы добавить еще одну визуальную изюминку, мы будем поворачивать захватчиков вокруг оси у. Мы также будем поворачивать корабль вокруг оси г, основываясь на его текущей скорости, благодаря чему он будет наклоняться в ту сторону, в которую перемещается.

Напишем для всего этого код. В листинге 12.12 приведен последний класс игры Droid Invaders.

Листинг 12.12. Класс WorldRenderer.java. занимающийся отрисовкой игрового мира

Класс WorldRenderer отслеживает состояние экземпляра класса GLGraphics, из которого мы получаем экземпляр класса GL10. В этом классе также хранятся экземпляры классов LookAtCamera, AmbientLight, DirectionLight и SpriteBatcher. Наконец, в нем есть член, отслеживающий текущий угол поворота, используемый для захватчиков.

В конструкторе мы, как обычно, устанавливаем значения членов класса. Камера имеет поле видимости, равное 67°, расстояние до ближней плоскости равно 0,1 единицы, а расстояние до дальней плоскости равно 100 единицам. Получившееся окно просмотра с легкостью вместит весь игровой мир. Мы поместим его позади корабля чуть выше него и повернем так, чтобы оно смотрело в точку (0; 0; -4). Подсветка имеет светло-серый цвет, а направленный источник света белый и исходит из правой верхней грани. Наконец, создаем экземпляр класса Spri teBatcher, который поможет нам отрисовывать прямоугольники взрывов.

Метод render О начинается с установки координаты камеры по оси х, равной координате корабля по той же оси. Конечно, мы соответственно устанавливаем значение координаты по оси х точки, на которую смотрит камера. Таким образом, камера будет следовать за кораблем. Как только позиция и точка просмотра обновятся, мы можем установить проекционную и видовую матрицы с помощью вызова метода LookAtCamera. setMatrices . Далее устанавливаем все состояния, необходимые для отрисовки. Нам понадобятся тестирование глубины, текстурирование, освещение, а также функциональность цветов материалов, поэтому нам не нужно будет определять материалы объектов с помощью вызова метода gl Material . Следующие два метода активируют подсветку и направленный источник света. После выполнения всех этих действий мы готовы отрисовывать наши объекты.

Первый объект, который мы отрисовываем, – корабль. Его отрисовка выполняется с помощью вызова метода renderShipO. Далее отрисовываем захватчиков с помощью метода render Invaders . Поскольку для отрисовки блоков щита и выстрелов не нужно текстурирование, мы отключаем его для того, чтобы сохранить несколько тактов процессора. Как только это будет выполнено, отрисовываем выстрелы и щиты с помощью вызовов методов renderShots и renderShields. Наконец, просто отключаем остальные состояния OpenGLES.

Метод renderShiр начинается с проверки состояния корабля. Если он взрывается, то мы отключаем освещение, вызываем метод renderExpl osionO для отрисовки взрыва на месте корабля и снова включаем освещение. Если корабль цел, мы связываем его текстуру и модель, помещаем в стек видовую матрицу, передвигаем его на свою позицию, поворачиваем его вокруг оси z, в зависимости от скорости и рисуем его модель. Наконец, из стека выталкивается видовая матрица (оставляя в нем только вид камеры) и отвязываются вершины модели корабля.

Метод render InvadersО очень похож на метод renderShipO. Единственное различие заключается в том, что мы в цикле проходим по списку захватчиков, а текстура привязывается к сети до этого. Это уменьшит количество привязок и несколько ускорит отрисовку. Далее для каждого захватчика проверяется его состояние и отрисовывается либо взрыв, либо нормальная модель захватчика. Поскольку привязка модели и текстуры выполняется вне цикла, нам приходится отвязывать их, а затем привязывать снова перед тем, как отрисовать взрыв вместо захватчика.

Метод renderShieldsО отрисовывает блоки щита. Мы применяем тот же принцип, что и при отрисовке захватчиков. Привязываем модель только однажды. Поскольку у блоков щита нет текстуры, нам не нужно ее привязывать. Однако нам следует включить смешивание. Нам также необходимо сделать общий цвет вершин синим, а его альфа-компоненту установить равной 0,4. Это сделает блоки щита несколько прозрачными.

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

Наконец, у нас есть таинственный метод renderExplosion. Мы получаем позицию, на которой хотим отрисовать взрыв, а также время состояния взрывающегося объекта. Второй параметр используется для получения корректного текстурного региона из экземпляра класса Animation, так же мы поступали и в случае с Бобом в игре Большой прыгун.

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

Вызов следующего метода как раз и является главным. Мы указываем экземпляру класса Spri teBatcher отрисовать прямоугольник в точке (0; 0; 0) (координата по оси 2 не задана, но неявно равна нулю, как вы помните), ширина и высота этого прямоугольника равны 2 единицы. Поскольку мы использовали метод glTrans. atef , этот прямоугольник будет находиться не в центре координат, а в центре позиции, определенной методом glTranslatefO, которая в точности повторяет позицию взрывающегося корабля или захватчика. Наконец, видовая матрица выталкивается из стека – и мы снова отключаем смешивание.

Вот и все. Двенадцать классов, создающих полноценную трехмерную игру, пародирующую классическую игру Space Invaders.

Поиграйте в нее. Когда вы закончите, мы рассмотрим вопросы, связанные с производительностью.

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

По теме:

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