Это третья статья из цикла переводов туториалов libGDX.
Первая статья находится здесь
Вторая статья находится здесь
scene2d
Пакет scene2d представляет собой классы для реализации графа для двухмерной сцены, которые могут быть полезны для управления группой иерархически связанных актеров (актер — некоторая сущность, которая может быть нарисована и которая может обрабатывать события ввода — прим. переводчика). Этот пакет предоставляет поддержку для обрвбо управления, рисования с возможностью поворота и масштабирования актеров в системе координат относительно родительского актера. Этот пакет также предоставляет фреймворк для управления действиями актеров через некоторые промежутки времени (tweening). Пакет scene2d.ui предоставляет актеров, которые могут быть полезны при построении графического интерфейса пользователя.
Важные классы из пакета
Класс Stage имеет «корневую» группу(group) куда приложение может добавлять своих актеров. Класс Stage имеет свою камеру и свой упаковщик спрайтов (SpriteBatch). Область просмотра камеры устанавливается равным размеру экрана. Когда класс Stage отрисовывается, SpriteBatch отрисовывает корневую группу. Вместе с тем, Stage реализует интерфейс InputProcessor и отсылает события ввода в корневую группу.
Класс Group является актером который может содержать других актеров. Вращение и масштабирование Group соответсвующим образом отражается на его дочерних актерах. Класс Group делегирует рисование и события ввода соответсвующим дочерним актерам. Он превращает координаты событий ввода так, что дочерние элементы получают эти координаты в своей собственной системе координат.
Класс Actor предоставляет базовый функционал для представления узла графа сцены. Он имеет позицию, размер, информацию про масштаб, вращение, родительський компонент (origin). Также актер может иметь имя, что позволяет найти его по этому имени и может помочь при отладке (вы можете вывести иерархию актеров с их именами).
Настройка класса Stage
Класс Stage имеет область просмотра. Вы можете задать ее в конструкторе, хотя неплохой идеей было бы устанавливать эту область когда приложение изменяет свой размер. Конструктор также принимает параметр логического типа, который называется stretch. Если этот параметр выставлен в true, класс Stage при отрисовке будет растягивать (сжимать) изображение до размеров экрана, если размер экрана не совпадает с размером области просмотра Stage. Если же этот параметр false, размеры области просмотра Stage будут урезаны до разрешения экрана. Если настройка области просмотра осуществляется в методе resize(), значение этого параметра несущественно.
Класс Stage имеет метод с названием act, который принимает время, которое прошло с момента рисования последнего кадра. Вызов этого метода приводит к вызову метода act у других актеров, что позволяет актерам осуществлять определенные действия через некоторые промежутки времени. Вызов метода act у класса Stage необязательный.
private Stage stage;
public void create () {
stage = new Stage(0, 0, true);
}
public void resize (int width, int height) {
stage.setViewport(width, height, true);
}
public void render () {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}
public void dispose() {
stage.dispose();
}
Актеры
Расширьте абстрактный класса Actor и реализуйте в нем методы для рисования, определения нажатий и обработки управления в графе сцены.
Рисование
Когда вызывается метод рисования для класса Stage, он вызывает метод рисования для корневой группы. В свою очередь, корневая группа вызывает методы рисования у дочерних актеров. Чтобы нарисовать актера, реализуйте метод draw():
TextureRegion region;
public void draw (SpriteBatch batch, float parentAlpha) {
batch.setColor(1, 1, 1, parentAlpha);
batch.draw(region, x, y, width, height);
}
SpriteBatch, который получает актера, уже настроенный родительським актером (корневой группой) на правильное отображение актера относительно левого нижнего угла корневой группы. Это такие параметры как расположение актера, его размер, информация про масштабирование, вращение. Это делает очень легким рисование актера в нужном месте. В коде, приведенном выше, параметры x, y, width, height есть публичные поля класса Actor.
Если параметр visible будет установлен в false для определенного актера, корневая группа не будет вызывать для него метод draw().
Параметр parentAlpha, который передается методу draw(), являет собой значение прозрачности цвета родительського компонента. Если учитывать этот параметр, корневая группа и дочерние актеры могут быть просвечивающими (полупрозрачными).
Метод begin() класса SpriteBatch уже вызван, когда вызывается метод draw() у определенного актера. Если актеру требуется нарисовать себя каким-либо другим путем, например, используя класс ShapeRenderer, класс SpriteBatch должен завершить и вновь начать упаковку спрайтов (должны быть вызваны методы begin() и end()). Конечно, это приведет к очищению буффера упаковщика спрайтов, поэтому нужно использовать эту возможность осторожно (могут быть потери производительности — прим. переводчика). Вы можете использовать матрицу проекций и матрицу преобразований из класса SpriteBatch:
private ShapeRenderer renderer;
public void draw (SpriteBatch batch, float parentAlpha) {
batch.end();
renderer.setProjectionMatrix(batch.getProjectionMatrix());
renderer.setTransformMatrix(batch.getTransformMatrix());
renderer.translate(x, y, 0);
renderer.begin(ShapeType.Rectangle);
renderer.rect(0, 0, width, height);
renderer.end();
batch.begin();
}
Определение нажатий
Когда вы вызывете метод hit() у класса Stage(), он вызывает метод hit() у корневой группы. Корневая группа вызывает метод hit() у дочерних актеров. Первое возвращаемое значение типа Actor и будет возвращаемым результатом класса Stage. (То есть, мы спускаемся по иерархии актеров, и как только какой-либо актер «думает», что на него нажали, он возвращает себя, а класс Stage и возвращает этого актера. — прим. переводчика). Для перехвата нажатий реализуйте метод hit() у актера:
public Actor hit (float x, float y) {
return x > 0 && x < width && y > 0 && y < height ? this : null;
}
Метод hit() возвращает актера, на которого было произведено нажатие, или null в противном случае. Координаты берутся относительно системы координат актера. В коде выше приведена типичная реализация, когда мы возвращаем актера, если мы мы нажали на точку, которая попадает в прямоугольник актера.
Обработка событий касания
Чтобы обрабатывать управление, реализуйте методы touchDown(), touchDragged() и touchUp():
public boolean touchDown (float x, float y, int pointer) {
return true;
}
public void touchDragged (float x, float y, int pointer) {
}
public void touchUp (float x, float y, int pointer) {
}
Когда происходит вызов метод touchDown() для класса Stage, вызывается метод touchDown() для корневой группы. Корневая группа вызывает метод hit() для дочерних актеров. Метод touchDown() вызывается для первого актера, который возвращается методом hit(). Если вызов touchDown() для этого актера возвращает false, это значит, что актер игнорирует событие и процесс продолжается для следующего актера. Если touchDown() возвращает true, актер получает фокус ввода. Это значит, что у него вызываются методы touchDragged() и touchUp(), если конечно он не игнорирует их. Когда вызывается метод touchUp() для актера, что гарантированно случится, актер теряет фокус ввода.
Метод touchDown() для класса Group рассылает сообщения touchDown дочерним актерам. Если этот метод переопределен, необходимо вызвать базовый метод super().touchDown(), иначе актеры не получат ни одного события про нажатия.
Есть также один дополнительный метод для обработки нажатий который может быть перекрыт, это метод touchMoved(). Он может быть вызван только на настольном ПК и он вызывается, когда вы перемещаете мышку.
Подобно к методу hit(), координаты, которые передаются методам-обработчикам управления, даются в системе координат актера.
Если поле touchable выставлено в false для актера, класс Group не будет вызывать методы для обработки управления для этого актера.
Для обработки управления с клавиатуры, что может произойти только на настольном ПК, переопределите методы keyDown(), keyUp и keyTyped(). Они могут быть вызваны только тогда, когда актер получит фокус ввода с клавиатуры. Это фокус может быть получен и сброшен вызовом метода keyboardFocus() класса Stage.
Для обработки скроллинга мышью, что может произойти только на настольном ПК, переопределите метод scrolled(). Он будет вызван лишь случае, когда актер имеет фокус для скроллинга. Установка и сброс этого фокуса производятся методом scrollFocus класса Stage.
Автор: 1nt3g3r