Java w/ Slick - My jump animation seems to jump as fast as the processor can handle

时光毁灭记忆、已成空白 提交于 2020-01-25 11:10:05

问题


I am making a small game using Slick2D and I run across an issue that makes my background move behind my character (who doesn't move). I'm not sure whether this is an issue with Slick or my code (probably the latter). The most frustrating thing about this issue is that it only occurs sometimes. With the exact same code it works perfectly, but it is completely unpredictable. Any ideas on what I can do? Here's my update method (There's some unfinished stuff in here regarding other aspects of the game, so just ignore that):

public void update(GameContainer gc, StateBasedGame sbg, int delta) throws SlickException {
    Input input = gc.getInput();
    if (!grounded) {
        vertVelocity -= GRAVITY;
        charPositionY += (float) vertVelocity;
    }

    if (input.isKeyDown(Input.KEY_A) && !quit) {
        charPositionX += delta * .4f;
    }
    if (input.isKeyDown(Input.KEY_D) && !quit) {
        charPositionX -= delta * .4f;
    }
    if (input.isKeyDown(Input.KEY_SPACE)) {
        if (grounded) {
            vertVelocity = 20;
        }
        grounded = false;
    }
    if (charPositionY < ground) {
        charPositionY = ground;
        grounded = true;
    }

    if (input.isKeyDown(Input.KEY_ESCAPE)) {
        quit = true;
    }
    if (quit) {
        if (input.isKeyDown(Input.KEY_R)) {
            quit = false;
        }
        if (input.isKeyDown(Input.KEY_M)) {
            sbg.enterState(0);
        }
        if (input.isKeyDown(Input.KEY_E)) {
            System.exit(0);
        }
    }
    if (charPositionX > MAP_LEFT_LIMIT) {
        charPositionX = MAP_LEFT_LIMIT;
    }
    for (int i = 0; i < crates.length; i++) {
        int crateShift = -(crates[i].getPosX()) + 428;
        if (charPositionX < crateShift && charPositionX > crateShift - crates[i].getWidth() && charPositionY == 0) {
            for (int k = 0; k < crates.length - 1; k++) {
                charPositionX = crateShift;
            }
        }
        if (onCrate == false && charPositionX < crateShift && charPositionX > crateShift - crates[i].getWidth() && charPositionY > CRATE_HEIGHT_DEFAULT && !grounded) {
            System.out.println(crateShift);
            System.out.println(crateShift - crates[i].getWidth());
            onCrate = true;
            System.out.println("ON CRATE");

        }else{
            onCrate = false;
        }
        if(!onCrate){
            ground = 0;
            System.out.println("NOT ON CRATE");
        }else{
            ground = 100;
        }

        if (charPositionY < 0) {
           charPositionY = 0;
           vertVelocity = 0;
        }
        if (charPositionX > 210 && charPositionX < crates[i].getPosX() - 32 && charPositionY == 0) {
         charPositionX = 210;
         }

        if (charPositionX < - 270 && charPositionX > - 370 && charPositionY <= 75) {
            if (!coinCollected) {
                score++;
                coinCollected = true;
            }
        }
        if (i == crates.length) {
            i = 0;
        }
    }
}

回答1:


Updates to the model and screen are typically managed from within the main thread. This should be a separate thread from the UI so it can "pause" for a specific period of time without preventing the UI from rendering the output or the game engine from processing user input.

The simplest way to do this is to just use Thread.sleep(time) which will cause the current Thread to sleep at least the specified amount of time (in milliseconds). The problem with this is it can produce uneven updates.

What I mean by this, is if it took 20 milliseconds to update the model and schedule UI updates on one cycle, but only 10 milliseconds on the next and 30 on the next, the timing will become uneven.

For example, assuming you're using 25fps, you will need a 40 millisecond delay.

  • Cycle #1, update 20 milliseconds, 40 millisecond delay, total delay = 60 milliseconds
  • Cycle #2, update 10 milliseconds, 40 millisecond delay, total delay = 50 milliseconds
  • Cycle #3, update 30 milliseconds, 40 millisecond delay, total delay = 70 milliseconds

This will start throwing out your framerate and could make you updates look jaggared.

Another solution is to record the time it takes to perform a given update and subtract that from the amount of time you want to wait in order to ensure that the frame rate stays as constant as possible.

long startTime = System.currentTimeMillis();
// Update the game state...
long endTime = System.currentTimeMillis();
long cycle = endTime - startTime;
long delay = MAX_DELAY - cycle;
Thread.sleep(delay); // This might need to be wrapped in a try-catch

For example, assuming that MAX_DELAY = 40...

  • Cycle #1, update 20 milliseconds, 40 - 20 = 20 millisecond delay, total delay = 40 milliseconds
  • Cycle #2, update 10 milliseconds, 40 - 10 = 30 millisecond delay, total delay = 40 milliseconds
  • Cycle #3, update 30 milliseconds, 40 - 30 = 10 millisecond delay, total delay = 40 milliseconds

Now, you could use System.nanoTime, but IMHO, unless you have a MAX_DELAY of around 5 milliseconds (roughly 200fps), the extra work it requires to translate the time to milliseconds doesn't bring a lot of benefit - remember HD is 60fps, roughly 16 milliseconds.

This is all theory and how this is applied to a specific API will differ.

You're next step is to look up a good tutorial that explains this in much better details in relationship to the Slick2D API.



来源:https://stackoverflow.com/questions/21817745/java-w-slick-my-jump-animation-seems-to-jump-as-fast-as-the-processor-can-han

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!