libGDX: Часть 3. Обзор модулей

libGDX - Диаграмма модулей

Статья, по сути, являтся переводом официальной документации. Может что-то будет отличаться. libGDX включает в себя несколько модулей, предоставляющих определённые возможности при разработке. Думаю, очевидно, какие модули должны присутствовать в такого рода библиотеке.

Введение

libGDX включает несколько модулей:

  • Input – предоставляет унифицированную модель ввода для всех платформ. Поддерживает клавиатуру, сенсорный экран, акселерометр и мышь, где это возможно.
  • Graphics – позволяет выводить изображение на экран, использую OpenGL ES, реализованный на аппаратном уровне.
  • Files – предоставляет абстрагированный доступ к файлам на различных платформах, реализуя типичные для работы с файлами функции ввода/вывода информации.
  • Audio – упрощают работу со звуком (запись/во произведение для различных платформ).
  • Math — предоставляет шустрые математический функции, которые могут понадобиться в игре.
  • Physics — полноценная обёртка Box2D.

Модули

Ввод (Input)

Модель позволяет работать с устройствами ввода на любой платформе. Это могут быть клавиши клавиатуры или мобильного устройства, сенсорный экран, акселерометр или мышь. В desctop-приложениях сенсорный экран заменяет мышь, в то время, когда акселерометр отсутствует.

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

В следующем примере показано как вывести координаты точки нажатия на тачскрине(или с помощью мыши на десктопе):

if (Gdx.input.isTouched()) {
  System.out.println("Input occurred at x=" + x + ", y=" + y); 
}

Если вы читали мою статью об архитектуре игр, то можете припомнить класс, который мы там создавали, а именно GameScreen. Он реализовывает интерфейсы InputProcessor. Так что нам всего лишь надо было переопределить кое-какие методы: mouseMoved(int x, int y), keyDown(int keycode) и другие. Соль в том, что можно было всё реализовать для различных платформ за счёт нашей архитектуры. В InputProcessor просто происходит обработка входного потока, а уже действия какие-то производятся в контроллере, независимо от типа ввода. В нашем примере реализована лишь обработка нажатий на сенсорном экране:

@Override
	public boolean touchDown(int x, int y, int pointer, int button) {

		if (!Gdx.app.getType().equals(ApplicationType.Android))
			return false;
		ChangeNavigation(x,y);
		return true;
	} 
	
	@Override
	public boolean touchUp(int x, int y, int pointer, int button) {
		if (!Gdx.app.getType().equals(ApplicationType.Android))
			return false;
		controller.resetWay();
		
		return true;
	}

	private void ChangeNavigation(int x, int y){
		controller.resetWay();
		if(height-y >  controller.player.getPosition().y * renderer.ppuY)
			controller.upPressed();
		
		if(height-y <  controller.player.getPosition().y * renderer.ppuY)
			controller.downPressed();
		
		if ( x< controller.player.getPosition().x * renderer.ppuX) 
			controller.leftPressed();
			
		if (x> (controller.player.getPosition().x +Player.SIZE)* renderer.ppuX)
			controller.rightPressed();
			
	}

Как видите, в соответствии с нажатием, оповещаем об этом контроллер, вроде controller.leftPressed(). Чтобы добавить возможность движения для нашего примера и с использованием клавиатуры, нам необходимо лишь переопределить метод keyDown(int keycode):

@Override
	public boolean keyDown(int keycode) {
		if (keycode == Keys.LEFT)
			controller.leftPressed();
		if (keycode == Keys.RIGHT)
			controller.rightPressed();
		if (keycode == Keys.UP)
			controller.upPressed();
		if (keycode == Keys.DOWN)
			controller.downPressed();
		return true;
	}

В соответствии с нажатой клавишей, мы опять же сигнализируем контроллер. Ну и, чтобы наш класс GameScreen мог перехватывать эти события, необходимо класс зарегистрировать как обработчик входного потока:

Gdx.input.setInputProcessor(this);

Графика (Graphics)

Модуль абстрагируется от работы с графическим процессором и предоставляет доступ к методам обертки OpenGL ES. Так же данный модуль заботится обо всём необходимом для реализации возможностей, предоставляемых производителями.

Главная особенность модуля — обеспечение возможности работы с текстурами и растровыми изображениями (ну, это очевидно из специфики модуля).

Как пример, для получения доступа к OpenGL API 1.0, необходимо выполнить следующий код:

GL10 gl = Gdx.graphics.getGL10 ();

Метод возвратит экземпляр, который можно использовать для вывода изображения. Если аппаратная конфигурация не поддерживает OpenGL ES 1.0, возвращается null.

В следующем фрагменте происходит очистка экрана и заливка красным цветом:

gl.glClearColor(0.1f, 0.0f, 0.0f, 1);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

Возвращается всегда конкретная реализация API (LWJGL, JOGL или Android), поэтому не нужно знать специфику; приложение будет работать на всех платформах.

Поддерживаемые версии API:

1.0 Gdx.graphics.getGL10();
1.1 Gdx.graphics.getGL11();
2.0 Gdx.graphics.getGL20();

Для подробностей можете глянуть официальную документацию.

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

Файлы (Files)

Файловый модуль обеспечивает универсальный способ доступа к файлам независимо от платформы. Это упрощает работу по чтению/записи файлов. Очевидно, запись в файл имеет свои ограничения, связанным с безопасностью платформы.

Наиболее распространенные случаи использования модуля Files — загрузка ресурсов (текстур, звуковых файлов) из одного подкаталога приложения для всех платформ. Это также очень удобно для сохранения состояния игры, результатов, достижений.

Если вы ресурсы храните в assets директории и включили её в итоговую сборку, то примерно так будет выглядеть создание текустуры на основе изображения:

Texture myTexture = new Texture(Gdx.files.internal("texture/brick.png"));

За счёт высокого уровня абстракции, работает что на андройде, что на десктопе.

К слову о сохранении состояния. В Android есть очень удобный механизм, названный SharedPreferences. В LibGDX для этого есть класс com.badlogic.gdx.Preferences. Так что, лично я файлы юзаю только для загрузки изображений/музыки. А состояние и результаты сохраняю используя Preferences.

Аудио (Audio)

Аудио-модуль упрощает создание и использование аудио файлов. Он так же предоставляет прямой доступ к устройству аудио-вывода.

Он позволяет работать со звуковыми файлами двух типов: музыка и звук. Оба типа поддерживает форматы WAV, MP3, OGG, mid. Возможно и другие, но вам и этих должно хватить (:

Экземпляры sound загружается в память и могут быть воспроизведены в любое время. Идеально подходит для звуковых эффектов, которые используются по несколько раз, таких как взрывы или выстрелы.

Экземпляр music, с другой стороны, являют собой поток из файлов на диске (или SD карты). При каждом воспроизведении он считывается из источника.

Следующий фрагмент кода воспроизводит повторно файл myMusicFile.mp3 с диска и устанавливает громкость 50%:

Music music = Gdx.audio.newMusic( Gdx.files.getFileHandle("music/myMusicFile.mp3", FileType.Internal));
//или так
music = Gdx.audio.newMusic( Gdx.files.internal("music/myMusicFile.mp3"));
//установка громкости в промежутке [0;1F]
music.setVolume(0.5f);
//начать воспроизведение
music.play();
//указываем, что воспроизведение файла надо повторять
music.setLooping(true);

Математика (Math)

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