如果没有触摸事件发生的Andr​​oid SurfaceView放缓 [英] Android SurfaceView slows if no touch events occur

查看:125
本文介绍了如果没有触摸事件发生的Andr​​oid SurfaceView放缓的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想提出一个游戏,除了游戏循环都进行的很顺利。我使用的是SurfaceView并绘制2D精灵(位图)。目前,该游戏是通过船小行星场中运动。船停留在屏幕中心和手机在任一方向倾斜移动的小行星(小行星改变位置,而不是玩家)。新的小行星产卵旧脱落的画面创造无限小行星场的感觉。

I am making a game and all is going well except for the game loop. I am using a SurfaceView and drawing 2D Sprites (Bitmaps). Currently the game is a ship moving through an asteroid field. The ship stays in the center of the screen and the phone is tilted in either direction to move the the asteroids (asteroids change location instead of player). New asteroids spawn as old ones fall off the screen creating an infinite asteroid field feeling.

运行在我的Nexus 5,我注意到,约3秒后,向下移动屏幕上的小行星变得波涛汹涌,尽​​管我的游戏循环设置为60fps的运行。这里曾是code:

Running on my Nexus 5, I noticed that after about 3 seconds, the asteroids moving down the screen became choppy, despite my game loop set to run at 60fps. Here was the code:

@Override
public void run() {
    Canvas canvas;
    long startTime;
    long timeTaken;
    long sleepTime;

    while (running) {
        canvas = null;

        //Update and Draw
        try {
            startTime = System.nanoTime();
            canvas = gameView.getHolder().lockCanvas();

            //Update
            gameModel.update(gameController.getPlayerShots(), gameController.getCurrentTilt());

            //Game Over?
            if (gameModel.isGameOver()) { running = false; }

            //Draw
            synchronized (gameView.getHolder()) { gameModel.drawToCanvas(canvas); }
        }
        finally {
            if (canvas != null) {
                gameView.getHolder().unlockCanvasAndPost(canvas);
            }
        }

        //Sleep if needed
        timeTaken = System.nanoTime() - startTime;
        sleepTime = FRAME_TIME - timeTaken;
        try {
            if (sleepTime > 0) {
                sleep(Math.abs((int)sleepTime/1000000), Math.abs((int)sleepTime % 1000000));
            }

        }
        catch (InterruptedException e) {}
    }

    //Load menu after game over
    if (gameModel.isGameOver()) {
        gameController.launchContinueMenu();
    }
}

我想这个问题可能是我的模型是做绘图画布,而我没有使用我surfaceview的OnDraw()方法。重构使用的onDraw()和相同的结果了。我打印出每帧的睡眠时间和我的线程一直沉睡5-10ms(在一个框架16.667ms),所以我的关系不是短期的计算能力。

I thought the problem may be that my model was doing the drawing to canvas and that I wasn't using my surfaceview's onDraw() method. Refactored to use onDraw() and same result as before. I printed out the sleep time of each frame and my thread was consistently sleeping for 5-10ms (16.667ms in a frame), so my nexus was not short on computing power.

我读了计算器,我不应该在视图上使用支架同步()。仍然没有运气。

I read on stackoverflow that I shouldn't use synchronize() on the view holder. Still no luck.

然后我就再计算器阅读,使用Thread.sleep()方法可能会造成问题,因为它并不总是准确的。我做了一个重大的重构,如下图所示。

Then I read again on stackoverflow that using Thread.sleep() may be causing the issue because it is not always accurate. I did a major refactor as shown below.

@SuppressLint("WrongCall")
@Override
public void run() {
    Canvas canvas;

    while (running) {
        canvas = null;

        //Update and Draw
        try {
            canvas = gameView.getHolder().lockCanvas();

            //Calc and smooth time
            long currentTimeMS = SystemClock.uptimeMillis();
            double currentDeltaTimeMS;
            if (lastTimeMS > 0) {
                currentDeltaTimeMS = (currentTimeMS - lastTimeMS);
            }
            else {
                currentDeltaTimeMS = smoothedDeltaTimeMS; // just the first time
            }
            avgDeltaTimeMS = (currentDeltaTimeMS + avgDeltaTimeMS * (avgPeriod - 1)) / avgPeriod;

            // Calc a better aproximation for smooth stepTime
            smoothedDeltaTimeMS = smoothedDeltaTimeMS + (avgDeltaTimeMS - smoothedDeltaTimeMS) * smoothFactor;

            lastTimeMS = currentTimeMS;

            //Update
            gameModel.update(smoothedDeltaTimeMS / 1000.0d, gameController.getCurrentTilt());

            //Game Over?
            if (gameModel.isGameOver()) { running = false; }

            //Draw
//                synchronized (gameView.getHolder()) {
//                   gameModel.drawToCanvas(canvas);
                gameView.onDraw(canvas);
//                }
        }
        //Release canvas
        finally {
            if (canvas != null) {
                gameView.getHolder().unlockCanvasAndPost(canvas);
            }
        }
    }

    //Load menu after game over
    if (gameModel.isGameOver()) {
        gameController.launchContinueMenu();
    }
}

这个新的方法应该用增量时间像以前绘制下一帧,而不是一组的增量只画尽可能快。仍然没有运气。

This new approach should just draw as fast as possible using delta time to draw next frame instead of a set increment as before. Still no luck.

我改变从矩形的位图我的位置到新位置类我创建了一个使用双,而不是整数来模拟子像素的运动。仍然没有运气。

I changed my bitmap locations from Rect's to a new positions class I created that uses doubles instead of ints to simulate sub-pixel movement. Still no luck.

东西我已经试过回顾:


  1. 使用的onDraw(),而不是gameModel绘图画布

  2. 请不要使用视图上的持有人同步()

  3. 使用时间自上次更新来更新,而不是前进一帧每次更新()调用下一帧。

  4. 删除了Thread.sleep()

  5. 亚像素移动

这一切后,我注意到,游戏运行得很好,而手机正在充电。在3秒后我拔掉电话,本场比赛再次变得波涛汹涌。后来我发现,如果我点击屏幕时,比赛变得波涛汹涌,一切又抚平另外3秒钟。我猜有某种正在影响我的表现SurfaceView电池省电功能?这到底是怎么回事,我该如何禁用它?这是很让人郁闷...

After all this, I noticed that the game run fine while the phone was charging. 3 seconds after I unplug the phone, the game becomes choppy again. Then I noticed that if I tap the screen when the game becomes choppy, everything smoothes out again for another 3 seconds. I'm guessing that there is some kind of battery saving feature that is affecting my SurfaceView performance? What is going on here, and how can I disable it? This is quite maddening...

我又测试了我的第一个游戏循环出于好奇(1 code座),并点击屏幕同时播放,一切都运行平稳。男人......所有的工作增加了复杂白白。我想这是一个很好的学习经验。任何想法如何我可以保持我的SurfaceView全速运行?帮助是极大的AP preciated。

I tested out my first game loop again out of curiosity (1st code block) and tapped the screen while playing and everything ran smoothly. Man... all that work adding complexity for nothing. I guess it's a good learning experience. Any ideas to how I can keep my SurfaceView running at full speed? Help is greatly appreciated.

:)

推荐答案

您的观察是正确的。总之,在N5电源管理积极节流掉电。如果你的手指与屏幕接触时,时钟速度增加,以确保交互是光滑的。 (有关详细信息,请参阅我的回答<一个href=\"http://stackoverflow.com/questions/21172585/android-thread-performance-priority-on-galaxy-note-2-when-screen-is-touched-rele/\">this问题。)

Your observation is correct. In short, the power management in the N5 aggressively throttles the power down. If your finger is in contact with the screen, the clock speeds are increased to ensure that interactions are smooth. (For more, see my answer to this question.)

要处理这种情况最好的办法是要认识到你需要的帧有时会下降。在 Grafika 录制GL应用活动采用一个简单的技巧与编导做到这一点。另请参见关于游戏循环一些额外的想法这篇文章

The best way to handle this is to recognize that you will need to drop frames sometimes. The "Record GL app" activity in Grafika uses a simple trick with Choreographer to do this. See also this article for some additional thoughts about game loops.

这篇关于如果没有触摸事件发生的Andr​​oid SurfaceView放缓的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆