Вызовите перерисовку из другого класса в Java? - PullRequest
4 голосов
/ 21 апреля 2009

Я, вероятно, делаю это неправильно, поэтому, пожалуйста, будьте милы Я занимаюсь разработкой Java-игры и нахожусь на стадии тестирования движения / анимации персонажей.

«Человек» может двигаться вверх и вниз влево и вправо по сетке. Класс, в котором нарисована сетка, является классом gamePanel. Кнопки находятся в классе gameControlPanel.

У меня есть кнопка, которая порождает человека в сетке. Затем у меня есть кнопка для перемещения человека вверх и вниз влево и вправо.

При нажатии кнопки перемещения вверх вызывается метод перемещения вверх из класса person. (На данный момент я тестирую только одного «человека» за раз.) В этом методе следующий код ...

int move = 10;
while(move!=0)
{
    setTopLeftPoint(new Point((int)getTopLeftPoint().getX(),
                              (int)getTopLeftPoint().getY() - 3));

    try
    {
        Thread.sleep(300);
    } catch (InterruptedException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }   
    move-=1;
}

Проблема в том, что я не могу вызвать метод repaint для класса gamePanel из класса Person. Чтобы обойти это, я создал таймер в классе gamePanel, который перерисовывает каждые 20 мс.

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

Я постараюсь ответить на любые вопросы по этому поводу.

Ответы [ 4 ]

2 голосов
/ 21 апреля 2009

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

Как общее практическое правило, вы не хотите выполнять какие-либо длительные вычисления в потоке AWT (в том числе в обработчиках событий), поскольку они не позволят приложению реагировать на другие события до ваши расчеты сделаны. Это часто будет отображаться пользователю как застрявшие кнопки, как вы описали. Чтобы обойти это, используйте SwingWorker , который может выполнять вычисления в отдельном потоке.

Наконец, нужно знать (но не обязательно менять), что таймеры и сны не гарантируют, когда они проснутся. Скорее, они гарантируют, что не проснутся до истечения времени, но теоретически могут спать бесконечно. Кроме того, не все машины имеют разрешение таймера 1 мс. В частности, на многих компьютерах с Windows таймеры имеют разрешение только 55 мс, поэтому таймер на 20 мс может давать странные результаты.

1 голос
/ 23 апреля 2009

Если вы хотите перекрасить с определенным интервалом, javax.swing.Timer, вероятно, класс для вас. В конкретном случае repaint вы можете вызывать его из не-EDT-потока, но вы можете столкнуться с трудностями, поскольку теперь вы имеете дело с несколькими потоками.

0 голосов
/ 21 апреля 2009

Обрабатывается ли нажатие кнопки потоком обработки событий вашего графического интерфейса?

Если это так, то метод перерисовки в графическом интерфейсе не будет запускаться до тех пор, пока не завершится поток отправки события (т.е. когда кнопка отпущена и она выходит из цикла). У меня недавно была эта проблема, и лучшее решение, которое я могу предложить, - это сделать класс с алгоритмом перемещения потоковым и запустить поток при обнаружении нажатия клавиши. Это позволяет завершить поток обработки события и поэтому позволяет перерисовывать графический интерфейс.

Для получения дополнительной информации о потоке см. Начало потока .

0 голосов
/ 21 апреля 2009

У меня нет большого опыта в создании игр, но наличие цикла для управления всей анимацией является фундаментальным аспектом игрового программирования. В большинстве простых 2D-игр есть только 1 цикл для рендеринга большей части анимации.

По моему опыту, хороший способ визуализации целой связки - это собрать коллекцию всех сущностей в вашей игре в одном месте и просто перебрать эту коллекцию, передав объект Graphics для каждой сущности.

Это позволит каждой сущности рисовать себя на графическом объекте. Хотя это всего лишь один из способов сделать это.

synchronized ( entities ) {
    for ( Entity e : entities ) {
        e.draw( g );
        e.doAction();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...