安卓工作室 2d 游戏帧率问题



我正在尝试开发可能的第一个 2d 安卓游戏。我打算在不使用引擎的情况下从头开始构建它。我设法创建了以下线程:

import android.graphics.Canvas;
import android.view.SurfaceHolder;

public class MainThread extends Thread {
private int FPS = 30;
private double averageFPS;
private GamePanel gamePanel;
private SurfaceHolder surfaceHolder;
private boolean running;
public static Canvas canvas;
public MainThread(SurfaceHolder surfaceHolder, GamePanel gamePanel) {
    super();
    this.surfaceHolder = surfaceHolder;
    this.gamePanel = gamePanel;
}

@Override
public void run() {
    long startTime;
    long timeMillis;
    long waitTime;
    long totalTime = 0;
    int frameCount = 0;
    // how many milliseconds it take to run through the loop
    long targetTime = 1000 / FPS;
    while (running) {
        startTime = System.nanoTime();
        canvas = null;
        // try to lock the canvas for pixel editing
        try {
            canvas = this.surfaceHolder.lockCanvas();
            synchronized (surfaceHolder) {
                // the main game loop
                this.gamePanel.update();
                this.gamePanel.draw(canvas);
            }
        } catch (Exception e) {
        } finally {
            if (canvas != null) {
                try {
                    surfaceHolder.unlockCanvasAndPost(canvas);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        timeMillis = (System.nanoTime() - startTime) / 1000000;
        waitTime = targetTime - timeMillis;
        try {
            System.out.println(waitTime);
            this.sleep(waitTime);
        } catch (Exception e) {
        }
        totalTime += System.nanoTime() - startTime;
        frameCount++;
        if (frameCount == FPS) {
            averageFPS = 1000 / ((totalTime / frameCount) / 1000000);
            frameCount = 0;
            totalTime = 0;
            System.out.println(averageFPS);
        }
    }
}

我遇到的问题是,在向游戏中添加内容时,平均 FPS 不断下降。只有背景,它在我的 Nexus 5 上以 30 分工作,但在添加角色和障碍物后,它下降到 22-21。无论如何我可以做优化它吗?

谢谢

更新:我的游戏面板看起来像这样:

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.util.ArrayList;
import java.util.Random;

public class GamePanel extends SurfaceView implements SurfaceHolder.Callback     {
public static final int WIDTH = 1920;
public static final int HEIGHT = 1080;
public static float MOVESPEED = -12;
private Random rand = new Random();
private MainThread thread;
private Background bg;
private Treadmill tm;
private Player player;
private ArrayList<Box> boxes;
private int minDistance = 600;
private int score;
public GamePanel(Context context) {
    super(context);
    // add callback service to the holder to intercept events
    getHolder().addCallback(this);

    // make gamePanel focusable so it can handle events
    setFocusable(true);
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    boolean retry = true;
    while (retry) {
        try {
            thread.setRunning(false);
            thread.join();
            retry = false;
            thread = null;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
    // instantiate objects
    thread = new MainThread(getHolder(), this);
    bg = new Background(BitmapFactory.decodeResource(getResources(), R.drawable.background));
    tm = new Treadmill(BitmapFactory.decodeResource(getResources(), R.drawable.ground));
    player = new Player(BitmapFactory.decodeResource(getResources(), R.drawable.character));
    boxes = new ArrayList<Box>();

    //start game loop
    thread.setRunning(true);
    thread.start();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        if (player.jump == false) {
            player.setVelocity(-14f);
            player.setJump(true);
        }
        return true;
    }
    return super.onTouchEvent(event);
}
public void update() {
    bg.update();
    tm.update();
    player.update();
    if (boxes.size() == 0) {
        boxes.add(new Box(BitmapFactory.decodeResource(getResources(), R.drawable.box),
                WIDTH));
    } else if (boxes.get(boxes.size() - 1).getX() < WIDTH) {
        if (WIDTH - boxes.get(boxes.size() - 1).getX() < minDistance) {
            boxes.add(new Box(BitmapFactory.decodeResource(getResources(), R.drawable.box),
                    rand.nextInt(400 - 50) + WIDTH + minDistance));
        }
    }
    for (int i = 0; i < boxes.size(); i++) {
        if (boxes.get(i).getX() <= player.getX() && boxes.get(i).getX() >= player.getX() - 12) {
            score++;
            MOVESPEED -= 0.2;
            System.out.println(MOVESPEED);
        }
        if (collision(boxes.get(i), player)) {
            boxes.remove(i);
            break;
        }
        if (boxes.get(i).getX() < -100) {
            boxes.remove(i);
            break;
        }
    }
    for (int i = 0; i < boxes.size(); i++) {
        boxes.get(i).update();
    }
}
@Override
public void draw(Canvas canvas) {
    final float scaleFactorX = getWidth() / (WIDTH * 1.f);
    final float scaleFactorY = getHeight() / (HEIGHT * 1.f);
    if (canvas != null) {
        final int saveState = canvas.save();
        canvas.scale(scaleFactorX, scaleFactorY);
        // draw the background
        bg.draw(canvas);
        tm.draw(canvas);
        player.draw(canvas);
        for (Box bx : boxes) {
            bx.draw(canvas);
        }
        drawText(canvas);
        canvas.restoreToCount(saveState);
    }
}
public boolean collision(GameObject a, GameObject b) {
    if (Rect.intersects(a.getRectangle(), b.getRectangle())) {
        return true;
    }
    return false;
}
public void drawText(Canvas canvas) {
    Paint paint = new Paint();
    paint.setColor(Color.BLACK);
    paint.setTextSize(50);
    paint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
    canvas.drawText("Score: " + (score), 15, HEIGHT - 20, paint);
}

感谢您到目前为止的所有帮助

问题似乎不在主线程活动中,您遵循了教程(除了行 - System.out.println(waitTime); - 但我不认为这是问题原因。问题很可能出在游戏面板中。;)

永远不要在游戏循环中使用Thread.sleep()。不保证在指定的时间内休眠。

无论如何,我认为这在使用 Canvas 时几乎是预期的行为。如果我是你,我会考虑使用OpenGL ES进行图形渲染之类的事情。当然,这使得它变得更加复杂(即使Android已经为你做了很多事情)。但好处是显而易见的 - 您可以获得实际的实时图形性能。

最新更新