作成中の Android ゲームで奇妙な問題が発生しています。これは 2D アクション パズル ゲームです。スプライトと背景は単純な不透明な画像ですが、すばやくスムーズに移動する必要があります。しかし、私は一般的なフレームレートの問題を経験しており、この特定の問題は私にとって非常に混乱しています.
問題は、ゲームを (ハードウェア、Nexus 7 で) 開始し、少なくとも 60 fps のフレーム レートで実行してから、終了して再起動すると、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;
}
}
これは少し混乱していることに気づきました。それは私がコーディングした最初のものです。フレームワークは、kibolt.com からのものです。含めるべき他のクラス/メソッドがあるかどうか教えてください。