我正在制作一款Android游戏的奇怪问题。这是一个2d动作益智游戏;精灵和背景是简单的不透明图像,但需要快速平稳地移动。然而,我遇到了一般的帧速率问题,但这个特殊问题让我很困惑。
问题在于我可以开始我的游戏(在硬件上,Nexus 7)并以至少60fps的帧速率运行,然后将其关闭并重新启动它将以30-45运行。重复这个过程,游戏通常以较慢的帧速率运行,但在每4次(或左右)尝试时运行得非常顺畅。
我是Android和编程的新手,所以我想知道是否有人猜测在重复运行中可能导致这种性能差异的原因是什么?如果它有用,我可以编辑包含一些代码,但这似乎更具理论性,我不确定与帖子相关的内容。
感谢。
编辑:
这是我的onCreate代码:
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.view.Window;
import android.view.WindowManager;
import com.jag.framework.Audio;
import com.jag.framework.FileIO;
import com.jag.framework.Game;
import com.jag.framework.Graphics;
import com.jag.framework.Input;
import com.jag.framework.Screen;
public abstract class AndroidGame extends Activity implements Game {
AndroidFastRenderView renderView;
Graphics graphics;
Audio audio;
Input input;
FileIO fileIO;
Screen screen;
WakeLock wakeLock;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
boolean isPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
int frameBufferWidth = isPortrait ? 800: 1200;
int frameBufferHeight = isPortrait ? 1200: 800;
Bitmap frameBuffer = Bitmap.createBitmap(frameBufferWidth,
frameBufferHeight, Config.RGB_565);
float scaleX = (float) frameBufferWidth
/ getWindowManager().getDefaultDisplay().getWidth();
float scaleY = (float) frameBufferHeight
/ getWindowManager().getDefaultDisplay().getHeight();
renderView = new AndroidFastRenderView(this, frameBuffer);
graphics = new AndroidGraphics(getAssets(), frameBuffer);
fileIO = new AndroidFileIO(this);
audio = new AndroidAudio(this);
input = new AndroidInput(this, renderView, scaleX, scaleY);
screen = getInitScreen();
setContentView(renderView);
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "MyGame");
}
@Override
public void onResume() {
super.onResume();
wakeLock.acquire();
screen.resume();
renderView.resume();
}
@Override
public void onPause() {
super.onPause();
wakeLock.release();
renderView.pause();
screen.pause();
if (isFinishing())
screen.dispose();
}
@Override
public Input getInput() {
return input;
}
@Override
public FileIO getFileIO() {
return fileIO;
}
@Override
public Graphics getGraphics() {
return graphics;
}
@Override
public Audio getAudio() {
return audio;
}
@Override
public void setScreen(Screen screen) {
if (screen == null)
throw new IllegalArgumentException("Screen must not be null");
this.screen.pause();
this.screen.dispose();
screen.resume();
screen.update(0);
this.screen = screen;
}
public Screen getCurrentScreen() {
return screen;
}
}
这是我的主要代码:
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import com.jag.framework.Game;
import com.jag.framework.Graphics;
import com.jag.framework.Image;
import com.jag.framework.Input.TouchEvent;
import com.jag.framework.Screen;
public class GameScreen extends Screen {
enum GameState {
Ready, Running, Paused, GameOver
}
GameState state = GameState.Ready;
// Variable Setup
private static Scene scene;
public static int screenheight;
private ArrayList<Pieces> pieces;
//lanes:
int lane;
Paint paint, paint2;
Rect rect;
Image fore, rings1, rings2, base1, base2;
boolean recent, freeze, touch, pospressed, negpressed, wrongbutton;
int timepassed, difficulty, recentinterval, score;
Bitmap bitmap;
Canvas canvas2;
Rect foreg;
InputStream in;
AssetManager assets;
public GameScreen(Game game) {
super(game);
// Initialize game objects here
scene = new Scene(600);
screenheight = game.getGraphics().getHeight();
pieces = new ArrayList<Pieces>();
lane = 100;
recent = true;
Pieces p3 = new Pieces(lane, 940, true);
pieces.add(p3);
paint = new Paint();
paint.setTextSize(30);
paint.setTextAlign(Paint.Align.CENTER);
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);
paint2 = new Paint();
paint2.setColor(Color.WHITE);
paint2.setStyle(Style.FILL);
difficulty = 50;
recentinterval = 30;
timepassed = 0;
freeze = false;
fore = Assets.block;
rings1 = Assets.ringswhite;
rings2 = Assets.ringsblack;
base1 = Assets.basewhite;
base2 = Assets.baseblack;
wrongbutton = false;
score = 0;
}
@Override
public void update(float deltaTime) {
List<TouchEvent> touchEvents = game.getInput().getTouchEvents();
// We have four separate update methods in this example.
// Depending on the state of the game, we call different update methods.
// Refer to Unit 3's code. We did a similar thing without separating the
// update methods.
if (state == GameState.Ready)
updateReady(touchEvents);
if (state == GameState.Running)
updateRunning(touchEvents, deltaTime);
if (state == GameState.Paused)
updatePaused(touchEvents);
if (state == GameState.GameOver)
updateGameOver(touchEvents);
}
private void updateReady(List<TouchEvent> touchEvents) {
// This example starts with a "Ready" screen.
// When the user touches the screen, the game begins.
// state now becomes GameState.Running.
// Now the updateRunning() method will be called!
if (touchEvents.size() > 0) {
game.getGraphics().clearScreen(Color.BLACK);
state = GameState.Running;
Assets.theme.stop();
}
}
private void updateRunning(List<TouchEvent> touchEvents, float deltaTime) {
// 1. All touch input is handled here:
int len = touchEvents.size();
for (int i = 0; i < len; i++) {
TouchEvent event = touchEvents.get(i);
if ((event.type == TouchEvent.TOUCH_DRAGGED || event.type == TouchEvent.TOUCH_DOWN) && event.y <= 1000) {
touch = true;
scene.setLine(event.x);
}
//POSITIVE BUTTON
if (event.type == TouchEvent.TOUCH_DOWN && ((0 < event.x) && (event.x < 250)) && event.y > 1000) {
pospressed = true;
}
//NEGATIVE BUTTON
if (event.type == TouchEvent.TOUCH_DOWN && ((550 < event.x) && (event.x < 800)) && event.y > 1000) {
negpressed = true;
}
//ACTIVATES ALERT (reduce score)
if (event.type == TouchEvent.TOUCH_UP) {
touch = false;
pospressed = false;
negpressed = false;
}
}
// 2. Check miscellaneous events like death:
// if (livesLeft == 0) {
// state = GameState.GameOver;
// }
// 3. Call individual update() methods here.
// This is where all the game updates happen.
// For example, robot.update();
if (!freeze){
timepassed += 1;
if ((timepassed % recentinterval) == 0){
recent = false;
}
}
Random randomGenerator = new Random();
int randomInt = randomGenerator.nextInt(difficulty);
int randomInt2 = randomGenerator.nextInt(7);
boolean randomBool = randomGenerator.nextBoolean();
int chanceOfNewPiece = 8;
if ((randomInt < chanceOfNewPiece)&&!recent) {
Pieces p = new Pieces((randomInt2+1)*lane, 940, randomBool);
pieces.add(p);
recent = true;
}
Iterator<Pieces> it = pieces.iterator();
while (it.hasNext()) {
Pieces p = it.next();
if (p.isVisible()&&!p.wayback&&!freeze)
p.update();
else if (p.isVisible()&&!p.wayback&&freeze){
p.still();
}
else if (p.wayback && pospressed){
if (score > 10){
score -= 10;
}
if (score <= 10){
score = 0;
}
if (p.type){
it.remove();
freeze = false;
pospressed = false;
Assets.click.play(100);
}
if (!p.type){
freeze = false;
pospressed = false;
wrongbutton = true;
}
}
else if (p.wayback && negpressed){
if (score > 10){
score -= 10;
}
if (score <= 10){
score = 0;
}
if (p.type){
freeze = false;
negpressed = false;
wrongbutton = true;
}
if (!p.type){
it.remove();
freeze = false;
negpressed = false;
Assets.click.play(100);
}
}
else if (p.isVisible() && p.wayback && wrongbutton){
p.updateback();
}
else if (p.isVisible()&&p.wayback){
p.updateback();
freeze = true;
}
else if (p.y < 10){
score += 1;
it.remove();
freeze = false;
wrongbutton = false;
}
else {
// if (p.y > screenheight-281){
// game.getGraphics().clearScreen(Color.BLACK);
// state = GameState.GameOver;
// }
score = 0;
it.remove();
freeze = false;
wrongbutton = false;
}
}
// if (pieces.size() == 0) {
//
// game.getGraphics().clearScreen(Color.BLACK);
// state = GameState.GameOver;
// }
}
private void updatePaused(List<TouchEvent> touchEvents) {
int len = touchEvents.size();
for (int i = 0; i < len; i++) {
TouchEvent event = touchEvents.get(i);
if (event.type == TouchEvent.TOUCH_UP) {
state = GameState.Running;
Assets.theme.stop();
}
}
}
private void updateGameOver(List<TouchEvent> touchEvents) {
int len = touchEvents.size();
for (int i = 0; i < len; i++) {
TouchEvent event = touchEvents.get(i);
if (event.type == TouchEvent.TOUCH_UP) {
nullify();
game.setScreen(new MainMenuScreen(game));
return;
}
}
}
@Override
public void paint(float deltaTime) {
//Debug.startMethodTracing();
Graphics g = game.getGraphics();
// draw the game elements
if (state == GameState.Running){
int fingerx = scene.getLine();
g.drawRect(fingerx, 0, g.getWidth(), 1200, Color.BLACK);
g.drawRect(0, 0, fingerx, 1200, Color.WHITE);
if (touch == false){
g.drawRect(250, 1000, 302, 205, Color.RED);
}
g.drawScaledImage(base1, fingerx, 955, g.getWidth()-fingerx,
base2.getHeight(), fingerx, 0, g.getWidth()-fingerx, base2.getHeight());
g.drawScaledImage(base2, 0, 955, fingerx, base2.getHeight(), 0, 0, fingerx, base2.getHeight());
g.drawString(String.valueOf(score),
350, 1075, paint);
////g.drawImage(back, 0, 0);
// g.drawScaledImage(Assets.fore, fingerx, 0, g.getWidth()-fingerx,
// Assets.fore.getHeight(), fingerx, 0, g.getWidth()-fingerx, Assets.fore.getHeight());
////g.drawImage(Assets.topwhite, 0, 0);
//g.saveCanvas();
//g.drawTransRect(0, 0, fingerx, g.getHeight());
////g.drawImage(fore, 0, 0);
//g.drawImage(base2, 0, 955);
// g.drawScaledImage(Assets.back, 0, 0, fingerx, Assets.back.getHeight(), 0, 0, fingerx, base2.getHeight());
// g.drawScaledImage(base2, fingerx, 955, g.getWidth()-fingerx, base2.getHeight(),
// fingerx, 0, g.getWidth()-fingerx, base2.getHeight());
//g.drawCropped(base2);
////g.drawImage(rings2, 0, 950);
//g.restoreCanvas();
for (Pieces p : pieces){
if (p.type == true)
g.drawImage(Assets.pos, (p.x - 40), p.y);
if (p.type == false){
g.drawImage(Assets.neg, (p.x - 40), p.y);
}
}
}
// draw the UI
if (state == GameState.Ready)
drawReadyUI();
if (state == GameState.Running)
drawRunningUI();
if (state == GameState.Paused)
drawPausedUI();
if (state == GameState.GameOver)
drawGameOverUI();
//Debug.stopMethodTracing();
}
private void nullify() {
// Set all variables to null. You will be recreating them in the
// constructor.
paint = null;
scene = null;
pieces = null;
scene = null;
pieces = null;
paint2 = null;
Assets.theme = null;
Assets.click = null;
// Call garbage collector to clean up memory.
System.gc();
}
private void drawReadyUI() {
Graphics g = game.getGraphics();
g.drawARGB(155, 0, 0, 0);
g.drawString("TOUCH THE SCREEN YA DUMMY",
400, 300, paint);
}
private void drawRunningUI() {
//Graphics g = game.getGraphics();
}
private void drawPausedUI() {
Graphics g = game.getGraphics();
// Darken the entire screen so you can display the Paused screen.
g.drawRect(0, 0, 801, 1281, Color.BLACK);
g.drawString("HEY GUY IT'S PAUSED", 640, 300, paint);
}
private void drawGameOverUI() {
Graphics g = game.getGraphics();
g.drawRect(0, 0, 1281, 801, Color.BLACK);
g.drawString("GAME OVER BRO", 640, 300, paint);
}
@Override
public void pause() {
if (state == GameState.Running)
System.gc();
state = GameState.Paused;
}
@Override
public void resume() {
}
@Override
public void dispose() {
}
@Override
public void backButton() {
pause();
}
public static Scene getScene(){
return scene;
}
public void setScore(int i){
score += i;
}
}
我意识到这有点混乱;这是我编码的第一件事。该框架来自kilobolt.com。如果我应该包括其他类别/方法,请告诉我。