Использование 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
и я еще не знаком с лучшими практиками, поэтому не стесняйтесь поправлять меня.