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

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

Мой рисунок создается следующим образом:

    ?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, но когда я запускаю это, карта полностью испорчена. Я правильно об этом говорю? Мой кастинг неправильный? (а может и то и другое!).

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

РЕДАКТИРОВАТЬ: на основе кода, предложенного Джонгом и 正宗白布鞋 ниже, я изменил свой код 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 принимать мои экземпляры. Не уверен, что я делаю это правильно.

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

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


person AndroidDev    schedule 30.11.2012    source источник
comment
Я думаю, что ваш кастинг неверен. Ваш R.id.container — это Android LinearLayout, но вы присвоили его AndEngine ITouchArea. Поскольку у вас уже есть XML-файл «формы», определенный в вашем /drawable, вы можете использовать его и некоторые функции AndEngine (например, BitmapTextureAtlasTextureRegionFactory.CreateFromResource) для создания вашего TextureRegion или Sprite, а затем прикрепить его к вашему HUD.   -  person 正宗白布鞋    schedule 30.11.2012
comment
1. вы забыли вызвать this.atlas.load(). 2. вы можете переопределить класс спрайта и реализовать свой метод onAreaTouched.   -  person 正宗白布鞋    schedule 30.11.2012
comment
Спасибо. Я добавил this.atlas.load(), который теперь меняет экран, но на экране беспорядок. Я не знаю, как переопределить класс спрайта таким образом.   -  person AndroidDev    schedule 30.11.2012
comment
load должен вызываться после завершения установки textureregion. есть несколько примеров, показывающих, как переопределить, например: строка 81 в ссылка   -  person 正宗白布鞋    schedule 30.11.2012
comment
Извините за вредительство, но я полностью застрял. Есть ли какие-нибудь эксперты AndEngine, которые могут взглянуть на это для меня? Спасибо.   -  person AndroidDev    schedule 01.12.2012


Ответы (2)


Вы не можете преобразовать LinearLayout в ITouchArea, ITouchArea — это интерфейс, реализованный только классами AndEngine.

Как предложил 正宗白布鞋, вы должны использовать метод 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);
person Jong    schedule 30.11.2012
comment
Спасибо. Я попытался реализовать ваше предложение, но не совсем решаю это. Я отредактировал свой ОП выше, указав, что я сделал, и дополнительные вопросы. Спасибо еще раз! - person AndroidDev; 30.11.2012
comment
Спасибо. Часть, которая не работает, — это BitmapTextureAtlasTextureRegionFactory. Я продолжаю получать исключение NullBitmapException, когда запускаю это. Любая идея, почему это может происходить? - person AndroidDev; 02.12.2012
comment
Вероятно, это происходит из-за того, что AndEngine не может загрузить ваш рисунок. Протестируйте рисование на регулярной активности - person Jong; 02.12.2012
comment
Деятельность, кажется, работает просто отлично. Я могу начать действие с этим в качестве его содержимого, и оно отлично отображается. На данный момент это просто очень простой градиентный фон. Я пытаюсь настроить hud, прежде чем тратить время на создание рисунков. Я начал новый пост об этом, чтобы просто сосредоточиться на нулевом исключении, поэтому, если у вас есть несколько минут и вы не возражаете, проверьте это. Спасибо за вашу помощь! - person AndroidDev; 03.12.2012

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

Насколько я знаю, похоже, что метод createFromResource(atlas, getApplicationContext(), R.drawable.drawableId, 0, 0) из BitmapTextureAtlasTextureRegionFactory не может работать с рисуемыми XML (такими как <shape>...</shape>).
Действительно, когда я отображал только цветной прямоугольник, все было в порядке, и я думаю с файл PNG тоже, но когда я пытался создать Sprite из моего XML-рисунка, я всегда получал 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 из TextureRegions (я хотел, чтобы у моей кнопки было 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) для «нежелательного» скользящего жеста — до выхода за пределы кнопки — для сброса цвета кнопки (см. эта тема).

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

person OroshiX    schedule 03.09.2013