Я пытаюсь расширить навыки ООП, пытаясь запрограммировать 2D-графическую игру. Использование утилиты Java swing.
Теперь то, что я до сих пор: 4 общих класса, абстрактный класс, интерфейс и класс KeyListener. (Не волнуйся, это очень маленькая игра на данный момент).
Из 4 общих классов основной класс устанавливает два других класса в качестве объектов внутри него. Этими двумя объектами являются моя графика и мой гаджет. Gamestate, в свою очередь, устанавливает последний оставшийся объект (игрока) внутри него.
Проблема заключается в том, что когда я изначально получил все, чтобы он работал, чтобы игрок мог перемещаться (через keyPressed), как считывается ввод с клавиатуры, игрок слегка дрогнул вперед, а затем бегал в непрерывном движении. Именно так, если вы удерживаете клавишу буквы на клавиатуре, перед тем, как начнется формирование строки, появится буква.
Поэтому я подумал: "О, это так очевидно. Я должен попытаться справиться с этим с помощью булевых элементов, чтобы при смене ключа у меня было" boolean right = true ". И у меня будет некоторый код, где-то уходит в цикле с условными операторами для перемещения игрока ".
Вот где я застрял. Потому что я не могу понять, как попасть в этот цикл без "заклинивания" моей программы. В попытках я запускал свою программу и не обращался ни к чему. Программа зависает, потому что она в цикле и пока еще не открыла окно поворота. У меня есть ощущение, что ответ связан с потоком (реализует runnable), но я нахожусь на такой новой территории с этим, что я хочу "правильный и хороший" способ сделать это.
Поэтому я полагаю, что это очень открытый вопрос для множества ответов. Как бы вы справились с этой проблемой?
--- РЕДАКТИРОВАТЬ*
Вот все исходные файлы по запросу. https://www.dropbox.com/sh/f4diy7qtzh4xkem/AABUkM415PrRK1hu35TVkBo2a
Общие классы: Main, Window, GameState, Robot. Интерфейсы: Тезисы движения: GameVisualiser Слушатели: ArrowPress
Простите некоторые комментарии.
Ну, вы не вдавались в подробности, какую игру вы делаете.
Независимо от этого, его легко угадать, какова ваша проблема. Вы только продвигаете свое состояние игр в прямом ответе на какое-то входное событие (вы упомянули KeyListener). Такая архитектура, основанная исключительно на входных событиях, отлично подходит для игр, которые только делают что-то в ответ на ввод пользователей (например, простые карточные или настольные игры).
Но, похоже, вы хотите продвинуть свое игровое состояние в тот момент, когда пользователь не вводит пользователя (например, между KeyDown и событием KeyUp). В этом случае вам понадобится то, что обычно называется игровым циклом, где игра фактически работает, постоянно обновляя состояние игры (обычно с фиксированными интервалами времени).
У вас есть два варианта:
a.) Использование нескольких потоков, которые имеют крутую кривую обучения для новичков, но очень гибкие.
b.) Создайте событие искусственно с фиксированной скоростью для продвижения состояния игры (это также будет использовать потоки под капотом, но вам не нужно разбираться с деталями):
Взгляните на класс java.swing.Timer. Вы создаете экземпляр Timer, который запускается с регулярными интервалами (скажем каждые 32 миллисекунды, что составляет примерно 30 раз в секунду). Таймер генерирует событие (вы присоединяете слушателя к таймеру, чтобы получать уведомление о событии) через равные промежутки времени. Теперь вы перемещаете все состояние игры в это событие действия. Это превращает вашу игру из входного события, управляемого в игру, управляемую тиком, давая вам возможность продвигать состояние игры при каждом тике по мере необходимости.
В вашем KeyListener вы просто обновите флаги для "перемещений в направлении", фактическое движение будет сделано в событии галочки с таймера.
Причина, по которой вы получаете отрывистое движение прямо сейчас, вероятно, вы полагаетесь на событие KeyTyped, которое создается искусственно путем swing - одно событие в момент нажатия клавиши, затем задержка, затем, наконец, после этой начальной задержки событие запускается с ключевую частоту повторения (заданную в настройках системы) до тех пор, пока клавиша не будет отпущена. Это не очень подходит для игры, вы лучше обрабатываете события KeyPressed и KeyReleased, которые отражают то, что пользователь действительно делает на клавиатуре.
Подход a.) С потоками по существу делает то же самое, с большей свободой и всем под вашим контролем - но еще много подводных камней, о которых нужно знать, таких как параллелизм и условия гонки.
Я бы предложил использовать потоки, которые позволят вам одновременно выполнять две вещи (в вашем случае рисовать игру и обрабатывать эти входы). Если вы сделаете позицию игрока открытой, вы должны будете создать поток, который обрабатывает вход и записывает в позицию, а основной поток (тот, который отображает игру) читает эту позицию. Вся информация, которая вам нужна, находится на странице документа оракула.