Бережное отношение к ресурсам устройства на котором работает ваша программа - залог крепкого здоровья, хорошей кармы и великого счастья всем пользователям и процессорам.
Например, если вы создаете живые обои настоятельно рекомендуется минимизировать потребляемые ресурсы. Оптимизация потребления памяти - отдельная большая тема о которой поговорим в другой раз, а сегодня проделаем достаточно простое и эффективное действо по ограничение количества кадров при рендринге изображения движком.
Начинающие разработчики при поиске подходящего движка часто обращаются к движку AndEngine. Оно и не мудрено, он хорошо проработан и имеет большое комьюнити. Правда документацией автор слегка пренебрег. Но форум движка бесценен, там можно найти ответ практически на любой вопрос, да и различных туториалов в интернете достаточно много. Я постараюсь писать ориентируясь именно на новичков, тем более что специалистам эта статья будет не очень интересна.Например, если вы создаете живые обои настоятельно рекомендуется минимизировать потребляемые ресурсы. Оптимизация потребления памяти - отдельная большая тема о которой поговорим в другой раз, а сегодня проделаем достаточно простое и эффективное действо по ограничение количества кадров при рендринге изображения движком.
Обратите внимание, что в конце статьи я опишу краткую пошаговую инструкцию для тех кто не очень хочет читаться полный текст.
Актуальная на данный момент ветка движка - GLES2, то есть версия использующая OpenGL ES 2. На самом деле основа под ограничение количества кадров в самом движке уже присутствует. Предположим что вы уже создали проект, а значит основная Activity (или WallpaperService у вас есть. В GLES2 немного изменился интерфейс родительского класса. В чистом виде имеет несколько наследуемых методов, список которых может отличаться в зависимости от того какой из какого именно класса идет наследование (SimpleBaseGameActivity, BaseGameActivity или BaseLiveWallpaperService).
SimpleBaseGameActivity имеет в девичестве следующий вид:
public class TMActivity extends SimpleBaseGameActivity {
@Override
public EngineOptions onCreateEngineOptions() {
// TODO Auto-generated method stub
return null;
}
@Override
protected void onCreateResources() {
// TODO Auto-generated method stub
}
@Override
protected Scene onCreateScene() {
// TODO Auto-generated method stub
return null;
}
}
BaseGameActivity и BaseLiveWallpaperService немного отличаются:
public class TMActivity extends BaseGameActivity {
@Override
public EngineOptions onCreateEngineOptions() {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreateResources(
OnCreateResourcesCallback pOnCreateResourcesCallback)
throws Exception {
// TODO Auto-generated method stub
}
@Override
public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback)
throws Exception {
// TODO Auto-generated method stub
}
@Override
public void onPopulateScene(Scene pScene,
OnPopulateSceneCallback pOnPopulateSceneCallback) throws Exception {
// TODO Auto-generated method stub
}
}
Обратите внимание на метод public EngineOptions onCreateEngineOptions(). В этом месте мы создаем экземпляр опций движка и возвращаем их родителю. Однако через опции ограничить количество кадров нельзя. В GLES1 мы имели возможность в нашей активности не просто задавать некоторый набор параметров движка, а создавать сам экземпляр класса Engine, что давало немного больше гибкости. Но в GLES2 все то же достаточно просто. Экземпляр Engine создается в родительском классе в отдельном методе onCreateEngine(final EngineOptions pEngineOptions), что дает нам возможность легко подменить его в наследнике (нашем основном классе). Для этого просто добавьте в ваш класс метод (для порядка лучше сразу до или сразу после onCreateEngineOptions(), но очередность методов не принципиальна):
@Override
public org.andengine.engine.Engine onCreateEngine(EngineOptions pEngineOptions) {
Engine engine = new Engine(pEngineOptions);
return engine;
}
Специально для ограничения количества кадров, в движке существует класс LimitedFPSEngine, который является наследником класса Engine. То есть вы можете при создании заменить строку:
Engine engine = new Engine(pEngineOptions);На следующую:
LimitedFPSEngine engine = new LimitedFPSEngine(pEngineOptions, 25);Где 25 это и есть требуемое количество кадров в секунду.
То есть в итоге метод будет выглядеть так:
@OverrideНе забывайте импортировать класс LimitedFPSEngine, нажав Ctrl+Shift+O.
public org.andengine.engine.Engine onCreateEngine(EngineOptions pEngineOptions) {
LimitedFPSEngine engine = new LimitedFPSEngine(pEngineOptions, 25);
return engine;
}
Иногда может потребоваться динамически менять частоту кадров. Создавать engine в процессе работы нельзя, а значит необходимо немного изменить класс LimitedFPSEngine. Что бы не вмешиваться в код движка мы просто сделаем другой класс расширения класса Engine. Создайте в своем проекте класс с названием FlexibleFPSEngine. Замените
public class FlexibleFPSEngine {следующим кодом:
}
import org.andengine.engine.Engine;
import org.andengine.engine.options.EngineOptions;
import org.andengine.util.time.TimeConstants;
public class FlexibleFPSEngine extends Engine {
private long mPreferredFrameLengthNanoseconds;
private int mFramesPerSecond;
public FlexibleFPSEngine(final EngineOptions pEngineOptions, final int pFramesPerSecond) {
super(pEngineOptions);
this.mFramesPerSecond = pFramesPerSecond;
}
@Override
public void onUpdate(final long pNanosecondsElapsed) throws InterruptedException {
this.mPreferredFrameLengthNanoseconds = TimeConstants.NANOSECONDS_PER_SECOND / mFramesPerSecond;
final long preferredFrameLengthNanoseconds = this.mPreferredFrameLengthNanoseconds;
final long deltaFrameLengthNanoseconds = preferredFrameLengthNanoseconds - pNanosecondsElapsed;
if(deltaFrameLengthNanoseconds <= 0) {
super.onUpdate(pNanosecondsElapsed);
} else {
final int sleepTimeMilliseconds = (int) (deltaFrameLengthNanoseconds / TimeConstants.NANOSECONDS_PER_MILLISECOND);
Thread.sleep(sleepTimeMilliseconds);
super.onUpdate(pNanosecondsElapsed + deltaFrameLengthNanoseconds);
}
}
public void setFramesPerSecond (final int pFramesPerSecond) {Теперь при создании экземпляра движка нужно использовать вместо LimitedFPSEngine ваш новый FlexibleFPSEngine. То есть:
mFramesPerSecond = pFramesPerSecond;
}
}
@OverrideДля доступа из других методов необходимо вынести определение переменной engine за пределы метода:
public org.andengine.engine.Engine onCreateEngine(EngineOptions pEngineOptions) {
FlexibleFPSEngine engine = new FlexibleFPSEngine(pEngineOptions);
return engine;
}
FlexibleFPSEngine engine;
@Override
public org.andengine.engine.Engine onCreateEngine(EngineOptions pEngineOptions) {
engine = new FlexibleFPSEngine(pEngineOptions);
return engine;
}
Лучше разместить FlexibleFPSEngine engine; в начале класса, рядом с прочими переменными (что бы не потерять).
Теперь вызвав экземпляр движка мы можем обратиться к его методу setFramesPerSecond(int pFramesPerSecond).
То есть: engine.setFramesPerSecond(37) - задаст ограничение в 37 кадров в секунду.
Краткая инструкция:
1. Создайте в проекте класс FlexibleFPSEngine и скопируйте в него код:import org.andengine.engine.Engine;
import org.andengine.engine.options.EngineOptions;
import org.andengine.util.time.TimeConstants;
public class FlexibleFPSEngine extends Engine {
private long mPreferredFrameLengthNanoseconds;
private int mFramesPerSecond;
public FlexibleFPSEngine(final EngineOptions pEngineOptions, final int pFramesPerSecond) {
super(pEngineOptions);
this.mFramesPerSecond = pFramesPerSecond;
}
@Override
public void onUpdate(final long pNanosecondsElapsed) throws InterruptedException {
this.mPreferredFrameLengthNanoseconds = TimeConstants.NANOSECONDS_PER_SECOND / mFramesPerSecond;
final long preferredFrameLengthNanoseconds = this.mPreferredFrameLengthNanoseconds;
final long deltaFrameLengthNanoseconds = preferredFrameLengthNanoseconds - pNanosecondsElapsed;
if(deltaFrameLengthNanoseconds <= 0) {
super.onUpdate(pNanosecondsElapsed);
} else {
final int sleepTimeMilliseconds = (int) (deltaFrameLengthNanoseconds / TimeConstants.NANOSECONDS_PER_MILLISECOND);
Thread.sleep(sleepTimeMilliseconds);
super.onUpdate(pNanosecondsElapsed + deltaFrameLengthNanoseconds);
}
}
public void setFramesPerSecond (final int pFramesPerSecond) {2. Определите переменную движка FlexibleFPSEngine engine;
mFramesPerSecond = pFramesPerSecond;
}
}
3. В классе сервиса или активности проекта добавьте метод:
@Override4. Теперь вызвав engine.setFramesPerSecond(int p) вы в любой момент сможете изменить ограничение по частоте кадров.
public org.andengine.engine.Engine onCreateEngine(EngineOptions pEngineOptions) {
FlexibleFPSEngine engine = new FlexibleFPSEngine(pEngineOptions);
return engine;
}
Надеюсь что статья была вам полезна.
PS: Как только переедем на новый сайт сразу сделаю в статьях подсветку кода, а пока что страдайте О_О
Комментариев нет:
Отправить комментарий