В сегодняшней "лекции" пойдет разбор как сделать живые обои они же (LiveWallpaper) на движке Andengine GLES2, ну т.е. на OpenGL 2. Я с трудом нашел рабочий пример на форуме andengine, да и то после того как написал свой :)
Итак, я почти уверен что сам AndEngine у Вас уже стоит, причем свежайшая версия. Потому что ветка правится каждый день. Помимо него, нужно еще расширение AndEngineWallpaperExtension. Т.е. скачиваем, распаковываем, кладем в наш workspace для Eclipse, в самом эклипсе делаем Import->Exiting Projects into Workspace, выбираем сначала один, потом второй каталог.
Возможно, придется обновить SDK до последних версий.
Теперь создаем проект под названием LiveWallpaperService, в Properties->Android->Library добавляем AndEngine и AndEngineWallpaperExtension. Проект готов. Главная активити у нас должна наследоваться от BaseLiveWallpaperService, т.е. болванка выглядит следующим образом:
За основу я взял проект GLES1 http://code.google.com/p/andenginelivewallpaperextensionexample/. Оттуда можно взять картинки и положить их в каталог /assets/gfx
Правим файл /res/values/strings.xml:
Добавляем файл /res/xml/wallpaper.xml:
Здесь тоже надеюсь всё понятно.
И правим AndroidManifest.xml, приводим его к следующему виду:
Да, в каталог /res/drawable не забываем добавить превьюшку обоев, которая будет отображаться в списке :). Подготовка на этом закончена, возвращаемся к LiveWallpaperService.java.
Как обычно, (если вы уже сделали HelloWorld на AndEngine), создаем камеру и Engine в методе onCreateEngineOptions:
и подгрузим картинки в onCreateResources:
Все вроде откомментировано и понятно. Единственное, наше приложение будет реагировать на датчик положения, поэтому нужно добавить интерфейс IAccelerationListener в объявление класса, чтобы наше приложение реагировало на акселерометр. И соответственно создадутся заглушки на два новых метода - onAccelerationAccuracyChanged и onAccelerationChanged.
В конце вызывается метод onCreateResourcesFinished(), что говорит приложению об окончательной загрузке ресурсов.
Переходим к созданию сцены, правим метод onCreateScene:
Сначала считаем координаты спрайтов относительно экрана, аттачим их к сцене. Создаем SpriteParticleSyste - "генератор дыма". В функции обратного вызова возвращаем готовую сцену.
Осталось только написать обработчик для акселерометра. Оформляем метод следующим образом:
Тут по движению акселерометра изменяется скорость частиц в mVelocityInitializer.
Общий код приложения
Итак, я почти уверен что сам AndEngine у Вас уже стоит, причем свежайшая версия. Потому что ветка правится каждый день. Помимо него, нужно еще расширение AndEngineWallpaperExtension. Т.е. скачиваем, распаковываем, кладем в наш workspace для Eclipse, в самом эклипсе делаем Import->Exiting Projects into Workspace, выбираем сначала один, потом второй каталог.
Возможно, придется обновить SDK до последних версий.
Теперь создаем проект под названием LiveWallpaperService, в Properties->Android->Library добавляем AndEngine и AndEngineWallpaperExtension. Проект готов. Главная активити у нас должна наследоваться от BaseLiveWallpaperService, т.е. болванка выглядит следующим образом:
public class LiveWallpaperService extends BaseLiveWallpaperService { @Override public EngineOptions onCreateEngineOptions() { } @Override public void onCreateResources( OnCreateResourcesCallback pOnCreateResourcesCallback) throws Exception { } @Override public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback) throws Exception { } @Override public void onPopulateScene(Scene pScene, OnPopulateSceneCallback pOnPopulateSceneCallback) throws Exception { } @Override public void onAccelerationAccuracyChanged(AccelerationData pAccelerationData) { } }
За основу я взял проект GLES1 http://code.google.com/p/andenginelivewallpaperextensionexample/. Оттуда можно взять картинки и положить их в каталог /assets/gfx
Правим файл /res/values/strings.xml:
Я думаю тут всё понятно. Вторая и третья строка - соответственно название и дескрипшн, которые будут отображаться в списке живых обоев.Cigarette Live-Wallpaper Cigarette Live-Wallpaper A cigarette smoking on your home-screen.
Добавляем файл /res/xml/wallpaper.xml:
Здесь тоже надеюсь всё понятно.
И правим AndroidManifest.xml, приводим его к следующему виду:
Да, в каталог /res/drawable не забываем добавить превьюшку обоев, которая будет отображаться в списке :). Подготовка на этом закончена, возвращаемся к LiveWallpaperService.java.
Как обычно, (если вы уже сделали HelloWorld на AndEngine), создаем камеру и Engine в методе onCreateEngineOptions:
@Override public EngineOptions onCreateEngineOptions() { mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT); return new EngineOptions( true , mScreenOrientation , new FillResolutionPolicy() , mCamera ); }
и подгрузим картинки в onCreateResources:
@Override public void onCreateResources( OnCreateResourcesCallback pOnCreateResourcesCallback) throws Exception { // каталог, откуда берем все картинки BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/"); // подготовка атласа mTexture = new BitmapTextureAtlas( getTextureManager() , 512 , 128 , TextureOptions.BILINEAR_PREMULTIPLYALPHA ); // установка положения текстур в атласе this.mCigaretteTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mTexture, this, "cigarette.png", 0, 0); // 400x120 this.mSmokeTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mTexture, this, "smoke.png", 381, 0); // 64x64 // загрузка текстур в атлас mTexture.load(); // включаем акселерометр this.enableAccelerationSensor(this); pOnCreateResourcesCallback.onCreateResourcesFinished();
Все вроде откомментировано и понятно. Единственное, наше приложение будет реагировать на датчик положения, поэтому нужно добавить интерфейс IAccelerationListener в объявление класса, чтобы наше приложение реагировало на акселерометр. И соответственно создадутся заглушки на два новых метода - onAccelerationAccuracyChanged и onAccelerationChanged.
В конце вызывается метод onCreateResourcesFinished(), что говорит приложению об окончательной загрузке ресурсов.
Переходим к созданию сцены, правим метод onCreateScene:
@Override public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback) throws Exception { // сцена mScene = new Scene(); // координаты левого верхнего угла спрайта сигареты final int cigaretteX = 0; final int cigaretteY = CAMERA_HEIGHT - (int)this.mCigaretteTextureRegion.getHeight(); // координаты левого верхнего угла спрайта дыма final int smokeX = cigaretteX + (int)this.mCigaretteTextureRegion.getWidth() - 100; final int smokeY = cigaretteY - 25; // создаем спрайты сигареты, дыма final Sprite sigarette = new Sprite(cigaretteX, cigaretteY, this.mCigaretteTextureRegion, this.getVertexBufferObjectManager()); final Sprite smoke = new Sprite(smokeX, smokeY, this.mSmokeTextureRegion, this.getVertexBufferObjectManager()); // добавляем слои сигареты и дыма на сцену mScene.attachChild(sigarette); mScene.attachChild(smoke); // генератор частиц final SpriteParticleSystem particleSystem = new SpriteParticleSystem( new PointParticleEmitter(smokeX, smokeY) // Particle Emitter. Координаты генератора частиц , 6 // минимальная частота , 8 // максимальная частота , 150 // максимум частиц , this.mSmokeTextureRegion // текстура дыма , this.getVertexBufferObjectManager() ); // скорость частиц mVelocityInitializer = new VelocityParticleInitializer( -20 // min X , 20 // max X , -100 // min Y , -120 // max Y ); particleSystem.addParticleInitializer(mVelocityInitializer); // прозрачность частиц particleSystem.addParticleModifier( new AlphaParticleModifier( 1f // from time , 0f // to time , 0f // from alfa , 10f // to alfa )); mScene.attachChild(particleSystem); pOnCreateSceneCallback.onCreateSceneFinished(mScene); }
Сначала считаем координаты спрайтов относительно экрана, аттачим их к сцене. Создаем SpriteParticleSyste - "генератор дыма". В функции обратного вызова возвращаем готовую сцену.
Осталось только написать обработчик для акселерометра. Оформляем метод следующим образом:
@Override public void onAccelerationChanged(AccelerationData pAccelerationData) { final float minVelocityX = (pAccelerationData.getX() + 2) * 5; final float maxVelocityX = (pAccelerationData.getX() - 2) * 5; final float minVelocityY = (pAccelerationData.getY() - 8) * 10; final float maxVelocityY = (pAccelerationData.getY() - 10) * 10; this.mVelocityInitializer.setVelocity(minVelocityX, maxVelocityX, minVelocityY, maxVelocityY); }
Тут по движению акселерометра изменяется скорость частиц в mVelocityInitializer.
package com.osmsoft.lws; import org.andengine.engine.camera.Camera; import org.andengine.engine.options.EngineOptions; import org.andengine.engine.options.EngineOptions.ScreenOrientation; import org.andengine.engine.options.resolutionpolicy.FillResolutionPolicy; import org.andengine.entity.particle.SpriteParticleSystem; import org.andengine.entity.scene.Scene; import org.andengine.entity.sprite.Sprite; import org.andengine.extension.ui.livewallpaper.BaseLiveWallpaperService; import org.andengine.opengl.texture.TextureOptions; import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas; import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory; import org.andengine.opengl.texture.region.ITextureRegion; import org.andengine.input.sensor.acceleration.AccelerationData; import org.andengine.input.sensor.acceleration.IAccelerationListener; import org.andengine.entity.particle.emitter.PointParticleEmitter; import org.andengine.entity.particle.initializer.VelocityParticleInitializer; import org.andengine.entity.particle.modifier.AlphaParticleModifier; public class LiveWallpaperService extends BaseLiveWallpaperService implements IAccelerationListener { private static final int CAMERA_WIDTH = 800; private static final int CAMERA_HEIGHT = 480; private static final int LAYER_SMOKE = 1; private static final int LAYER_CIGARETTE = 0; public static Camera mCamera; private BitmapTextureAtlas mTexture; private ScreenOrientation mScreenOrientation; private VelocityParticleInitializer mVelocityInitializer; private Scene mScene; private ITextureRegion mSmokeTextureRegion; private ITextureRegion mCigaretteTextureRegion; @Override public EngineOptions onCreateEngineOptions() { mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT); return new EngineOptions( true , mScreenOrientation , new FillResolutionPolicy() , mCamera ); } @Override public void onCreateResources( OnCreateResourcesCallback pOnCreateResourcesCallback) throws Exception { // каталог, откуда берем все картинки BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/"); // подготовка атласа mTexture = new BitmapTextureAtlas( getTextureManager() , 512 , 128 , TextureOptions.BILINEAR_PREMULTIPLYALPHA ); // установка положения текстур в атласе this.mCigaretteTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mTexture, this, "cigarette.png", 0, 0); // 400x120 this.mSmokeTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mTexture, this, "smoke.png", 381, 0); // 64x64 // загрузка текстур в атлас mTexture.load(); // включаем акселерометр this.enableAccelerationSensor(this); pOnCreateResourcesCallback.onCreateResourcesFinished(); } @Override public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback) throws Exception { // сцена mScene = new Scene(); // координаты левого верхнего угла спрайта сигареты final int cigaretteX = 0; final int cigaretteY = CAMERA_HEIGHT - (int)this.mCigaretteTextureRegion.getHeight(); // координаты левого верхнего угла спрайта дыма final int smokeX = cigaretteX + (int)this.mCigaretteTextureRegion.getWidth() - 100; final int smokeY = cigaretteY - 25; // создаем спрайты сигареты, дыма final Sprite sigarette = new Sprite(cigaretteX, cigaretteY, this.mCigaretteTextureRegion, this.getVertexBufferObjectManager()); final Sprite smoke = new Sprite(smokeX, smokeY, this.mSmokeTextureRegion, this.getVertexBufferObjectManager()); // добавляем слои сигареты и дыма на сцену mScene.attachChild(sigarette); mScene.attachChild(smoke); // генератор частиц final SpriteParticleSystem particleSystem = new SpriteParticleSystem( new PointParticleEmitter(smokeX, smokeY) // Particle Emitter. Координаты генератора частиц , 6 // минимальная частота , 8 // максимальная частота , 150 // максимум частиц , this.mSmokeTextureRegion // текстура дыма , this.getVertexBufferObjectManager() ); // скорость частиц mVelocityInitializer = new VelocityParticleInitializer( -20 // min X , 20 // max X , -100 // min Y , -120 // max Y ); particleSystem.addParticleInitializer(mVelocityInitializer); // прозрачность частиц particleSystem.addParticleModifier( new AlphaParticleModifier( 1f // from time , 0f // to time , 0f // from alfa , 10f // to alfa )); mScene.attachChild(particleSystem); pOnCreateSceneCallback.onCreateSceneFinished(mScene); } @Override public void onPopulateScene(Scene pScene, OnPopulateSceneCallback pOnPopulateSceneCallback) throws Exception { pOnPopulateSceneCallback.onPopulateSceneFinished(); } @Override public void onAccelerationAccuracyChanged(AccelerationData pAccelerationData) { // TODO Auto-generated method stub } @Override public void onAccelerationChanged(AccelerationData pAccelerationData) { final float minVelocityX = (pAccelerationData.getX() + 2) * 5; final float maxVelocityX = (pAccelerationData.getX() - 2) * 5; final float minVelocityY = (pAccelerationData.getY() - 8) * 10; final float maxVelocityY = (pAccelerationData.getY() - 10) * 10; this.mVelocityInitializer.setVelocity(minVelocityX, maxVelocityX, minVelocityY, maxVelocityY); } }
Ссылки по теме:
http://www.andengine.org/forums/live-wallpaper-extension/ - форум по расширению
http://www.andengine.org/forums/post32197.html - болванка для livewallpaper
http://www.andengine.org/forums/gles2/no-particle-system-examples-t6159.html?p27526 - Еще какие-то обои
1 комментарий:
хорошо бы было на исходник посмотреть!) спасибо за урок!
Отправить комментарий