2013-10-15 3 views
1

Я делаю java 2d-скроллер и имейте проблемы с несколькими ключами одновременно. Такие как правые + вверх. Всякий раз, когда вы отпускаете вверх, вы перестаете двигаться вправо, когда вы медленно возвращаетесь на землю, хотя правое все еще нажато. Вот слушатели клавиатуры, которые у меня установлены. dx - моя горизонтальная скорость движения, а dy - вертикальная высота. Ниже от класса персонажаИгровой лаг при отпускании клавиши

public void keyPressed(KeyEvent e) { 
    int key = e.getKeyCode(); 
    if (key == KeyEvent.VK_LEFT) { 
     dx = -5; 
     mainCharacterImageFacing = l.getImage(); 
     } 

    if (key == KeyEvent.VK_RIGHT) { 
     dx = 5; 
     mainCharacterImageFacing = r.getImage(); 
    } 

    if (key == KeyEvent.VK_UP) { 
     dy = 1; 
     mainCharacterImageFacing = r.getImage(); 
    } 

} 

public void keyReleased(KeyEvent e) { 
    int key = e.getKeyCode(); 
    if (key == KeyEvent.VK_LEFT); 
    dx = 0; 
    if (key == KeyEvent.VK_RIGHT) 
     dx = 0; 
    if (key == KeyEvent.VK_UP) 
     {dy = 0; 
     mainCharacterImageFacing = r.getImage(); 
     } 

Это часть кода из главного окна игры, которая имеет дело с вызовом основных методов нажатие/отпускание, а также о скачке.

private class AL extends KeyAdapter{ 
    public void keyReleased(KeyEvent e) { 
     p.keyReleased(e); 
    } 

    public void keyPressed(KeyEvent e) { 
     p.keyPressed(e); 
    } 
} 

@Override 
public void run() 
{ 
    long beforeTime; 
    long timeDiff; 
    long sleep; 

    beforeTime = System.currentTimeMillis(); 
    while(done == false) 
    { 
     cycle(); 
     timeDiff = System.currentTimeMillis() - beforeTime; 
     sleep = 10 - timeDiff; 
     if (sleep < 0) 
      sleep = 2; 
     try { 
      Thread.sleep(sleep); 
     } catch (Exception e) 
     {} 
     beforeTime = System.currentTimeMillis(); 
    } 
    done = false; 
    h = false; 
    k = false; 
} 

boolean h = false; 
boolean done = false; 
public void cycle() { 
    if (h == false) 
     v = v - 2; //jump speed falling 
    if (v == 350) //max y value of jump. Lower numbers = higher jumps 
     h = true; 
    if (h == true && v <= 470) //starting y value 
     { 
     v = v + 2; //jump speed rising 
     if (v == 470) 
      done = true; 
    } 

} 

ответ

2

Не обрабатывайте движение непосредственно в классе AL. Вместо этого используйте булевы и установить их истина/ложь соответственно:

private class AL extends KeyAdapter{ 
    public void keyPressed(KeyEvent e) { 
     int key = e.getKeyCode(); 
     if (key == KeyEvent.VK_LEFT) { 
      left = true; 
     } 

     if (key == KeyEvent.VK_RIGHT) { 
      right = true 
     } 

     if (key == KeyEvent.VK_UP) { 
      //... 
     } 

    } 

    public void keyReleased(KeyEvent e) { 
     int key = e.getKeyCode(); 
     if (key == KeyEvent.VK_LEFT) 
      left = false 
     if (key == KeyEvent.VK_RIGHT) 
      right = false 
     if (key == KeyEvent.VK_UP) 
      //... 
     } 
    } 

Причина этого заключается в том, потому что Keypressed и keyReleased вызываются, когда ключи действовали на, хотя это означает, что она не будет синхронизирована с вашей основной петля.

Чтобы переместить ваш спрайт, вызовите метод в цикле, который, если ваши условия верны, соответственно перемещает ваш спрайт, иначе ничего не делает.

EDIT: После пересмотра кода еще несколько предложений.

Прежде всего, посмотрите подпиксельная визуализация. Подпиксельная рендеринга используется для того, чтобы движение спрайтов выглядело более плавным.

Еще одна вещь, которую нужно искать, - это переменные временные метки (иногда называемые временными интервалами дельта). Время Delta можно использовать, чтобы убедиться, что действия выполняются синхронно с игроками fps. Если один игрок имеет 60 кадров в секунду, а другой - 30 кадров в секунду, игрок с 30 кадрами в секунду будет видеть действия, выполняемые на половине скорости. Тем не менее, с дельта-таймером действия всегда выполняются с одинаковой скоростью. Here's a good article.

В-третьих, ваше время. В настоящее время вы используете System.getCurrentTimeMills. Это плохо, а не точно. Вместо этого используйте System.nanoTime.

Четвертое, что я заметил, это ваш алгоритм прыжка. Лучше всего включить ускорение. Сначала вам нужно объявить константу для ускорения (0.1 или 0.2 хороши) и подсчитать вертикальную скорость. Затем вы можете упасть, когда вертикальная скорость достигает определенного значения. Вот небольшой фрагмент, хотя, если у вас есть гравитация, вы можете отредактировать его. Прежде всего установите vSpeed, чтобы сказать -8 по умолчанию.

public void jump() { 
    vSpeed += ACCELERATION; 
    if(vSpeed < 8) 
     dy += vSpeed; 
    else 
     vSpeed = -8; 
     falling = false; 
} 

Я просто написал это с верхней части моей головы, но в принципе, так как перемещение вверх забирает номер, вы, кажется, прыгать, когда он добавляет отрицательные числа, то вы начнете падать, когда он достигает 0 , а земля снова достигает 8.

0

Проблема заключается в том, как ОС обрабатывает ключевые события и передает их в ваше приложение. Когда вы нажимаете клавишу, она запускает событие для перехода вниз. Затем, основываясь на ваших настройках для повторения, он начнет нажимать клавишу снова через некоторое время на некоторой частоте. (вы можете видеть это при наборе текста. Нажмите клавишу и удерживайте ее).

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

Это будет несовместимо с каждым os, и люди могут обманывать вашу игру, как есть, тем самым ускоряя повторный таймер на клавиатуре.

По этим причинам очень плохая идея делать анимации внутри ключевых слушателей. У вас должны быть флаги настроек true/false и их чтение в игровом цикле. (Как показано в ответе @ «Устранение неполадок»).

Смежные вопросы