Дек
12

AndEngine. Экран загрузки (Preloader)

logo_100

Как и во флэш играх, на Андроиде тоже принято делать экран загрузки.

 

Когда загрузка ресурсов игры занимает много времени, экран загрузки (Прелоадер) просто необходим.

Сделать его очень просто. Вот алгоритм:

1. Запускаем движок как обычно: Создаём активити, создаём движок, создаём сцену.

2. Во время загрузки ресурсов (метод onLoadResources) загружаем в Атлас картинку, которую будем показывать на экране, пока у нас грузятся другие ресурсы.

3. Как только движок запустится, то в методе onLoadScene или onLoadComplete запускаем в отдельном асинхронном потоке загрузку ресурсов игры. По окончании загрузки убираем картинку-прелоадер с экрана и запускаем игру.

А вот и код (я взял из своей игры):

package com.drderico.cheepers.full;

import java.util.HashMap;
import java.util.List;

import javax.microedition.khronos.opengles.GL10;

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.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.opengl.util.GLHelper;
import org.anddev.andengine.ui.activity.BaseGameActivity;

import android.os.Bundle;
import android.view.KeyEvent;
import android.widget.Toast;

import com.heyzap.sdk.HeyzapLib;
import com.openfeint.api.OpenFeint;
import com.openfeint.api.OpenFeintDelegate;
import com.openfeint.api.OpenFeintSettings;
import com.openfeint.api.resource.Leaderboard;

public class Main extends BaseGameActivity {

	public static Camera mCamera;

	//Scenes
	public static MainState _MainState;
	private static Scene PreloaderScene;

	private static BitmapTextureAtlas Preloader_Texture;
	private static TextureRegion Preloader_TR;
	private static Sprite Preloader_Sp;

	private static boolean GameLoaded = false;

	public static Engine thisEngine;

	@Override
	protected void onCreate(final Bundle pSavedInstanceState) {

		super.onCreate(pSavedInstanceState);

	}

	@Override
	public Engine onLoadEngine() {
		mCamera = new Camera(0, 0, CommonValues.CAMERA_WIDTH, CommonValues.CAMERA_HEIGHT);
		return new Engine(new EngineOptions(true, ScreenOrientation.PORTRAIT, new RatioResolutionPolicy(CommonValues.CAMERA_WIDTH, CommonValues.CAMERA_HEIGHT), mCamera).setNeedsSound(true).setNeedsMusic(true));
	}

	@Override
	public void onLoadResources() {

		thisEngine = this.mEngine;
		thisEngine.enableVibrator(this);

		BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
		Preloader_Texture = new BitmapTextureAtlas(512, 1024, TextureOptions.DEFAULT);
		Preloader_TR = BitmapTextureAtlasTextureRegionFactory.createFromAsset(Preloader_Texture, Main.this, "menu/loading_scr.jpg", 0, 0);
		thisEngine.getTextureManager().loadTextures(Preloader_Texture);
	}

	public Scene onLoadScene() {

		PreloaderScene = new Scene();
		PreloaderScene.setIgnoreUpdate(true);
		Preloader_Sp = new Sprite(0, 0, Preloader_TR);
		PreloaderScene.attachChild(Preloader_Sp);

		GameLoaded = false;

		/**
		 * Показываем экран ожидания загрузки игры.
		 * В Асинхронном задании запускаем загрузку ресурсов
		 * и ждём окончания этого задания
		 */

		IAsyncCallback callback = new IAsyncCallback() {

            @Override
            public void workToDo() {
            	Textures.LoadTextures(Main.this);

            }

            @Override
            public void onComplete() {
            	GameLoaded();
            }
        };
        //Исправленный вариант. Работает в GLES1 и GLES2
        runOnUiThread(new Runnable() {
		@Override
		public void run() {
			new AsyncTaskLoader().execute(callback);
		}
        });
        //Старый вариант. Не работает в GLES2
        //new AsyncTaskLoader().execute(callback);

		return PreloaderScene;
	}

	/**
	 * Ресурсы загрузились. Убираем сплэш, запускаем игру
	 */
	protected void GameLoaded() {
		GameLoaded = true;

		_MainState = new MainState(Main.this);
		mEngine.setScene(_MainState);

		PreloaderScene = null;
		thisEngine.getTextureManager().unloadTextures(Preloader_Texture);
		Preloader_Texture = null;
		Preloader_Sp = null;

		_MainState.ShowMainScreen();
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK)
		{
			if (_MainState != null) {
				_MainState.onKeyDown(keyCode, event);
				return true;
			}
		}

	    return super.onKeyDown(keyCode, event);
	}

	@Override
	public void onLoadComplete() {
	}

	@Override
	public void onPauseGame() {
		super.onPauseGame();
		if (!GameLoaded) return;
		if (_MainState != null) _MainState.PauseGame();

	}

	@Override
	public void onResumeGame() {
		super.onResumeGame();
		if (!GameLoaded) return;
		if (_MainState != null) _MainState.UnPauseGame();
	}
}

Интерфейс IAsyncCallback:

package com.drderico.cheepers.full;

public interface IAsyncCallback {
    // ===========================================================
    // Methods
    // ===========================================================

    public abstract void workToDo();

    public abstract void onComplete();
}

Класс AsyncTaskLoader:

package com.drderico.cheepers.full;

import android.os.AsyncTask;

public class AsyncTaskLoader extends AsyncTask<IAsyncCallback, Integer, Boolean> {

    // ===========================================================
    // Fields
    // ===========================================================

    IAsyncCallback[] _params;

    // ===========================================================
    // Inherited Methods
    // ===========================================================

    @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();
        }
    }
}



6 коммент. к записи “AndEngine. Экран загрузки (Preloader)”

  • А что такое _MainState = new MainState (Main.this);

    и Textures.LoadTextures (Main.this);

    • _MainState — это моя главная сцена (Scene).

      Textures.LoadTextures (Main.this) — метод в классе Textures, в котором происходит загрузка ресурсов

  • А для GLES2 этот метод работает? А то у меня не грузяться текстуры в отдельном потоке.

  • Так можно было бы использовать простой поток:

    Thread background = new Thread (new Runnable () {

    public void run () {

    Textures.loadTextures ();

    GameLoaded ();

    }

    });

    background.start ();

    вместо:

    IAsyncCallback callback = new IAsyncCallback () {

    @Override

    public void workToDo () {

    Textures.LoadTextures (Main.this);

    }

    @Override

    public void onComplete () {

    GameLoaded ();

    }

    };

    new AsyncTaskLoader ().execute (callback);

    Или нет?

    • Наверно можно. Я уже не помню, почему использовал IAsyncCallback. Если Thread работает, то пусть остаётся 🙂

Прокомментировать



ЗАДАЙ СВОЙ ВОПРОС