Java w/Slick — моя анимация прыжка, кажется, прыгает так быстро, как может обрабатывать процессор.

Я делаю небольшую игру, используя Slick2D, и столкнулся с проблемой, из-за которой мой фон перемещается за моим персонажем (который не двигается). Я не уверен, проблема ли это в Slick или в моем коде (вероятно, в последнем). Самое неприятное в этой проблеме то, что это происходит только иногда. С точно таким же кодом работает отлично, но совершенно непредсказуемо. Любые идеи о том, что я могу сделать? Вот мой метод обновления (Здесь есть кое-что незаконченное, касающееся других аспектов игры, так что просто игнорируйте это):

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;
        }
    }
}

person Conner Gillette    schedule 16.02.2014    source источник
comment
Есть ли какая-то сделка в вашем основном цикле, которая контролирует частоту кадров?   -  person MadProgrammer    schedule 17.02.2014
comment
Нет. Как мне это сделать?   -  person Conner Gillette    schedule 17.02.2014
comment
Все, что мне нужно сделать, это gc.setVSync(true); Я не умный человек. Спасибо за вашу помощь.   -  person Conner Gillette    schedule 17.02.2014


Ответы (1)


Обновления модели и экрана обычно управляются из основного потока. Это должен быть отдельный поток от пользовательского интерфейса, чтобы он мог «приостанавливать» на определенный период времени, не мешая пользовательскому интерфейсу отображать выходные данные или игровому движку обрабатывать пользовательский ввод.

Самый простой способ сделать это — просто использовать Thread.sleep(time), что приведет к тому, что текущий Thread будет спать по крайней мере указанное количество времени (в миллисекундах). Проблема в том, что это может привести к неравномерным обновлениям.

Я имею в виду, что если для обновления модели и планирования обновлений пользовательского интерфейса в одном цикле требуется 20 миллисекунд, но только 10 миллисекунд в следующем и 30 миллисекунд в следующем, время станет неравномерным.

Например, если вы используете 25 кадров в секунду, вам потребуется задержка в 40 миллисекунд.

  • Цикл №1, обновление 20 мс, задержка 40 мс, общая задержка = 60 мс
  • Цикл №2, обновление 10 мс, задержка 40 мс, общая задержка = 50 мс
  • Цикл №3, обновление 30 мс, задержка 40 мс, общая задержка = 70 мс

Это начнет выбрасывать вашу частоту кадров и может сделать ваши обновления неровными.

Другое решение состоит в том, чтобы записать время, необходимое для выполнения данного обновления, и вычесть это время из времени, которое вы хотите ждать, чтобы обеспечить максимально постоянную частоту кадров.

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

Например, если предположить, что MAX_DELAY = 40...

  • Цикл №1, обновление 20 миллисекунд, 40 - 20 = задержка 20 миллисекунд, общая задержка = 40 миллисекунд
  • Цикл № 2, обновление 10 миллисекунд, 40 - 10 = задержка 30 миллисекунд, общая задержка = 40 миллисекунд
  • Цикл № 3, обновление 30 миллисекунд, 40 - 30 = задержка 10 миллисекунд, общая задержка = 40 миллисекунд

Теперь вы можете использовать System.nanoTime, но ИМХО, если у вас нет MAX_DELAY около 5 миллисекунд (примерно 200 кадров в секунду), дополнительная работа, необходимая для перевода времени в миллисекунды, не приносит большой пользы - помните, что HD составляет 60 кадров в секунду, примерно 16 миллисекунд.

Это все теория, и то, как это применяется к конкретному API, будет отличаться.

Следующим шагом будет поиск хорошего учебника, в котором это объясняется более подробно в связи с Slick2D API.

person MadProgrammer    schedule 16.02.2014