缩放固定的SurfaceView以垂直填充并保持纵横比

时间:2012-05-22 18:02:42

标签: android surfaceview

我一直试图寻找答案而且似乎找不到答案(这是一种非常规的方法来编写Android游戏,所以可以预料到,至少我认为)。

我试图在Android中创建一个GBA风格的RPG游戏(用于怀旧)。 OpenGL对我来说不够好,因为它在游戏循环中不够可定制(我只想在需要绘制的东西时调用draw,因为我想要这个游戏来在如何使用电池方面非常有效率,这意味着它更像是一个投票应用而不是游戏)。我创建了一个自定义的表面视图,它有自己的线程,每当需要完成绘制时都会调用它(我在SDK中的示例LunarLander安卓游戏之后对其建模)。

问题是,我希望游戏本身是固定大小(208x160),然后扩展到屏幕大小。我所遇到的问题似乎无论如何都是在XML的扩展SurfaceView的常规参数范围内这样做。处于当前状态的游戏如下所示。我试图让它延伸到屏幕的高度并保持宽度的比例,同时也不会增加可视游戏(保持固定,无论屏幕尺寸如何)。

http://i.stack.imgur.com/EWIdE.png(我打算在线发布实际图片。垃圾邮件预防可以咬我>。<)

目前,我正在获取SurfaceView的画布并直接绘制它,并将我的尺寸作为硬编码像素尺寸(208px,160px)提供。

这是线程目前在获取画布和绘图时的样子。什么是更好的方式来绘制画布而不改变我希望游戏虚拟占据的尺寸?

@Override
    public void run()
    {
        Canvas c = null;
        try
        {
            c = surfaceHolder.lockCanvas(null);
            synchronized (surfaceHolder)
            {
                draw(c);
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (c != null)
                surfaceHolder.unlockCanvasAndPost(c);
        }
    }

draw方法是这样的(StringBuilder是引擎中我自己的编码对象):

public void draw(Canvas canvas)
{       
    canvas.drawColor(Color.GRAY);
    StringBuilder stringBuilder = new StringBuilder(canvas, Color.BLACK, letters);
    stringBuilder.drawString("Oh, hello there!");
    stringBuilder.setLocation(10, 20);
    stringBuilder.drawString("Why am I so small?");
}

有什么想法吗?

2 个答案:

答案 0 :(得分:4)

假设您的draw功能已重命名为drawBase。这是你如何做到的:

public void draw(Canvas canvas)
{
    final float scaleFactor = Math.min( getWidth() / 208.f, getHeight() / 160.f );
    final float finalWidth = 208.f * scaleFactor;
    final float finalHeight = 160.f * scaleFactor;
    final float leftPadding = ( getWidth() - finalWidth ) / 2;
    final float topPadding =  ( getHeight() - finalHeight ) / 2;

    final int savedState = canvas.save();
    try {
        canvas.clipRect(leftPadding, topPadding, leftPadding + finalWidth, topPadding + finalHeight);

        canvas.translate(leftPadding, topPadding);
        canvas.scale(scaleFactor, scaleFactor);

        drawBase(canvas);
    } finally {
        canvas.restoreToCount(savedState);
    }
}

答案 1 :(得分:1)

(K-ballo接受的答案很好,但是自写入以来的2。5年里,显示器变得越来越密集,这意味着软件渲染越来越昂贵。获得硬件帮助非常重要做这项工作。)

要以特定分辨率呈现,您可以使用SurfaceHolder#setFixedSize()。这会将Surface的大小设置为您指定的精确尺寸。表面将按比例放大以匹配硬件缩放器的视图大小,这将比软件缩放更有效。此功能在此blog post中有所描述,您可以在Grafika's"硬件缩放器训练器"活动(demo video)。

您可以通过调整Surface的大小(这是Grafika为该演示所做的工作)或通过将视图调整为字母或柱形框来为不同尺寸的显示器保持适当的宽高比。您可以在Grafika的AspectFrameLayout类中找到后者的示例,该类用于各种相机和视频演示。

关于这一点:

  

OpenGL对我来说不够好,因为它在游戏循环中不够自定义(我只想在需要绘制某些内容时调用绘图...... < / p>

您有两种选择。首先,您可以使用GLSurfaceView#setRenderMode()禁用连续渲染。其次,您不需要使用GLSurfaceView来使用OpenGL。 Grafika中的大多数GLES代码都在SurfaceView或TextureView上运行。