Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/226.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Android'中独立于CPU速度进行计算和绘图;s SurfaceView_Android_2d_Surfaceview - Fatal编程技术网

在Android'中独立于CPU速度进行计算和绘图;s SurfaceView

在Android'中独立于CPU速度进行计算和绘图;s SurfaceView,android,2d,surfaceview,Android,2d,Surfaceview,为了使用SurfaceView在Android中绘制2D游戏,我在主要活动的onCreate()中使用了它: 这是对此类的引用: public class GameView extends SurfaceView implements SurfaceHolder.Callback 此外,我还有一个线程,它的run()函数: public void run() { Canvas c; while (_run) { c = null; try {

为了使用SurfaceView在Android中绘制2D游戏,我在主要活动的
onCreate()
中使用了它:

这是对此类的引用:

public class GameView extends SurfaceView implements SurfaceHolder.Callback
此外,我还有一个线程,它的
run()
函数:

public void run() {
    Canvas c;
    while (_run) {
        c = null;
        try {
            c = _surfaceHolder.lockCanvas(null);
            synchronized (_surfaceHolder) {
                _panel.updatePhysics();
                _panel.onDraw(c);
            }
        }
        finally { // when exception is thrown above we may not leave the surface in an inconsistent state
            if (c != null) {
                _surfaceHolder.unlockCanvasAndPost(c);
            }
        }
    }
}
updatePhysics()
中,我进行了一些计算。当然,它们比这个简单的示例更复杂,但工作方式相同:

public void updatePhysics() {
    GraphicObject.Coordinates coord;
    GraphicObject.Speed speed;
    for (GraphicObject graphic : _allElements) {
        coord = graphic.getCoordinates();
        speed = graphic.getSpeed();
        coord.setX(coord.getX() + speed.getX());
        coord.setY(coord.getY() + speed.getY());
        ...
    }
}
onDraw()
中,我将所有内容都绘制到画布上:

@Override
public void onDraw(Canvas canvas) {
    canvas.drawBitmap(BITMAP, xPos, yPos, null);
    ...
}
这一切都很好。当我在我的设备上测试它时,它看起来相当不错。但是当我把它给了其他人,他做了一个测试游戏,物体移动得更快!为什么会这样?因为线程尽可能频繁地调用
updatePhysics()
,这意味着快速设备更频繁地调用此函数

如何防止这种情况发生,并使游戏在所有设备上都同样快速?像这样的

private long lastRun = System.currentTimeMillis();

public void updatePhysics() {
    long millisPassed = System.currentTimeMillis()-lastRun;
    ...
    float newCoord = (coord.getX() + speed.getX()) * millisPassed / 33;
    coord.setX(newCoord);
    ...
}

谢谢你的帮助

当我开始渲染帧时,我会节省时间(在你的例子中是updatePhysics()),然后下次我到达这一点时,我知道要花多少时间,如果时间过得太快,你可以使用

如果可以,直接使用时间来计算你所有的物理量。这通常效果最好

如果您无法基于时间进行计算,因为您所做的只是基于步骤的,并且您知道生成下一步不会花费太多时间,那么您有另一个选择

创建两个线程。第一种方法是以固定速率推进状态(您必须确保这也能以该速率在低速设备上运行)。第二种方法获取当前状态,即查看并绘制该状态。现在,第二个线程可以像它想要的那样慢,因为它只是跳过一些状态(或者如果更快,则多次绘制相同的状态)

下面的小示例有一个线程,它推进某个状态对象并每次替换引用,因此使用线程不必担心它的状态对象被修改

class GameState {
    private int state = 0;

    public GameState advanceState() {
        GameState result = new GameState();
        result.state = this.state + 1;
        return result;
    }
}

class SurfaceViewImplementation extends SurfaceView {

    // the current state
    volatile GameState mState = new GameState();

    void somewhere() {
        Thread fastProducer = new Thread(new Runnable() {
            private static final long MAX_WAIT = 1000 / 60; 
            @Override
            public void run() {
                while (!Thread.interrupted()) {
                    long timeBefore = SystemClock.currentThreadTimeMillis();
                    GameState newState = mState.advanceState();
                    mState = newState;
                    long timeAfter = SystemClock.currentThreadTimeMillis();
                    long timeSpent = timeAfter - timeBefore;
                    SystemClock.sleep(Math.max(0, MAX_WAIT - timeSpent));
                }
            }
        });
        fastProducer.start();
        Thread slowConsumer = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!Thread.interrupted()) {
                    GameState currentState = mState;
                    longRunningDraw(currentState);
                }
            }
        });
        slowConsumer.start();
    }
}

如果生产线程不能以所需的速率运行,那么仍然无法提供与速度无关的结果。

与您的建议完全相同。您需要一些系统时钟的参考。要么以固定的时间间隔更新(这会限制帧速率,因此可能不好),要么根据时间计算,使其直接依赖于时间(2),而不是依赖于帧。帧率改变,因此,不是每一帧都意味着相同的时间跨度。谢谢你,扎普和古斯塔沃!所以我需要用类似于
*milliu seconds\u passed/40
?通过常数
40
我可以确定一切的速度,对吗?
睡眠
只有在你想要一个上限(例如60fps)的情况下才起作用,但是如果设备比你的上限慢,你仍然会遇到同样的问题。当它慢的时候你不会睡觉,只有当它快的时候,当它慢的时候你除了尝试改进你的设计之外别无选择,也许可以尝试OpenGL,但这意味着如果你在一两帧内降到35fps,那么你的物理就会变得一团糟。根据经过的时间更新您的物理是标准和最佳解决方案。感谢您提供此替代解决方案!你的介绍让我很容易做出决定,而我选择的解决方案将取决于时间。
class GameState {
    private int state = 0;

    public GameState advanceState() {
        GameState result = new GameState();
        result.state = this.state + 1;
        return result;
    }
}

class SurfaceViewImplementation extends SurfaceView {

    // the current state
    volatile GameState mState = new GameState();

    void somewhere() {
        Thread fastProducer = new Thread(new Runnable() {
            private static final long MAX_WAIT = 1000 / 60; 
            @Override
            public void run() {
                while (!Thread.interrupted()) {
                    long timeBefore = SystemClock.currentThreadTimeMillis();
                    GameState newState = mState.advanceState();
                    mState = newState;
                    long timeAfter = SystemClock.currentThreadTimeMillis();
                    long timeSpent = timeAfter - timeBefore;
                    SystemClock.sleep(Math.max(0, MAX_WAIT - timeSpent));
                }
            }
        });
        fastProducer.start();
        Thread slowConsumer = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!Thread.interrupted()) {
                    GameState currentState = mState;
                    longRunningDraw(currentState);
                }
            }
        });
        slowConsumer.start();
    }
}