Как правильно масштабировать игру на Android

для простоты предположим, что я делаю простую игру-клон Pong для Android. Предположим, что играть можно будет только в ландшафтном режиме. (не обращайте внимания на квадратные телефоны).

Я бы хотел, чтобы игра выглядела в одном масштабе на каждом телефоне, до такой степени, что если вы сделаете скриншот игры на QVGA-телефоне и измените его размер до размера WVGA, он будет выглядеть почти так же, как игра. посмотри на WVGA телефоне. Другими словами, ширина ракетки всегда должна составлять 1/32 ширины экрана, диаметр мяча всегда должен составлять 1/16 ширины экрана.

Как правильно нарисовать приложение? Он будет работать в стандартном SurfaceView, который будет отображаться на Canvas.

Допустим, у меня есть PNG с высоким разрешением для весла, мяча и игрового шрифта (табло, главное меню).

Должен ли я узнать физическое разрешение, затем масштабировать Canvas через scale(float sx, float sy), чтобы все мои холсты (на QVGA и WVGA) имели одинаковое виртуальное разрешение, а затем рисовать точно такие же примитивы в каждой позиции на каждом Размер экрана?

Или я могу как-то использовать независимые от плотности пиксели (dip) в Canvas?


person Axarydax    schedule 15.11.2010    source источник


Ответы (3)


Я только один раз поиграл с функциями рисования холста, а затем переключил все на opengl, но логика осталась прежней (я думаю).

Во-первых, вы захотите сохранить постоянное соотношение формы одного телефона к другому. в моем приложении я добавляю эффект «черной полосы» с каждой стороны. в onSurfaceChanged вам нужно рассчитать соотношение, это соотношение позволит вам определить, сколько места вам нужно удалить с каждой стороны, чтобы сохранить постоянный аспект вашего рисунка. это даст вам дельту X или Y для применения ко всем вашим розыгрышам. Следующий код - это то, что я адаптировал из версии ogl, поэтому, возможно, его нужно немного изменить.

@Override
   public void onSurfaceChanged(int w, int h){
   float ratioPhysicScreen = nativeScreenResoltionW/nativeScreenResoltionH;
   float ratioWanted = GameView.getWidth()/GameView.getHeight();
   if(ratioWanted>ratioPhysicScreen){
      newHeight = (int) (w*GameView.getHeight()/GameView.getWidth());
      newWidth = w;
      deltaY = (int) ((h-newHeight)/2);
     deltaX = 0;
   }else{
      newWidth = (int) (h/GameView.getHeight()*GameView.getWidth());
      newHeight = h;
      deltaX = (int) ((w-newWidth)/2);
      deltaY = 0;       
}

тогда вы также захотите иметь возможность рисовать свои изображения на холсте, зная размер на холсте, а не реальный размер, и где разница между image.getWidth() (фактический размер изображения) и image.getScaledWidth(canvas), который дает вам размер элемента в dp, что означает, насколько большим он будет отображаться на экране), важен. посмотрите на пример ниже.

public class MainMenuView extends PixelRainView{
private Bitmap bmpPlay = null;
private float playLeft = 0;
private float playRight = 0;
private float playBottom = 0;
private float playTop = 0;

public MainMenuView(Context context, AttributeSet attrs) {
    super(context,attrs);
}



@Override
public void unLoadBitmaps() {
    super.unLoadBitmaps();
    if(bmpPlay != null){
        bmpPlay.recycle();
        bmpPlay = null;
    }
}



@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if(bmpPlay == null){
        bmpPlay = getBitmapFromRessourceID(R.drawable.play_bt);
        playLeft = (this.getWidth()-bmpPlay.getScaledWidth(canvas))/2; 
        playRight = playLeft + bmpPlay.getScaledWidth(canvas);
        playTop = (this.getHeight()-bmpPlay.getScaledHeight(canvas))/2;
        playBottom = playTop+bmpPlay.getScaledHeight(canvas);
    }
    canvas.drawBitmap(bmpPlay,playLeft, playTop, null);

    }       
}


@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
}



@Override
public boolean onTouchEvent(MotionEvent event) {
    if(event.getAction() == MotionEvent.ACTION_DOWN){
        float x = event.getX();
        float y = event.getY();
        //test central button
        if(x>playLeft && x<playRight && y<playBottom && y>playTop){
            Log.e("jason", "touched play");
            PixelRainView.changeView(R.layout.composedlayoutgroup);
        }
    return super.onTouchEvent(event);
}
}

Это должно решить все ваши проблемы с соотношением кросс-платформ. Я бы предложил opengl, потому что это упростит вашу потребность в сохранении постоянного аспекта, но я думаю, что это не вариант ^^

Надеюсь, это поможет вам достаточно

person Jason Rogers    schedule 19.11.2010

Используйте провалы и раскрашивайте весла вместо PNG.

person Fred Grott    schedule 15.11.2010
comment
как использовать провалы в методах Canvas, таких как drawLine()? - person Axarydax; 15.11.2010
comment
хорошо, давайте забудем о клоне Pong и поговорим об играх, основанных на тайлах, таких как Pac-man или SimCity. Итак, есть плитки, которые хранятся в PNG, и Pong, возможно, был слишком простым примером. - person Axarydax; 15.11.2010

Я думаю, что доступны только 3 стандартных разрешения (ldip, mdip, hdip) и у вас должна быть папка ресурсов для каждого из них.

http://developer.android.com/guide/practices/screens_support.html

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

person dcarneiro    schedule 15.11.2010