Должен ли я использовать SwingWorker, многопоточность или рекурсивное обновление для этой анимации? - PullRequest
1 голос
/ 23 апреля 2009

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

Я планировал использовать код, который я вставил в этот вопрос . Однако это не сработало, и мне сказали, что я должен использовать SwingWorker.

Будучи решателем проблем, я думал об этом весь день, и у меня была мысль. Я мог бы добиться того же эффекта, действуя немного по-другому.

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

Моя идея состояла в том, чтобы я мог вызвать метод перед перерисовкой в ​​событии для таймера, который переместил бы всех людей на 1 единицу ближе к их месту назначения (следующий квадрат / клетка). Будет ли это работать? Позже в игре может быть около 100 человек. Хватит ли 20 мс времени, чтобы пройти через всех людей и переместить их на одну единицу ближе к месту назначения? 20 мс слишком мало времени? Я просто не имею никакого смысла?

Ваши мнения / ответы / мысли приветствуются:)

Ответы [ 3 ]

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

Я согласен почти со всем, что сказал Билл, особенно с тем, что Swing загадочен (хотя на самом деле не так сильно, как другие графические среды).

Чтобы дать несколько ссылок, 30 кадров в секунду (это то, что производит большинство чересстрочных экранов) составляет 1 кадр каждые 33 мс. 60 кадров в секунду - это самый высокий показатель, который могут воспринимать люди (1 кадр / 16 мс), и большинство ЖК-мониторов обновляются с частотой 60 или 75 Гц, что будет абсолютным быстродействием, которое вы на самом деле можете произвести. 20 мс / кадр - это частота кадров 50 кадров в секунду, которая также совпадает с электрической частотой на европейских территориях и просто заметна человеческому глазу.

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

Еще одно предупреждение: в то время как рисование должно выполняться в потоке AWT, а расчеты по нему (чтобы ваша программа реагировала), состояние также должно обновляться в потоке AWT. Если вы позволите потоку, выполняющему вычисления, обновить состояние игры, то поток AWT увидит это в середине перерисовки, что приведет к эффекту, называемому разрывом. Таким образом, вам может потребоваться сделать копию состояния для публикации в ветке AWT. Для этого и предназначен SwingWorker, который вы, вероятно, будете использовать вместе с таймером.

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

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

ОК, сначала ответьте на вопрос 20 миллис. Вы можете получить довольно много игровой логики за 20 мс. Но я бы сказал, что слишком часто обновлять дисплей. Вы также должны иметь в виду, что ОС обычно выделяет процессор в порядке временных интервалов 10–20 мс - иными словами, другой процесс в любой момент может легко задержать ваш процесс примерно на такое же время. Посмотрите, например, мою статью о поведении Thread.sleep () - обратите внимание на график, что, поскольку система умеренно загружена, ОС не может выполнить заданное нами время ожидания за. Если вам нужен средний сон между кадрами в 100 мс, то 20 мс или около того дрожание здесь и там не будет слишком плохим. Но дрожание 20 мс, когда вы просите 20 мс, вероятно, будет более заметным ...

Так что я, вероятно, начну с 10 кадров в секунду (паузы 100 мс) и посмотрю, как это выглядит.

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

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

В этой области свинга, пожалуй, самая "черная магия" из всех на Яве. Это может быть сложно, и есть много подходов.

Самое важное правило - никогда не изменять экран, если вы не участвуете в потоке AWT, но не используйте поток AWT для чего-то большего, чем просто для изменения экрана.

Поскольку каждый свинг "Callback" (например, прослушиватель кнопок) входит в поток AWT, вам обычно не нужно об этом думать, но при активной ситуации рендеринга вы должны уделять пристальное внимание.

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

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

Затем каждый компонент должен посмотреть на свое состояние (которое уже обновлено) и использовать эту информацию для рисования.

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

...