воскресенье, 22 апреля 2012 г.

(АРХИВ GLES1) Создание спрайта. Перетаскивание вручную. Акселерометр.

Вашему вниманию предлагается следующий код.
На черном фоне создается спрайт (картинка-самолетик). Этот спрайт можно двигать пальцем по экрану. Так же он связан с акселерометром. Если наклонить аппарат влево, то самолетик на экране движется влево. Чем сильнее наклоняешь - тем  быстрее движется.

package ru.sapfil.andengine.test1;
 
import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.ZoomCamera;
import org.anddev.andengine.engine.handler.IUpdateHandler;
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.entity.util.FPSLogger;
import org.anddev.andengine.input.touch.TouchEvent;
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.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;

/** пример работы с движком andengine
 * на экране создается 1 спрайт методами движка
 * спрайт предвигается акселерометром
 * так же спрайт можно двигать перетаскиванием
 * @author Sapfil
 * @link русскоязычный тутор по выводу анимированного спрайта на экран
 * http://korzh.net/2011-04-andengine.-pervyj-opyt.html
 * @link основной список туторов на форуме andengine  
 * http://www.andengine.org/forums/tutorials/mimminito-s-tutorial-list-t417.html
 * @link тутор по использованию акселерометра  
 * http://www.andengine.org/forums/post30254.html?hilit=accelerometer#p30254
 * @link мой ЖЖ-блог
 * http://sapfil-proger.livejournal.com/6779.html
 */
public class AE_Test1_Activity extends BaseGameActivity implements SensorEventListener {
 
 // размеры окна отображения
 static final int CAMERA_WIDTH = 320;
 static final int CAMERA_HEIGHT = 480;  
 // класс Camera определяет текущую область видимости на экране
 private ZoomCamera mCamera;
 //Хранение текстуры в памяти.
 private Texture mTexture;
 //Координаты нужной части текстуры для спрайта
 private TextureRegion mSpriteTextureRegion;
 //спрайт 
 Sprite mSprite;
 //Управление сенсорами
 private SensorManager sensorManager;
 // текущие состояния акселерометра;
 private int accellerometerSpeedX;
    private int accellerometerSpeedY;
    // текущие координаты спрайта;
    private int sX, sY;

/** Первая функция загрузки движка - создание объекта Engine
 * При создании задаются опции движка - EngineOptions
 */
//@Override
public Engine onLoadEngine() { 
 //Создадим новый объект камеры, с размерами нашего экрана.
 this.mCamera = new ZoomCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
 //Класс RatioResolutionPolicy отвечает за пропорции ширины и высоты экрана.
 //Чтобы пропорции соответствовали нашему экрану, в качестве параметров введем размеры экрана.
 RatioResolutionPolicy Resolution = new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT);
 //Класс EngineOptions является хранилищем настроек для основного класса движка Engine.
 //Первый параметр равен конструктора pFullscreen = true,
 //выставляем таким образом полноэкранный режим.
 //Второй параметр - ориентация экрана, будем использовать ландшафный режим.
 //Третий параметр - пропорции экрана, мы его инициализировали выше.
 //Последний четвертый параметр - наша камера.
 EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.PORTRAIT, Resolution, this.mCamera);
 //в результате, нам необходимо вернуть объект класса Engine,
 //параметром конструктора класса являются настройки.
 return new Engine(engineOptions);
}
 
/** вторая функция - загрузка ресурсов
 * Здесь мы загружаем текстуры(картинки), звуки и прочие внешине файлы
 */
//@Override
public void onLoadResources() {
 //Создаем текстуру размерами 64*64
 //Обратите внимание, каждый размер текстуры должен равняться значению 2 в n-ой степени!
 this.mTexture = new Texture(64, 64, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
 //Установим путь по умолчанию для файлов
 TextureRegionFactory.setAssetBasePath("gfx/");
 //Загружаем графические данные из файла.
 //Первый параметр - наша текстура.
 //Второй - текущий контекст, ресурсы из нашего приложения.
 //Третий параметр - имя файла.
 //Четвертый и пятый - начальные координаты хранения графики в текстуре.
 // (Для анимации): Шестой и седьмой - количество кадров по горизонтали и вертикали соответственно 
    this.mSpriteTextureRegion = TextureRegionFactory.createFromAsset(this.mTexture, this, "ship.png", 0, 0);
    //Загружаем текстурy
    this.mEngine.getTextureManager().loadTexture(this.mTexture); 
}
 
/** третья функция - создание сцены */
//@Override
public Scene onLoadScene() {
 //Создаем объект класса Scene. Это и есть наш хранитель всей отображаемой графической информации,
 //такой как спрайты, шрифты, линии, прямоугольники и т.п.
 final Scene mScene = new Scene(1);
 // 1 в скобочках - количество слове в сцене
 return mScene;
}

//@Override
public void onLoadComplete() {
 // объявление и последующая регистрация акселерометра
  sensorManager = (SensorManager) this.getSystemService(Context.SENSOR_SERVICE); 
  sensorManager.registerListener(this, sensorManager
             .getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
             SensorManager.SENSOR_DELAY_GAME); 
 //Добавляем спрайт на сцену
 sX = (CAMERA_WIDTH - this.mSpriteTextureRegion.getWidth()) / 2;
 sY = (CAMERA_HEIGHT - this.mSpriteTextureRegion.getHeight()) / 2;
 createSprite(sX, sY);
 
 // дебаг-регистратор ФПС (я пока с ним не разобрался)
 this.mEngine.registerUpdateHandler(new FPSLogger()
 {
  public void onUpdate(float pSecondsElapsed) {
   // TODO Auto-generated method stub
  }
 });
 /** ***********************************************************
  * ОСНОВНОЙ ЦИКЛ ИГРЫ!!!
  ************************************************************ */
 // основной цикл игры!
    this.mEngine.registerUpdateHandler(new IUpdateHandler() {
      public void onUpdate(float pSecondsElapsed) {           
                    updateSpritePosition();
            }
            public void reset() {
                    // TODO Auto-generated method stub
            }
    });
}

/**
 * Создание спрайта в заданной точке X,Y
 */
private void createSprite(float x, float y) {
  
  // создаем спрайт по координатам и текстурной области
        this.mSprite = new Sprite(x, y, this.mSpriteTextureRegion)
        {
         // функция перемещения спрайта вручную (перетягивание пальцем)
         @Override
            public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
                            float pTouchAreaLocalX, float pTouchAreaLocalY)
            {
          sX = (int) (pSceneTouchEvent.getX() - this.getWidth()/2);
          sY = (int) (pSceneTouchEvent.getY() - this.getHeight()/2);
          mSprite.setPosition(sX, sY);
          return true;
            }
         
        };        
        
        // регистрируем область, реагирущую на касания (для перетягивания спрайта вручную)
        this.mEngine.getScene().registerTouchArea(this.mSprite);       
        // добавляем спрайт в сцену
        // getScene - получить сцену нашего движка
        // getLastChild - получить последний слой сцены
        // attachChild - добавить в полученный слой то что в скобках (this.mSprite) - наш спрайт
        this.mEngine.getScene().getLastChild().attachChild(this.mSprite);
}

// обработка данных с акселерометра
public void onSensorChanged(SensorEvent event) {
    synchronized (this) {
            switch (event.sensor.getType()) {
            case Sensor.TYPE_ACCELEROMETER:
                    accellerometerSpeedX = (int) event.values[1];
                    accellerometerSpeedY = (int) event.values[0];
                    break;
            }
    }
}

// тоже какие-то данные с акселерометра - пока не разобрался
public void onAccuracyChanged(Sensor sensor, int accuracy) {
    //
}

// функция движения спрайта в зависимости от данных с акселерометра
private void updateSpritePosition() {
    if ((accellerometerSpeedX != 0) || (accellerometerSpeedY != 0)) {
            // Set the Boundary limits
            int tL = 0;
            int lL = 0;
            int rL = CAMERA_WIDTH - (int) mSprite.getWidth();
            int bL = CAMERA_HEIGHT - (int) mSprite.getHeight();

            // вычисление новых координат и проверка касания с краем экрана
            if (sX >= lL)
                    sX -= accellerometerSpeedY;
            else
                    sX = lL;
            if (sX <= rL)
                    sX -= accellerometerSpeedY;
            else
                    sX = rL;
            if (sY >= tL)
                    sY += accellerometerSpeedX;
            else
                    sY = tL;
            if (sY <= bL)
                    sY += accellerometerSpeedX;
            else
                    sY = bL;

            mSprite.setPosition(sX, sY);
    };
}
}

Ваши вопросы, предложения и комментарии - приветствуются :)

3 комментария:

  1. Надо бы заменить onLoadResources.
    Вот так работает:


    public void onLoadResources() {
    //Создаем текстуру размерами 64*64
    //Обратите внимание, каждый размер текстуры должен равняться значению 2 в n-ой степени!

    //Установим путь по умолчанию для файлов
    BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
    //this.mTexture = new Texture(64, 64, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
    this.mBitmapTextureAtlas = new BitmapTextureAtlas(64, 64, TextureOptions.BILINEAR_PREMULTIPLYALPHA);

    //Загружаем графические данные из файла.
    //Первый параметр - наша текстура.
    //Второй - текущий контекст, ресурсы из нашего приложения.
    //Третий параметр - имя файла.
    //Четвертый и пятый - начальные координаты хранения графики в текстуре.
    // (Для анимации): Шестой и седьмой - количество кадров по горизонтали и вертикали соответственно
    this.mSpriteTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset((BitmapTextureAtlas) this.mBitmapTextureAtlas, this, "ship.png", 0, 0);
    //Загружаем текстурy
    this.mEngine.getTextureManager().loadTexture(this.mBitmapTextureAtlas);
    }

    И импорт:
    import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
    import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;

    ОтветитьУдалить
    Ответы
    1. Спасибо что зашли.
      В свое время этот код точно работал. Дело в том, что я окончательно перешел на GLES2. И по-этому в данный момент не могу проверить код. Возможно, у меня была более старая версия движка, а у Вас более новая. В моем коде есть TextureRegionFactory, а в Вашем варианте BitmapTextureAtlasTextureRegionFactory. В движке, основанном на GLES2 эта функция называется точно так же, как и у Вас - это еще один довод в пользу предположения, что у Вас другая, более свежая версия.

      Где то я уже говорил о том, что движок постоянно меняется, но это не всегда хорошо. В нашем случае произошел конфликт версий. Но я рад, что Вы смогли справиться с этой проблемой и даже нашли время сообщить об этом. Спасибо. :)

      Удалить
    2. У меня на глес2 не запустился :( можно проапгрейдить примерчик под глес2. только начал изучать данный движок.
      З.Ы.Ж. Я выражаю свою надежду то, что вы выложите рабочий проект-еклипс на гитхабе.
      З.З.Ы.Ж. Заранее благодарен.

      Удалить