Java w/ Slick - My jump animation seems to jump as

2019-09-09 17: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条回答
2楼-- · 2019-09-09 17:27

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.

查看更多
登录 后发表回答