Главная » Программирование игр под Android » GLGAME: РЕАЛИЗАЦИЯ ИГРОВОГО ИНТЕРФЕЙСА

0

 

Мы реализовали класс Androi dGame, который связывает все подмодули для звука, файлов ввода-вывода, графики и обработки пользовательского ввода. Мы вновь используем большую часть этого кода в нашей будущей двухмерной игре на OpenGL ES, поэтому создадим новый класс GLGame, который реализует игровой интерфейс, который мы описали ранее.

Вообще, мы пока знаем об OpenGL ES недостаточно, чтобы реализовать интерфейс Graphics. Однако здесь вас ждет сюрприз: мы не будем его реализовывать. OpenGL не очень хорошо работает с программными моделями интерфейса Graphics. Вместо этого мы создадим новый класс GLGraphics, отслеживающий экземпляр класса GL10, получаемый от GLSurfaceView (листинг 7.2).

Листинг 7.2. GLGraphics.Java: отслеживание GLSurfaceView и экземпляра GL10 package com.badlogiс.androi dgames.framework.imp1;

В этом классе всего несколько методов-установщиков и методов-получателей. Обратите внимание, что мы будем использовать данный класс для визуализации потока, запущенного GLSurfaceView. Таким образом, у нас может возникнуть проблема с вызовом метода Vi ew, который работает в основном в потоке пользовательского интерфейса. В данном случае это неважно, Мы сможем запрашивать только ширину и высоту GLSurfaceView, чего нам вполне хватит.

Класс GLGame немного сложнее. Он использует большую часть кода из класса Androi dGame. Единственный момент, который вызывает сложности, – синхронизация между визуализацией и потоками пользовательского интерфейса. Рассмотрим, как это происходит (листинг 7.3).

Листинг 7.3. GLGame.java. реализация OpenGL ES Game package com.badlogic.androidgames.framework.impl;

Этот класс дополняет класс Activity и реализует Game и интерфейс GLSurf aceVi ew. Renderer. Он содержит перечень GLGameState, отслеживающий, в каком состоянии на данный момент находится экземпляр класса GLGame. Мы вернемся к этому немного позже.

Члены данного класса состоят из экземпляров класса GLSurf aceVi ew и GLGraphi cs. Класс также содержит экземпляры Audio, Input, FilelO и Screen, которые понадобятся нам для написания игры, так же как и в классе Androi dGame. Элемент state отслеживает состояние с помощью одного из перечней GLGameState. Элемент stateChanged представляет собой объект, который мы будем использовать для синхронизации потока пользовательского интерфейса и потока визуализации. Далее используем элемент, отслеживающий дельту времени, и WakeLock, который не дает экрану гаснуть.

В OnCreate выполняется обычная подпрограмма установки. Мы развертываем Activity на весь экран и создаем экземпляр GLSurfaceView, устанавливая его как вид с содержимым. Мы также создаем экземпляры всех остальных классов, которые реализуют интерфейсы фреймворка, в частности классы AndroidFilelO или Androidlnput. Обратите внимание на то, что мы заново используем классы, которые применяли в классе Androi dGame. за исключением Androi dGraphics. Еще один важный момент заключается в том, что мы больше не разрешаем классу Androidlnput масштабировать координаты касания до целевого разрешения; как это было в Androi dGame. Оба значения масштаба равны 1, так что мы будем использовать реальные координаты касания. Зачем это нужно, мы разберемся чуть позже. Последнее, что нам предстоит сделать, – создать экземпляр класса WakeLock.

В методе onResume мы указываем классу GLSurfaceView запустить поток визуализации, вызвав его метод onResume. Мы также создаем WakeLock.

Далее вызываем метод onSurfaceCreate. Он, естественно, также вызывается в потоке визуализации. Здесь мы видим, как используются перечни состояний. Если приложение запущено впервые, то состояние будет иметь вид GLGameState. Initialized. В этом случае мы вызываем метод getStartScreen для того, чтобы вернуться к стартовому экрану игры. Если игра находится в неинициализированном состоянии, но уже была запущена, мы знаем, что мы просто ее возобновили. В любом случае мы устанавливаем GLGameState. Runni ng и вызываем текущий метод Screen – resume. Мы также отслеживаем текущее время, чтобы позже можно было вычислить дельту времени.

Нам также необходима синхронизация, поскольку теми элементами, которыми мы управляем внутри блока синхронизации, также можно управлять в методе onPause потока пользовательского интерфейса. Необходимо избежать этого, поэтому используем объект в качестве замка. Мы могли бы также применить экземпляр класса GLGame.

Метод onSurfaceChanged – это, в сущности, заглушка, поэтому не будем его разбирать.

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

Если игра запущена, подсчитываем дельту времени и указываем текущему Screen обновиться.

Если игра поставлена на паузу, указываем текущему Screen также встать на паузу. Затем мы изменяем состояние на GLGameState. Idle, обозначая, что мы получили запрос на приостановку от потока пользовательского интерфейса. Поскольку мы ожидаем, что это произойдет в методе onPause пользовательского интерфейса, мы сообщаем потоку пользовательского интерфейса, что он теперь может поставить приложение на паузу. Данное уведомление необходимо, поскольку нам нужно убедиться, что поток визуализации поставлен на паузу/закрыт в случае, если наша Activity закрыта или поставлена на паузу в потоке пользовательского интерфейса.

Если Acti vi ty завершается (и не поставлена на паузу), переходим к GLGameState. Finished. В этом случае указываем текущему Screen остановиться и удалить себя, а затем отослать еще одно уведомление потоку пользовательского интерфейса, ожидающему, пока поток визуализации завершит работу.

Метод onPause – обычный метод уведомления для работы с Acti vi ty, вызываемый потоком пользовательского интерфейса, когда Activity ставится на паузу. В зависимости от того, закрыто приложение или поставлено на паузу, устанавливаем соответствующее состояние и ждем, пока поток визуализации обработает это новое состояние. Для этого используется стандартный механизм Java ожидание/ уведомление.

Наконец, высвобождаем WakeLock и указываем GLSurf aceVi ew и Acti vi ty встать на паузу, остановить поток визуализации и удалить поверхность OpenGL ES, из-за чего инициируется потеря контекста OpenGL ES, о которой мы говорили ранее.

Метод getGLGraphi cs  – это новый метод, доступный только через класс GLGame. Он возвращает экземпляр класса GLGraphics, который мы сохраняем, чтобы позже у нас был доступ к интерфейсу GL10 при дальнейшей реализации Screen.

Остаток данного класса функционально не изменился. Если мы случайно попытаемся получить доступ к стандартному экземпляру класса Graphics, получим исключение, поскольку GLGame не поддерживает такую операцию. Вместо этого будем работать с методом GLGraphics, который получаем через метод GLGame. getGLGraphicsO.

Зачем нам нужна вся эта сложнейшая синхронизация с потоком визуализации? Так мы добьемся того, что наши реализации Screen будут полностью работать в потоке визуализации. Все методы Screen будут выполняться здесь, что необходимо, если мы хотим получить доступ к функционалу OpenGL ES. Запомните, мы можем получить доступ к OpenGL ES только в потоке визуализации.

Подведем итоги с помощью примера. В листинге 7.4 показано, как выглядит наш первый пример при использовании GLGame и Screen.

Листинг 7.4. GLGameTest.Java; больше очистки экрана, теперь на 100 X больше GLGame

Это та же самая программа, что и в нашем предыдущем примере, за исключением того, что теперь мы наследуем от GLGame, а не от Activity и предоставляем реализацию Screen вместо реализации GLSurfaceView.Renderer.

В следующих примерах мы просто рассмотрим соответствующие части реализации Screen каждого примера. Общая структура наших примеров останется той же. Конечно, нам необходимо добавить пример реализации GLGame к нашей стартовой Acti vi ty и файлу манифеста.

С учетом всего этого визуализируем наш первый треугольник.

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

По теме:

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