安卓2D帆布游戏:FPS抖动问题帆布、问题、游戏、FPS

2023-09-04 09:51:13 作者:最后1次温柔

我根据我的比赛中月球着陆器的演示,虽然重大的修改,我可以避开40-50fps,但问题是,它的波动40-50fps这么多,它会导致移动图形抖动之间!它很烦人的,使我的游戏看起来真的低劣的时候,其实它在一个良好的帧速率运行。

我尝试设置线程的优先级高,但只是让事情变得更糟......现在将40-60fps ...

之间波动

我想限制本FPS至约30,使得这将是恒定的。这是一个好主意,并没有其他人有经验,或不同的解决方案?

谢谢!

这是我跑环

  @覆盖
    公共无效的run(){
        而(mRun){
            帆布C = NULL;
            尝试 {
                C = mSurfaceHolder.lockCanvas(空);
                同步(mSurfaceHolder){
                    如果(mMode服务== STATE_RUNNING){

                        updatePhysics();
                    }
                    doDraw(C);
                }
            } 最后 {
                //这样做的最后,这样,如果抛出一个异常
                //上面的过程中,我们不留在表面
                //不一致的状态
                如果(C!= NULL){
                    mSurfaceHolder.unlockCanvasAndPost(C);
                }
            }
        }
        }

私人无效updatePhysics(){

        现在= android.os.SystemClock.uptimeMillis();

        经过=(现 -  mLastTime)/ 1000.0;

        posistionY + =经过*速度;
        mLastTime =现在;
}
 

解决方案

请不要将您的游戏的逻辑(物体运动等)的帧速率更新率。换句话说,把你的图纸和逻辑更新code。在两个独立的组件/线程。这样,你的游戏逻辑是完全独立于你的帧率。

逻辑更新应根据多少时间已经过去了自上次更新(姑且称之为增量)。因此,如果你有一个对象在移动1像素/毫秒,然后在每一个更新的对象应该做的是这样的:

 公共无效更新(INT增量){
    this.x + = this.speed *增量;
}
 
在线反恐FPS游戏下载 在线反恐FPS游戏最新安卓版 v1.0.5 嗨客手机站

所以,现在就算你的FPS滞后,也不会影响你的对象的移动速度,因为增量只会更大,使物体移动更远的补偿(也有在某些情况下的并发症,但是这是它的要点)。

这是计算你的逻辑更新对象内三角(在某些线程循环中运行)的一种方式:

 专用长lastUpdateTime;
专用长currentTime的;

公共无效更新(){
    currentTime的= System.currentTimeMillis的();
    INT三角洲=(INT)(currentTime的 -  lastUpdateTime);
    lastUpdateTime = currentTime的;
    myGameObject.update(增量); //这就需要像上面的更新方法。
}
 

希望帮助!请询问如果您有任何其他问题;我一直在做Android的游戏自己。 :)

样品code:

复制这两个片段(1活动,1视图),然后运行code。结果应该是一个白点顺利地飘落下来你的屏幕,无论你的FPS是什么。在code看起来有点复杂,漫长,但它实际上很简单;该意见应说明一切。

这活动课不是太重要。你可以在它忽略大部分的code。

 公共类TestActivity延伸活动{

    私人TestView视图;

    公共无效的onCreate(包savedInstanceState){
        //这些线只是增加我们正在使用的视图。
        super.onCreate(savedInstanceState);
        的setContentView(R.layout.randomimage);
        RelativeLayout的RL =(RelativeLayout的)findViewById(R.id.relative_layout);
        鉴于=新TestView(本);
        RelativeLayout.LayoutParams PARAMS =新RelativeLayout.LayoutParams(
                10000,10000);
        rl.addView(查看,则params);

        //这将启动我们的观点的逻辑线程
        view.startMyLogicThread();
    }

    公共无效的onPause(){
        super.onPause();
        //当我们的活动暂停,我们希望我们的观点停止更新它的逻辑。
        //这个prevents在后台,它吃掉了电池运行应用程序。
        view.setActive(假);
    }
}
 

这个类是其中令人兴奋的东西!

 公共类TestView扩展视图{

    //当然,这东西应该是在自己的对象,但只是在这个例子中..
    私人浮动位置; //如果我们的点是
    私人浮速度; //如何快速点的移动

    民营涂料P; // OnDraw的过程中使用的()
    私人布尔活跃; //如果我们的逻辑仍然有效

    公共TestView(上下文的背景下){
        超(上下文);
        //设置一些初步的任意值
        位置= 10F;
        速度= .05f;
        P =新的油漆();
        p.setColor(Color.WHITE);
        积极=真实;
    }

    //我们画了这里的一切。这是默认情况下,在自己的线程(UI线程)。
    //我们只需要调用这个线程THREAD_A。
    公共无效的OnDraw(帆布C){
        c.drawCircle(150,位置,1,P);
    }

    //这只是更新我们的基础上给了一个三角形的位置。
    公共无效更新(INT增量){
        位置+ =增量*速度;
        postInvalidate(); //告诉我们的观点重绘自身,因为我们的立场改变。
    }

    //最重要的部分!
    //这将启动另一个线程(我们称之为THREAD_B)。 THREAD_B将运行完全
    //独立于THREAD_A(以上);因此,FPS变化不会影响如何
    //我们的速度提高了我们的立场。
    公共无效startMyLogicThread(){
        新的Thread(){
            公共无效的run(){
                //存储当前时间值。
                长的时间1 = System.currentTimeMillis的();
                长的时间2;

                //一旦被激活是假的,这个循环(和线程)终止。
                而(活性){
                    尝试 {
                        //这是你的目标三角洲。 25毫秒= 40FPS
                        视频下载(25);
                    }赶上(InterruptedException的E1){
                        e1.printStackTrace();
                    }

                    时间2 = System.currentTimeMillis的(); //获取当前时间
                    INT三角洲=(INT)(时间2  - 时间1); //计算多久它已经从去年的更新
                    更新(增量); //我们的增量调用Update
                    时间1 =时间2; //更新我们的时间变量。
                }
            }
        }。开始(); //开始THREAD_B
    }

    //方法这就是所谓的活动
    公共无效SETACTIVE(布尔有效){
        this.active =有效;
    }
}
 

I based my game off of the lunar lander demo, although heavily modified, and I can get around 40-50fps but the problem is it fluctuates between 40-50fps so much that it causes the moving graphics to jitter! Its very annoying and makes my game look really shitty when in fact its running at a good frame rate.

I tried setting the thread priority higher but that just made it worse... now it will fluctuate between 40-60fps...

I was thinking of limiting the FPS to about 30 so that it will be constant. Is this a good idea and does anyone else have experience or a different solution?

Thanks!

This is my run loop

@Override
    public void run() {
        while (mRun) {
            Canvas c = null;
            try {
                c = mSurfaceHolder.lockCanvas(null);
                synchronized (mSurfaceHolder) {
                    if(mMode == STATE_RUNNING){

                        updatePhysics();
                    }
                    doDraw(c);
                }
            } finally {
                // do this in a finally so that if an exception is thrown
                // during the above, we don't leave the Surface in an
                // inconsistent state
                if (c != null) {
                    mSurfaceHolder.unlockCanvasAndPost(c);
                }
            }
        }
        }

private void updatePhysics() {

        now = android.os.SystemClock.uptimeMillis();

        elapsed = (now - mLastTime) / 1000.0;

        posistionY += elapsed * speed;
        mLastTime = now;
}

解决方案

Don't base your game's logic (object movement, etc.) updating rate on the framerate. In other words, put your drawing and logic updating code in two separate components/threads. This way your game logic is completely independent from your framerate.

Logic updating should be based on how much time has passed since the last update (let's call it delta). Therefore, if you have an object moving at 1px/millisecond, then during each update your object should do something like this:

public void update(int delta) {
    this.x += this.speed * delta;
}

So now even if your FPS lags, it won't affect your object's movement speed, since the delta will just be larger, making the object move farther to compensate (there are complications in some cases, but that's the gist of it).

And this is one way of calculating delta within your logic updating object (running in some thread loop):

private long lastUpdateTime;
private long currentTime;

public void update() {
    currentTime = System.currentTimeMillis();
    int delta = (int) (currentTime - lastUpdateTime);
    lastUpdateTime = currentTime;
    myGameObject.update(delta); // This would call something like the update method above.
}

Hope that helps! Please ask if you have any other questions; I've been making Android games myself. :)

Sample code:

Copy these two snippets (1 activity and 1 view) and run the code. The result should be a white dot smoothly falling down your screen, no matter what your FPS is. The code looks kinda complicated and long, but it's actually quite simple; the comments should explain everything.

This activity class isn't too important. You can ignore most of the code in it.

public class TestActivity extends Activity {

    private TestView view;

    public void onCreate(Bundle savedInstanceState) {
        // These lines just add the view we're using.
        super.onCreate(savedInstanceState);
        setContentView(R.layout.randomimage);
        RelativeLayout rl = (RelativeLayout) findViewById(R.id.relative_layout);
        view = new TestView(this);
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
                10000, 10000);
        rl.addView(view, params);

        // This starts our view's logic thread
        view.startMyLogicThread();
    }

    public void onPause() {
        super.onPause();
        // When our activity pauses, we want our view to stop updating its logic.
        // This prevents your application from running in the background, which eats up the battery.
        view.setActive(false);
    }
}

This class is where the exciting stuff is!

public class TestView extends View {

    // Of course, this stuff should be in its own object, but just for this example..
    private float position; // Where our dot is
    private float velocity; // How fast the dot's moving

    private Paint p; // Used during onDraw()
    private boolean active; // If our logic is still active

    public TestView(Context context) {
        super(context);
        // Set some initial arbitrary values
        position = 10f;
        velocity = .05f;
        p = new Paint();
        p.setColor(Color.WHITE);
        active = true;
    }

    // We draw everything here. This is by default in its own thread (the UI thread).
    // Let's just call this thread THREAD_A.
    public void onDraw(Canvas c) {
        c.drawCircle(150, position, 1, p);
    }

    // This just updates our position based on a delta that's given.
    public void update(int delta) {
        position += delta * velocity;
        postInvalidate(); // Tells our view to redraw itself, since our position changed.
    }

    // The important part!
    // This starts another thread (let's call this THREAD_B). THREAD_B will run completely
    // independent from THREAD_A (above); therefore, FPS changes will not affect how
    // our velocity increases our position.
    public void startMyLogicThread() {
        new Thread() {
            public void run() {
                // Store the current time values.
                long time1 = System.currentTimeMillis();
                long time2;

                // Once active is false, this loop (and thread) terminates.
                while (active) {
                    try {
                        // This is your target delta. 25ms = 40fps
                        Thread.sleep(25);
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }

                    time2 = System.currentTimeMillis(); // Get current time
                    int delta = (int) (time2 - time1); // Calculate how long it's been since last update
                    update(delta); // Call update with our delta
                    time1 = time2; // Update our time variables.
                }
            }
        }.start(); // Start THREAD_B
    }

    // Method that's called by the activity
    public void setActive(boolean active) {
        this.active = active;
    }
}