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

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

 


 

 1. Texture Packer GUI

Скачать: http://code.google.com/p/libgdx/wiki/TexturePacker texture packer

В процессе разработки приложения (игры) приходит все время иметь дело с кадрами, картинками (текстурами) которые нужно позиционировать на экране. В зависимости от масштабов приложения таких кадров может быть от нескольких до нескольких сотен. Причем, существует такое ограничение — размерность каждой картинки должна быть кратна степени двойки. То есть, каждая картинка должна быть размеров 2 х 2, 4 х 2, 2 х 1024. Произвольной длинны либо ширины у картинки, загружаемой в память быть не может. Последние модели смартфонов не скажут вам ничего, но на более ранних устройствах приложение будет просто валиться.

Как с этим бороться? Во-первых, можно конечно же каждую картинку подгонять под нужные размеры, иметь при этом кучу лишнего места на картинках (=> использовать лишнюю память), потом обрезать вручную каждую картинку. Вариант второй — создавать спрайты — изображения, которые включают в себя набор кадров. К примеру, мы можем создать спрайт размером 2048 х 2048, замостить его всеми объектами какой-нибудь конкретной сцены и в последующем загрузить в память только один этот спрайт.

Как это решает Texture Packer. Создаем там так называемый .pack, выбираем папку, в которую сбрасываем все свои текстуры, задаем максимальный размер текстур для спрайта и нажимаем кнопку «Упаковать». На выходе мы получим один (или несколько — если все картинки не поместились на текстуру) страйт и .pack файл, который хранит расположение (пиксельные координаты) каждой картинки в спрайте.

Далее в коде приложения мы можем для начала загрузить атлас (в терминологии LibGdx):

TextureAtlas atlas = new TextureAtlas( Gdx.files.internal( gameAssetsPath(this.atlasFile) ) );

И потом найти нужную нам картинку:

TextureRegion region = atlas.findRegion("region_name");

 

2. Hiero

Скачать: http://code.google.com/p/libgdx/downloads/detail?name=hiero.jar&can=2&q=

LibGdx такова, что не умеет работать с теми шрифтами, которые установлены в ОС. Поэтому все надписи, которые придется рисовать, мы должны и будем делать с помощью растровых шрифтов. Растровый шрифт представляет собой спрайт (см. рисунок справа), на который нанесены все символы, которые нам нужны будут теоретически + текстовый файл (.fnt для LibGdx), который описывает пиксельную позицию каждого символа на спрайте.

Hiero — программа, которая поможет нам генерировать паки (спрайт + .fnt) для LibGdx. Запускаем его. Выбираем себе нужную стилистику — размер шрифта, тени, эффекты, сам шрифт. Нажимаем File -> Save BMFont files и сохраняем файлы.

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

Программно шрифт подгрузить можно будет так:

 

BitmapFont font = new BitmapFont(".fnt file", "sprite file", false);

 

3. Universal Tween Engine (UTE)

Скачать: http://code.google.com/p/java-universal-tween-engine/

В процессе работы с объектами некоторые из них нам придется так или иначе модифицировать — увеличиватьуменьшать, сдвигать, убиратьдобавлять. Чтобы это выглядело плавно, нам очень поможет UTE. По сути он делает аппроксимацию между исходными данными и конечными.

Пример: нам нужно сдвинуть плавно на 10 влево пикселей объект на экране. Нам нужно сообщить UTE следующее: текущую позицию объекта, конечную координату (x + 10), конечную кординату y, время, за которое нужно пройти эти 10 пикселей (скажем 1 секунду). В итоге UTE будет менять на протяжении секунды координату x до x+10. А мы будем просто рисовать объект.

Как это выглядит программно. Для каждого типа объектов нам необходимо сделать .java класс Accessor, унаследованный от шаблонного класса TweenAccessor<?> и определить там два метода getVakues и setValues. Так это будет выглядеть для спрайта:

public class SpriteAccessor implements TweenAccessor<Sprite> {
	public static final int POS_XY = 1;
	public static final int CPOS_XY = 2;
	public static final int SCALE_XY = 3;
	public static final int ROTATION = 4;
	public static final int OPACITY = 5;
	public static final int TINT = 6;

	@Override
	public int getValues(Sprite target, int tweenType, float[] returnValues) {
		switch (tweenType) {
			case POS_XY:
				returnValues[0] = target.getX();
				returnValues[1] = target.getY();
				return 2;

			case CPOS_XY:
				returnValues[0] = target.getX() + target.getWidth()/2;
				returnValues[1] = target.getY() + target.getHeight()/2;
				return 2;

			case SCALE_XY:
				returnValues[0] = target.getScaleX();
				returnValues[1] = target.getScaleY();
				return 2;

			case ROTATION: returnValues[0] = target.getRotation(); return 1;
			case OPACITY: returnValues[0] = target.getColor().a; return 1;

			case TINT:
				returnValues[0] = target.getColor().r;
				returnValues[1] = target.getColor().g;
				returnValues[2] = target.getColor().b;
				return 3;

			default: assert false; return -1;
		}
	}

	@Override
	public void setValues(Sprite target, int tweenType, float[] newValues) {
		switch (tweenType) {
			case POS_XY: target.setPosition(newValues[0], newValues[1], false); break;
			case CPOS_XY: target.setPosition(newValues[0] - target.getWidth()/2, newValues[1] - target.getHeight()/2); break;
			case SCALE_XY: 
				target.setScale(newValues[0], newValues[1]); 
				break;
			case ROTATION: target.setRotation(newValues[0]); break;

			case OPACITY:
				Color c = target.getColor();
				c.set(c.r, c.g, c.b, newValues[0]);
				target.setColor(c);
				break;

			case TINT:
				c = target.getColor();
				c.set(newValues[0], newValues[1], newValues[2], c.a);
				target.setColor(c);
				break;

			default: assert false;
		}
	}
}

Далее нам нужно зарегистрировать факт того, что SpriteAccessor используется для типа Sprite и нужен менеджер — объект класса TweenManager:

		Tween.registerAccessor(Sprite.class, new SpriteAccessor());				
		tweenManager = new TweenManager();

Так же нужно при каждой отрисовке обновлять tweenManager, например так:

tweenManager.update(Gdx.graphics.getDeltaTime());

Собственно все, теперь мы можем модифицировать объекты. Мы можем делать отдельные Tween’ы

Tween.to(objectToRun, SpriteAccessor.POS_XY, 8f).target(objectToRun.getX() + 10, objectToRun.getY()).start(tweenManager);

и так же можем группировать Tween’ы в Timeline’ы

		Timeline.createSequence()

		.push(Tween.to(objectToRun, ActorAccessor.SCALE_XY, 1f).target(2f, 2f).ease(TweenEquations.easeNone))	
		.push(Tween.to(objectToRun, SpriteAccessor.POS_XY, 8f).target(objectToRun.getX() + 10, objectToRun.getY()))	

.start(tweenManager);

При этом вначале объект увеличится в два раза за 1 секунду, а потом сдвинется на 10 пикселей за 8 секунд.

 

4. Box2D — editor

Скачать: http://code.google.com/p/box2d-editor/

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

Box2D — editor позволяет визуально настраивать модели — задавать им области, массу и пр. атрибуты.

 

5. Particle Editor

Скачать: http://www.badlogicgames.com/wordpress/?p=1255

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

 

 

 

Пример того, как можно использовать все эти тулзовины можно найти вот тут — http://habrahabr.ru/post/137861/. Мы же, попробуем шаг за шагом сделать сцену, на примере которой рассмотрим работу 2D-графического приложения и LibGdx в частности.