Android SurfaceHolder unlockCanvasAndPost benötigt zu viel Zeit

Faberix

Mitglied
Hallo Forum

Ich schreibe gerade mein Java-Spiel für Android um. Es funktioniert schon ganz ordentlich, aber es ruckelt immer ein Wenig. Ich habe mal in der LogCat geschaut und festgestellt, dass es die Funktion "SurfaceHolder.unlockCanvasAndPost(Canvas)" ist. Sie benötigt meist zwischen 40 und 100 Millisekunden, das ist einfach zu viel.

Hier mein Code:
Java:
public void repaint() {
            if(!surfaceHolder.getSurface().isValid())
                return false;
            long start = System.currentTimeMillis();
            Canvas canvas = surfaceHolder.lockCanvas();
            System.out.println("lockCanvasTime: " + (System.currentTimeMillis() - start));
            paint(canvas);
            start = System.currentTimeMillis();
            surfaceHolder.unlockCanvasAndPost(canvas);
            System.out.println("unlockCanvasTime: " + (System.currentTimeMillis() - start));
        }

Java:
protected void paint(Canvas canvas) {
            long start = System.currentTimeMillis();
            canvas.drawBitmap(background, new Rect(backgroundX,(int)(screenHeight), backgroundX + width, (int) (screenHeight + height)), new Rect(0, 0, width, height), null);
            level.drawLevel(new Rect(strecke, (int)(screenHeight), strecke + width, (int)(screenHeight + height)), canvas);
           
            for(EntityMonster monster : level.activeMonsters) {
                monster.draw(canvas, strecke, (int)screenHeight);
            }
           
            if(equiptedPowerUp != null) {
                if(!equiptedPowerUp.isDrawAfterCharacter())
                    equiptedPowerUp.draw(canvas, strecke, (int)screenHeight);
            }
           

            if(isGhost)
                canvas.drawBitmap(currentCharacter, playerRelativePosX , PlayerRelativeHeight, ghostPaint);
            else
                canvas.drawBitmap(currentCharacter, playerRelativePosX, PlayerRelativeHeight, null);
           
           
            for(EntityCoin coin : level.activeCoins) {
                if(coin.isCollected) {
                    coin.draw(canvas, strecke, (int)screenHeight);
                }
                else {
                    canvas.drawBitmap(coinImgs[coinImgNum], coin.getRelativePositionX(strecke), coin.getRelativePositionY((int)screenHeight), null);
                }
            }
           
            for(EntityPowerUp powerUp : level.activePowerUps) {
                powerUp.draw(currentScreenGraphics, strecke, (int)screenHeight);
            }
            if(equiptedPowerUp != null) {
                if(equiptedPowerUp.isDrawAfterCharacter())
                    equiptedPowerUp.draw(currentScreenGraphics, strecke, (int)screenHeight);
            }
           
            for(EntityFlyPlatform platform : level.activeMovingSolids) {
                platform.draw(currentScreenGraphics, strecke, (int)screenHeight, flyPlatformImgNum);
            }

            canvas.drawBitmap(healthImages[Health], width - healthImageWidth, 4, null);
            canvas.drawBitmap(coinImgs[0], 4, coinImgPosY, null);
            canvas.drawText(collectedCoins + "", collectedCoinsTextX, collectedCoinsTextY, textPaint);
            canvas.drawBitmap(powerUpDisplay[powerUpFuel], 10, height - powerUpDisplay[0].getHeight() - 10, null);

           
            if(isPaused){
                Paint pausePaint = new Paint();
                pausePaint.setColor(Color.BLACK);
                pausePaint.setAlpha(100);
                pausePaint.setStyle(Style.FILL);
                canvas.drawRect(new Rect(0,0,width,height), pausePaint);
                canvas.drawText("Pausiert", (float)(width/2 - (90 * GameActivity.scaleFactorX)), (float)(height/2 - (200 * GameActivity.scaleFactorY)), textPaint);
            }
            else if(isDead) {
                Paint deathPaint = new Paint();
                deathPaint.setColor(Color.RED);
                deathPaint.setAlpha(100);
                deathPaint.setStyle(Style.FILL);
                canvas.drawRect(new Rect(0,0,width,height), deathPaint);
                canvas.drawText("Du bist gestorben", (float)(width/2 - (200 * GameActivity.scaleFactorX)), (float)(height/2 - (200 * GameActivity.scaleFactorY)), textPaint);
            }
            System.out.println("paintTime: " + (System.currentTimeMillis() - start));
        }

Der Game-Loop:
Java:
while(running) {
                startTime = System.currentTimeMillis();
                while(!finished) {
                    System.out.println("waiting for game2");
                    try {
                        Thread.sleep(4);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
              
                repaint();
                System.out.println("gameTimeRepaint: " + (System.currentTimeMillis() - startTime));
                synchronized(game2) {
                    game2.notify();
                }
                synchronized(entityManager) {
                    entityManager.notify();
                }
                if(isPaused || isDead) {
                    synchronized(this) {
                        try {
                            this.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    startTime = System.currentTimeMillis();
                }
                System.out.println("gameTime: " + (System.currentTimeMillis() - startTime));
                sleepTime = TPS - (System.currentTimeMillis() - startTime);
                if(sleepTime < 0)
                    sleepTime = 10;
                try {
                    if(pressedSpace) {
                        pressedSpaceTime += sleepTime;
                        if(pressedSpaceTime > maxPressedSpaceTime) {
                            pressedSpaceTime = 0;
                            pressedSpace = false;
                        }
                    }
                    System.out.println("sleepTime: " + sleepTime);
                    Thread.sleep(sleepTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
              
                if(strecke + characterWidth2 >= maxWidth)
                    running = false;
            }

Ausschnitt aus LogCat:
09-19 12:14:41.171: I/System.out(2259): lockCanvasTime: 1
09-19 12:14:41.224: I/System.out(2259): unlockCanvasTime: 51
09-19 12:14:41.272: I/System.out(2259): lockCanvasTime: 2
09-19 12:14:41.324: I/System.out(2259): unlockCanvasTime: 51
09-19 12:14:41.351: I/System.out(2259): lockCanvasTime: 1
09-19 12:14:41.406: I/System.out(2259): unlockCanvasTime: 52
09-19 12:14:41.437: I/System.out(2259): lockCanvasTime: 1
09-19 12:14:41.498: I/System.out(2259): unlockCanvasTime: 60
09-19 12:14:41.532: I/System.out(2259): lockCanvasTime: 2
09-19 12:14:41.583: I/System.out(2259): unlockCanvasTime: 50​

Weiss jemand, wie man dieses Problem beheben kann?

Mit freundlichen Grüssen, Faberix
 

Faberix

Mitglied
Nein, es ist in einem separaten Thread:

Java:
@Override
        public void run() {
            while(!started) {
                try {
                    Thread.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            last = System.currentTimeMillis();
            while(running) {
                startTime = System.currentTimeMillis();
                while(!finished) {
                    System.out.println("waiting for game2");
                    try {
                        Thread.sleep(4);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
               
                repaint();
                System.out.println("gameTimeRepaint: " + (System.currentTimeMillis() - startTime));
                synchronized(game2) {
                    game2.notify();
                }
                synchronized(entityManager) {
                    entityManager.notify();
                }
                if(isPaused || isDead) {
                    synchronized(this) {
                        try {
                            this.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    startTime = System.currentTimeMillis();
                }
                System.out.println("gameTime: " + (System.currentTimeMillis() - startTime));
                sleepTime = TPS - (System.currentTimeMillis() - startTime);
                if(sleepTime < 0)
                    sleepTime = 5;
                try {
                    if(pressedSpace) {
                        pressedSpaceTime += sleepTime;
                        if(pressedSpaceTime > maxPressedSpaceTime) {
                            pressedSpaceTime = 0;
                            pressedSpace = false;
                        }
                    }
                    System.out.println("sleepTime: " + sleepTime);
                    Thread.sleep(sleepTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
               
                if(strecke + characterWidth2 >= maxWidth)
                    running = false;
            }
           
           
            synchronized(game2) {
                game2.notify();
            }
            synchronized(entityManager) {
                entityManager.notify();
            }
            clear();
            GameActivity.Instance.exitGameOnPause();
            if(toMainMenu)
                GameActivity.Instance.backToMainMenu();
            else
                GameActivity.Instance.backToLevelMenu();
        }
 

Oben