Create a 2D game loop without lag on Android

I spent some time learning how to create 2D rendering game loops on Android anno 2016

I want to achieve the following goals:

>Smooth animation > hardware acceleration > no lag (60 FPS) > use normal canvas > simplicity (no OpenGL)

Myth about surfaceview:

First, several articles recommend using surfaceview. At first glance, this seems to be a good idea because it uses a separate rendering thread, but it turns out that the canvas returned from surfaceholder cannot be hardware accelerated! With quadhd (2560) × 1440) resolution devices using surfaceview with software rendering is extremely inefficient

Therefore, my choice is to extend the basic view and override ondraw(). Every update calls invalidate()

Smooth animation:

My next challenge is smooth animation. It turns out that reading system. Nanotime () in OnDraw () is not a good idea because it will not be called every 1 / 60 second, resulting in jittery motion on my sprite. Therefore, I use choreographer to provide me with the frame time of each Vsync. That's good

Current progress:

I think I'm close, but I still occasionally encounter some lag on old devices. The memory utilization is very low, so I don't think GC can solve this problem... It seems that my callback occasionally loses / jumps aoad frames

I will post my code and look forward to your comments and suggestions

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.support.v4.content.res.ResourcesCompat;
import android.util.AttributeSet;
import android.view.Choreographer;
import android.view.View;

public class MiniGameView extends View implements Choreographer.FrameCallback
{
    private final float mDisplayDensity;

    private long mFrameTime = System.nanoTime();

    private final Drawable mBackground;
    private final Drawable mMonkey;

    public MiniGameView(Context context)
    {
        this(context, null);
    }

    public MiniGameView(Context context, AttributeSet attrs)
    {
        super(context, attrs);

        mDisplayDensity = getResources().getDisplayMetrics().density;

        // Load graphics
        mBackground = ResourcesCompat.getDrawable(getResources(), R.drawable.background, null);
        mMonkey = ResourcesCompat.getDrawable(getResources(), R.drawable.monkey, null);

        Choreographer.getInstance().postFrameCallback(this);
    }

    // Receive time in nano seconds at last VSYNC. Use this frameTime for smooth animations!
    @Override
    public void doFrame(long frameTimeNanos)
    {
        mFrameTime = frameTimeNanos;

        Choreographer.getInstance().postFrameCallback(this);
        invalidate();
    }

    // Draw game here
    @Override
    protected void onDraw(Canvas canvas)
    {
        drawBackground(canvas);
        drawSprites(canvas);
    }

    private void drawBackground(Canvas canvas)
    {
        mBackground.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        mBackground.draw(canvas);
    }

    private void drawSprites(Canvas canvas)
    {
        double t = mFrameTime * 0.00000001;

        int width = canvas.getWidth();
        int height = canvas.getHeight();

        for(int i=0;i<8;i++)
        {
            double x = width * (1 + Math.sin(-0.181 * t)) * 0.5;
            double y = height * (1 - Math.cos(0.153 * t)) * 0.5;

            int size = (int)Math.round((80 + 40 * Math.cos(0.2 * t)) * mDisplayDensity);

            drawSprite(canvas, mMonkey, (int) x, (int) y, size, size);

            t += 0.8;
        }
    }

    private void drawSprite(final Canvas canvas, final Drawable sprite, int x, int y, int w2, int h2)
    {
        sprite.setBounds(x - w2, y - h2, x + w2, y + h2);
        sprite.draw(canvas);
    }

}

I also created systrace file

resolvent:

There is really no "myth" about surfaceview. It is the best choice for high-resolution and fast animation... But you must use OpenGL es. Canvas rendering on surface (surfaceview, TextureView, etc.) is not accelerated by hardware, and becomes more and more expensive as the number of pixels increases

A useful feature of surfaceview is that it can set the surface to a fixed size and let the display hardware enlarge it. For some types of games, this can produce sufficient performance. An example of scaling is here. Please note that rendering uses gles

General suggestions on game loops can be found in this appendix. You seem to be doing the right thing. You may want to consider adding a frame loss counter to see if the animation fault is related to frame loss. (if the continuous time reported by the choreographer jumps from 16.7ms to 33ms, you have discarded one.)

The best way to track animation failures is to use systrace. With these traces, you can easily and accurately see what all threads are doing and determine the cause and result of pauses

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>