суббота, 10 марта 2012 г.

Android. AndEngine. Загрузка ресурсов в фоне

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

Первое, что вам нужно сделать, это создать свою собственную реализацию AsyncTask.





Путь, который описан в Android API - это создание AsyncTask с параметром и использование некоторых действий в самом классе. Я предпочитаю, чтобы он был более гибким, поэтому я создал callback функцию, которую будет вызывать  AsyncTask при необходимости. Таким образом:


public interface IAsyncCallback {
    // ===========================================================
    // Методы
    // ===========================================================
 
    public abstract void workToDo();
 
    public abstract void onComplete();
 
}
Затем я создаю свой подкласс AsyncTask:

import android.os.AsyncTask;
 
public class AsyncTaskLoader extends AsyncTask<IAsyncCallback, Integer, Boolean> {
 
    // ===========================================================
    // Свойства
    // ===========================================================
 
    IAsyncCallback[] _params;
 
    // ===========================================================
    // Наследуемые методы
    // ===========================================================
 
    @Override
    protected Boolean doInBackground(IAsyncCallback... params) {
        this._params = params;
        int count = params.length;
        for(int i = 0; i < count; i++){
            params[i].workToDo();
        }
        return true;
    }
 
    @Override
    protected void onPostExecute(Boolean result) {
        int count = this._params.length;
        for(int i = 0; i < count; i++){
            this._params[i].onComplete();
        }
    }
}


Итак, теперь у меня есть AsyncTask готовый сделать то что я захочу

Вот моя загрузка Activity:

import static org.anddev.andengine.extension.physics.box2d.util.constants.PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT;
 
import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.Camera;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.extension.physics.box2d.FixedStepPhysicsWorld;
import org.anddev.andengine.extension.physics.box2d.PhysicsConnector;
import org.anddev.andengine.extension.physics.box2d.PhysicsFactory;
import org.anddev.andengine.extension.physics.box2d.PhysicsWorld;
import org.anddev.andengine.opengl.texture.Texture;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.opengl.texture.region.TextureRegionFactory;
import org.anddev.andengine.ui.activity.BaseGameActivity;
 
import android.view.Display;
import android.widget.RelativeLayout;
 
import com.adwhirl.AdWhirlLayout;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.revstudios.codestores.AsyncTaskLoader;
import com.revstudios.codestores.IAsyncCallback;
 
/**
 * Written by Tyler Reid of Studio Reveries.
 * 
 * All work provided can be modified and used freely so long as this statement stays in the source code.
 * 
 * 
 * @author Tyler Reid @ www.studioreveries.com
 *
 */
public abstract class LoadingGameActivity extends BaseGameActivity {
 
 // ===========================================================
 // Свойства
 // ===========================================================
 
 protected Engine engine;
 protected PhysicsWorld physEngine;
 
 private Texture loadScreenBGTexture;
 private TextureRegion loadScreenBGRegion;
 
 private Texture carTexture;
 private TextureRegion carRegion;
 
 private ArrayList<Body> loadingBodies = new ArrayList<Body>();
 
 // ===========================================================
 // Константы
 // ===========================================================
 
 protected static final float CAMERA_WIDTH = 320, CAMERA_HEIGHT = 480;
 protected static final int AD_SIZE_Y = 50;
 protected static final int PHYSICS_TIME_STEP = 60;
 
 
 // ===========================================================
 // Наследуемые методы
 // ===========================================================
 
 @Override
 public Engine onLoadEngine() {
  Camera camera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
  return engine = new Engine(new EngineOptions(true, ScreenOrientation.PORTRAIT, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), camera));
 }
 
 @Override
 public void onLoadResources() {
  TextureRegionFactory.setAssetBasePath("gfx/load/");
 
  loadScreenBGTexture = new Texture(512, 256, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
  loadScreenBGRegion = TextureRegionFactory.createFromAsset(loadScreenBGTexture, this, "logo.png", 0, 0);
 
  carTexture = new Texture(128,128);
  carRegion = TextureRegionFactory.createFromAsset(carTexture, this, "car.png", 0, 0);
 
 
  engine.getTextureManager().loadTextures(loadScreenBGTexture, carTexture);
 }
 
 /**
   * Здесь вы можете создать свой экран загрузки. Я создал свой мир физики 
     * чтобы продемонстрировать что вы можете сделать тут.
   */
 @Override
 public Scene onLoadScene() {
  Scene scene = new Scene(1);
  //scene.setBackground(new ColorBackground(10, 200, 10));
 
  physEngine = new FixedStepPhysicsWorld((int)PHYSICS_TIME_STEP, new Vector2(0, 0), false);
  scene.registerUpdateHandler(physEngine);
 
  // отображаем логотип загрузки
  Sprite s = new Sprite(100, 100, loadScreenBGRegion);
  s.setPosition((CAMERA_WIDTH / 2) - (s.getWidthScaled() / 2), (CAMERA_HEIGHT / 3) - (s.getHeightScaled() / 2));
  scene.getBottomLayer().addEntity(s);
 
  // car fixturedef
  FixtureDef carDef = PhysicsFactory.createFixtureDef(1, 3, 0);
 
  // create initial car
  Sprite queCar = new Sprite((CAMERA_WIDTH / 5) * 1, (CAMERA_HEIGHT / 3) * 2, carRegion);
  scene.getTopLayer().addEntity(queCar);
 
  Body queCarBody = PhysicsFactory.createCircleBody(physEngine, queCar, BodyType.DynamicBody, carDef);
  queCarBody.CollisionType = TrafConst.CollisionMisc;
 
  physEngine.registerPhysicsConnector(new PhysicsConnector(queCar, queCarBody));
 
  // create second car
  Sprite ballCar = new Sprite((CAMERA_WIDTH / 5) * 3, (CAMERA_HEIGHT / 3) * 2, carRegion);
  scene.getTopLayer().addEntity(ballCar);
 
  Body ballCarBody = PhysicsFactory.createCircleBody(physEngine, ballCar, BodyType.DynamicBody, carDef);
  ballCarBody.CollisionType = TrafConst.CollisionMisc;
 
  physEngine.registerPhysicsConnector(new PhysicsConnector(ballCar, ballCarBody));
 
  // impulse que car
  queCarBody.setLinearVelocity(new Vector2(100 / PIXEL_TO_METER_RATIO_DEFAULT,0));
 
  /*
   * Это вызывается когда все ресурсы будут загружены в фоне
   */
  IAsyncCallback callback = new IAsyncCallback() {
 
   @Override
   public void workToDo() {
    assetsToLoad();
   }
 
   @Override
   public void onComplete() {
    unloadLoadingScene();
    engine.setScene(onAssetsLoaded());
   }
  };
 
  new AsyncTaskLoader().execute(callback);
 
  return scene;
 }
 
 // ===========================================================
 // Методы
 // ===========================================================
 
 private void unloadLoadingScene(){
 
 }
 
 /**
  * Это вызывается после того как все asyc ресурсы загружены
  * Загрузчик будет отвечать за изменения сцены.
  */
 protected abstract Scene onAssetsLoaded();
 
 
 /**
  * Это вызывается когда ресурсы должны быть загружены в фоне.
  */
 protected abstract void assetsToLoad();
 
}
Это будет базовая активити для любой, имеющей много ресурсов, которые должны быть предварительно загружены (либо подгружаются при отображении экрана загрузки).

Вот простой пример активити, которая позволяет расширить данную. Есть ряд важных особенностей, которые освещены в комментариях. Читайте внимательно.

import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.extension.physics.box2d.FixedStepPhysicsWorld;
import org.anddev.andengine.opengl.texture.Texture;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.opengl.texture.region.TextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
 
import com.badlogic.gdx.math.Vector2;
import com.revstuidios.trafficjam.LayoutLoadingGameActivity;
import com.revstuidios.trafficjam.PedalHUD;
import com.revstuidios.trafficjam.PedalHUD.IPedalListener;
import com.revstuidios.trafficjam.sprites.PlayerCarSprite;
 
public class GameActivity extends LayoutLoadingGameActivity {
 
 // ===========================================================
 // Свойства
 // ===========================================================
 
 Texture playerTexture;
 TiledTextureRegion playerTiledRegion;
 
 Texture hudTexture;
 TextureRegion brakeRegion, gasRegion, bgRegion;
 
 PlayerCarSprite Player;
 
 
 // ===========================================================
 // Константы
 // ===========================================================
 
 // ===========================================================
 // Наследуемые методы
 // ===========================================================
 
 @Override
 public Engine onLoadEngine() {
  // Это необходимая заглушка! Если здесь этого не будет, ваш экран загрузки не будет работать
  // This is all you will ever put in to your loading activity.
  return super.onLoadEngine();
 }
 
 @Override
 public void onLoadResources() {
  // Это необходимая заглушка! Если здесь этого не будет, ваш экран загрузки не будет работать
  // This is all you will ever put in to your loading activity.
  super.onLoadResources();
 }
 
 @Override
 public Scene onLoadScene() {
  // Это необходимая заглушка! Если здесь этого не будет, ваш экран загрузки не будет работать
  // This is all you will ever put in to your loading activity.
  return super.onLoadScene();
 }
 
 @Override
 public void onLoadComplete() {
  // Ничего здесь не помещайте
 }
 
 @Override
 protected Scene onAssetsLoaded() {
  // Здесь вы можете написать все, что вы обычно помещаете в onLoadScene.
  // Это вызывается когда все ресурсы будут загружены
  Scene scene = new Scene(3);
 
  Sprite x = new Sprite(100,100, brakeRegion);
  scene.getBottomLayer().addEntity(x);
 
  return scene;
 }
 
 @Override
 protected void assetsToLoad() {
  // здесь вы загружаете любые ресурсы, которые вы хотите грузить в фоне.
 
  TextureRegionFactory.setAssetBasePath("gfx/game/");
 
  playerTexture = new Texture(64,128);
  playerTiledRegion = TextureRegionFactory.createTiledFromAsset(playerTexture, this, "car.png", 0, 0, 2, 2);
 
  hudTexture = new Texture(512,128);
  bgRegion = TextureRegionFactory.createFromAsset(hudTexture, this, "pedalsBG.png", 0, 0);
  brakeRegion = TextureRegionFactory.createFromAsset(hudTexture, this, "brake.png", 341, 0);
  gasRegion = TextureRegionFactory.createFromAsset(hudTexture, this, "gas.png", 399, 0);
 
  engine.getTextureManager().loadTextures(playerTexture, hudTexture);
 }
 
 // ===========================================================
 // Методы
 // ===========================================================
}

Чтобы использовать данный код, просто создайте свою активити. Экран загрузки будет отображаться автоматически. Будет запускаться onAssetsLoaded() и возвращаемая им сцена станет основной.

Комментариев нет: