如何在安卓设备上正确地缩放游戏

9
为了简单起见,假设我正在为Android制作一个简单的Pong克隆游戏。假设它只能在横屏模式下玩(现在忽略方形手机)。
我希望游戏在每个手机上看起来都是相同比例的,以至于如果你在QVGA手机上截取游戏屏幕截图并将其调整大小到WVGA大小,它看起来几乎与在WVGA手机上看到的游戏一样。换句话说,挡板的宽度应始终为屏幕宽度的1/32,球的直径应始终为屏幕宽度的1/16。
什么是正确的应用程序绘制方式?它将在标准SurfaceView中运行,该视图将被绘制到Canvas上。
假设我有用于挡板、球和游戏字体(记分牌、主菜单)的高分辨率PNG文件。
我是否需要找出物理分辨率,然后通过scale(float sx, float sy)缩放Canvas,使得所有Canvas(在QVGA和WVGA上)具有相同的虚拟分辨率,并在每个屏幕尺寸上的每个位置上绘制完全相同的基元?
还是我可以在Canvas中以某种方式使用密度无关像素(dip)?
3个回答

4
我只使用过绘图画布功能玩了一次,然后就全部转换成了OpenGL,但逻辑保持不变(我想)。
首先,您需要保持一个比例恒定的形式从一个手机到另一个手机。在我的应用程序中,我在每个侧面添加了“黑带”效果。在onSurfaceChanged中,您需要计算一个比率,这个比率将允许您确定需要在每个侧面上移除多少空间以保持绘图的一致性。这将为您提供一个要应用于所有绘图的delta 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,因为它会简化你需要保持恒定纵横比的需求,但我猜这可能不是一个选项^^ 希望这能帮到你。

2
使用渐变来绘制挡板,而不是使用 PNG 图片。

我如何在Canvas方法(如drawLine())中使用dips? - Axarydax
好的,让我们忘掉 Pong 克隆游戏,来谈谈像 Pac-man 或 SimCity 这样的基于瓷砖的游戏。因此,这些瓷砖存储在 PNG 中,而 Pong 可能是一个过于简单的例子。 - Axarydax

-1
我认为只有3个标准的分辨率可用(ldip,mdip,hdip),你应该为每个分辨率创建一个资源文件夹。

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

如果您手动缩放PNG以适应3个可用分辨率中的每一个,手机应该以透明的方式加载特定的资源文件夹。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接