Использование Android Drawable в качестве AndEngine HUD

Я пытаюсь создать AndEngine HUD, который будет располагаться поверх TMXTiledMap (терпите меня, я очень новичок в AndEngine). Для простоты сначала у меня есть простой прямоугольник, созданный с помощью Android. Идея состоит в том, что он будет располагаться в центре нижней части экрана и никогда не будет двигаться, даже если карта под ним перемещается в разных направлениях. Пока все, что я хочу сделать, это заставить этот прямоугольник появиться. Позже я добавлю другие функции в прямоугольник.

Мой Drawable создается так:

    ?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle" >
        <corners
            android:radius="7dp" />
        <gradient
            android:startColor="#343434"
            android:endColor="#17171717"
            android:angle="270"
            android:useLevel="false"
            android:type="linear" />
        <padding
            android:left="10dp"
            android:top="10dp"
            android:right="10dp"
            android:bottom="10dp" />
    </shape>

И я вытащил это в макет, как это:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="300dip"
    android:layout_height="100dip"
    android:orientation="horizontal" 
    android:layout_marginLeft="20dp"
    android:background="@drawable/menu_bkgrnd" >
</LinearLayout>

И, наконец, вот где я пытаюсь сделать это как HUD:

rect = new HUD();
ITouchArea container = (ITouchArea) findViewById(R.id.container);
this.rect.registerTouchArea(container);
rect.attachChild((IEntity) container);

Как вы можете видеть, я много раз кастуюсь, чтобы удовлетворить AndEngine, но когда я запускаю это, карта полностью облажается. Я правильно об этом говорю? Мой кастинг неправильный? (или, может быть, оба!).

Спасибо за любую помощь.

РЕДАКТИРОВАТЬ: Основываясь на коде, который Jong и 布鞋 白布鞋 предложили ниже, я настроил свой Java-код следующим образом:

this.atlas = new BitmapTextureAtlas(null, 256, 256, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
this.atlas.load();
ITextureRegion drawable = BitmapTextureAtlasTextureRegionFactory.createFromResource(atlas, getApplicationContext(), R.drawable.myDrawable, 0, 0);
rect.attachChild(new Sprite(0, 0, drawable, this.getVertexBufferObjectManager()));

На данный момент я все еще пытаюсь заставить это появиться на экране. Я отрегулирую размер и местоположение позже.

Все компилируется и работает без ошибок, однако мой экран - просто беспорядок.

Как видите, мне пришлось внести несколько небольших корректировок в аргументы конструктора, чтобы AndEngine принял мои экземпляры. Не уверен, что я делаю это правильно.

Другая проблема, которую я вижу в этом коде, заключается в том, что мне кажется, что этот код просто помещает неактивную фигуру на мой экран. Я знаю, что в своем первоначальном посте я сказал, что моей непосредственной целью является сделать этот прямоугольник видимым, но я думаю, что он должен отображаться как зарегистрированная область касания, поскольку в конечном итоге это будет что-то с элементами управления, которые должны реагировать для пользовательских команд. Извините, если я слишком минимизировал то, что я пытаюсь сделать.

Я до сих пор не понимаю этого. У кого-нибудь есть предложения? Еще раз спасибо!

2 ответа

Вы не можете разыграть LinearLayout в ITouchArea, ITouchArea интерфейс, реализованный только классами AndEngine

Как предложено 正宗 use 布鞋, вы должны использовать createFromResource метод BitmapTextureAtlasTextureRegionFactory,

Вы можете использовать этот код:

BitmapTextureAtlas atlas = new BitmapTextureAtlas(sizeX, sizeY, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
TextureRegion drawable = BitmapTextureAtlasTextureRegionFactory.createFromResource(atlas, getApplicationContext(), R.drawable.drawableId, 0, 0);
rect.attachChild(new Sprite(x, y, drawable));

РЕДАКТИРОВАТЬ:

Если вы хотите, чтобы ваш спрайт реагировал на сенсорные события, вы можете зарегистрировать его как сенсорную область в своем rect HUD.

Sprite sprite = new Sprite(x, y, drawable, getVertexBufferObjectManager()) {
    @Override
    public boolean onAreaTouched(final TouchEvent pTouchEvent, final float pX, final float pY) {
        //Do what you want here
    }
}
rect.registerTouchArea(sprite);
rect.attachChild(sprite);

У меня была такая же проблема несколько дней назад, и я не мог найти правильный ответ. Итак, теперь, когда я собрал информацию из разных источников, вот как я справился с этим.

AFAIK, похоже, что метод createFromResource(atlas, getApplicationContext(), R.drawable.drawableId, 0, 0) от BitmapTextureAtlasTextureRegionFactory не может иметь дело с XML Drawable (например, <shape>...</shape>).
Действительно, когда я только отображал цветной прямоугольник, все было хорошо - и я думаю, с файлом PNG - но когда я пытался создать Sprite из моего XML Drawable, я всегда получал NullBitmapException когда рисунок произошел.

Шаги, которые я предпринял:

  • Преобразовать нарисованный ресурс в Drawable
  • Перерабатывать Drawable в Bitmap ( Источник здесь)
  • Перерабатывать Bitmap в TextureRegion (Это где я использовал это)
  • Создать Sprite от TextureRegion (или два для выбранных / невыбранных, как здесь)
  • Прикрепить Sprite к игре HUD

Итак, с кодом:

Преобразовать нарисованный ресурс TextureRegion

/**
 * Takes a drawable, and converts it to a TextureRegion.
 * @param context
 * @param resId the drawable ID
 * @param textureSizeX width for our TextureRegion
 * @param textureSizeY height for our TextureRegion
 * @return a TextureRegion from the drawable
 */
public static TextureRegion textureRegionFromDrawable(BaseGameActivity context, int resId, int textureSizeX, int textureSizeY) {
    Drawable drawable = context.getResources().getDrawable(resId);
    Bitmap bitmap = drawableToBitmap(drawable);
    BitmapTextureAtlasTextureSource source = new BitmapTextureAtlasTextureSource(bitmap);
    BitmapTextureAtlas textureAtlas = new BitmapTextureAtlas(context.getTextureManager(), textureSizeX, textureSizeY);
    textureAtlas.addTextureAtlasSource(source, 0, 0);
    textureAtlas.load();
    TextureRegion textureRegion = (TextureRegion) TextureRegionFactory.createFromSource(textureAtlas, source, 0, 0);
    return textureRegion;
}
// Drawable to Bitmap
public static Bitmap drawableToBitmap(Drawable drawable) {
    if (drawable instanceof BitmapDrawable) {
        return ((BitmapDrawable) drawable).getBitmap();
    }
    Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    drawable.draw(canvas);
    return bitmap;
}

Утилита промежуточный класс

public class BitmapTextureAtlasTextureSource extends BaseTextureAtlasSource implements IBitmapTextureAtlasSource {
    private final int[] mColors;
    public BitmapTextureAtlasTextureSource(Bitmap pBitmap) {
        super(0, 0, pBitmap.getWidth(), pBitmap.getHeight());
        mColors = new int[mTextureWidth * mTextureHeight];
        for (int y = 0; y < mTextureHeight; ++y) {
            for (int x = 0; x < mTextureWidth; ++x) {
                mColors[x + y * mTextureWidth] = pBitmap.getPixel(x, y);
            }
        }
    }
    @Override
    public Bitmap onLoadBitmap(Config pBitmapConfig) {
        return Bitmap.createBitmap(mColors, mTextureWidth, mTextureHeight, Bitmap.Config.ARGB_8888);
    }

    @Override
    public IBitmapTextureAtlasSource deepCopy() {
        return new BitmapTextureAtlasTextureSource(Bitmap.createBitmap(mColors, mTextureWidth, mTextureHeight, Bitmap.Config.ARGB_8888));
    }

    @Override
    public Bitmap onLoadBitmap(Config pBitmapConfig, boolean pMutable) {
        // TODO Auto-generated method stub
        return null;
    }
}

Создать два Sprite от TextureRegion s (я хотел 2 состояния для моей кнопки: выбранный / невыбранный), и прикрепить их к HUD

int textureSizeX = 512, textureSizeY = 512;
TextureRegion textureDefault = AndEngineUtils.textureRegionFromDrawable(activity, R.drawable.custom_menu_button, textureSizeX, textureSizeY);
TextureRegion textureSelected = AndEngineUtils.textureRegionFromDrawable(activity, R.drawable.custom_menu_button_selected, textureSizeX, textureSizeY);
mGameHUD = new HUD();

// 2 sprites for selected and unselected
final Sprite buttonUnselected, buttonSelected ;
buttonSelected = new Sprite(0, 0, textureSelected, activity.getVertexBufferObjectManager());
buttonSelected.setVisible(false);

buttonUnselected = new Sprite(0, 0, textureDefault, activity.getVertexBufferObjectManager()) {
    @Override
    public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY) {
        switch (pSceneTouchEvent.getAction()) {
        case TouchEvent.ACTION_DOWN:
            // Change button
            buttonSelected.setVisible(true);
            this.setVisible(false);
            break;
        case TouchEvent.ACTION_UP:
            // reset button
            this.setVisible(true);
            buttonSelected.setVisible(false);
            break;
        default:
            break;
        }
        return super.onAreaTouched(pSceneTouchEvent, pTouchAreaLocalX, pTouchAreaLocalY);
    }
};
mGameHUD.attachChild(buttonSelected);
mGameHUD.attachChild(buttonUnselected);
mGameHUD.registerTouchArea(buttonUnselected);
camera.setHUD(mGameHUD);

Мы также можем использовать scene.setOnAreaTouchListener(touchListener) для того, чтобы "нежелательный" скользящий жест - до тех пор, пока он не будет за пределами кнопки - предпринять effet для сброса цвета кнопки (см. эту ветку).

Я только начал использовать AndEngine и я еще не знаком с лучшими практиками, поэтому не стесняйтесь поправлять меня.

Другие вопросы по тегам