KeyListener отстает непостоянно

1

Я пишу небольшую игру на Java, и, как и в большинстве игр, мне нужно слушать вход пользователя. Я решил использовать java.awt.event.KeyListener для обработки входных данных.

Вот мой основной метод:

public static void main(String[] args){
    LevelViewer l = new LevelViewer(LevelFileIO.load());
    List<Entity> entities = l.getEntities();
    List<GameObject> gameObjects = l.getGameObjects();
    Pacman player = null;
    for (Entity e : entities){
        if (e instanceof Pacman){
            player = (Pacman)e;
            break;
        }
    }


    JFrame frame = new JFrame();
    frame.add(l);
    frame.setResizable(false);
    frame.pack();
    frame.setVisible(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setFocusable(true);
    frame.requestFocus();

    class Listener implements KeyListener{
        Pacman player;


        Listener(Pacman player){
            this.player = player;
        }

        @Override
        public void keyPressed(KeyEvent e) {
            switch(e.getKeyCode()){
            case KeyEvent.VK_W:
                player.up();
                break;
            case KeyEvent.VK_D:
                player.right();
                break;
            case KeyEvent.VK_S:
                player.down();
                break;
            case KeyEvent.VK_A:
                player.left();
                break;
            }


        }

        @Override
        public void keyReleased(KeyEvent e) {}

        @Override
        public void keyTyped(KeyEvent e) {}

    }
    frame.addKeyListener(new Listener(player));
    Timer timer = new Timer();
    timer.schedule(new UpdateTimer(
            entities.toArray(new Entity[entities.size()]),
            gameObjects.toArray(new GameObject[gameObjects.size()]),
            l), 0, 17);
}

Это все довольно просто, когда я читаю ключевые события, я вызываю методы в проигрывателе, которые просто меняют его скорость.

Пример:

public void right(){
    this.setVelocity(new Vector2(speed, 0));
    this.setSprite(right);
}

Таймер в конце основного метода просто вызывает это:

public UpdateTimer(Entity[] toUpdate, GameObject[] gameObjects, LevelViewer toRedraw){
    this.toUpdate = toUpdate;
    this.gameObjects = gameObjects;
    this.toRedraw = toRedraw;
}

@Override
public void run() {
    toRedraw.repaint();
    if (timeAtLastUpdateCall == 0){
        timeAtLastUpdateCall = System.currentTimeMillis();
        for (Entity e : toUpdate){
            e.start();
        }
        return;
    }
    long newTime = System.currentTimeMillis();
    double deltaT = ((double)(newTime - timeAtLastUpdateCall)/1000.0);
    timeAtLastUpdateCall = newTime;
    for (Entity e : toUpdate){
        for (GameObject g : gameObjects){
            if (g.touching(e)){
                e.setVelocity(e.getVelocity().multiply(-1));
                e.free(g);
            }
        }
        e.update(deltaT);
        e.getSprite().nextFrame();
    }
}

Вся эта функция запуска выполняет некоторую проверку столкновений, а затем вызывает метод обновления в каждом объекте. В случае с игроком он просто вычисляет, сколько он должен двигаться с момента последнего вызова обновления:

public void update(double deltaT){
    this.setPosition(this.getPosition().add(velocity.multiply(deltaT)));
}

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

Это проблема с Java KeyListener или с моей реализацией?

Я хотел бы исправить это, чтобы иметь гладкий пользовательский ввод.

  • 1
    Чтобы быстрее получить помощь, опубликуйте MCVE (минимальный завершенный проверяемый пример) или SSCCE (короткий, автономный, правильный пример).
Теги:
awt
keylistener

1 ответ

0

Я не думаю, что это проблема с KeyListener. Я не разработчик игры, но некоторые вещи, которые нужно учитывать:

  1. Вы приурочили время, необходимое для выполнения TimerTask? Если это когда-либо более 17 мс, это может быть проблемой, особенно когда вы сравниваете расписание с графикомAtFixedRate
  2. Вы можете использовать правильный игровой цикл, особенно если вы планируете играть в эту игру в системах, находящихся вне вашего контроля.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню