Отделение физики и игровой логики от кода пользовательского интерфейса

12

Я работаю над простой блочной игрой-головоломкой.

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

Я разделил код на две части: игровую логику и пользовательский интерфейс, как я делал во многих играх-головоломках:

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

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

Пользовательский интерфейс берет эту сетку и рисует ее путем преобразования логических размеров в размеры в пикселях (то есть умножает их на константу). Однако, поскольку в игре почти нет игровой логики, мой уровень игровой логики [1] не имеет ничего общего, кроме обнаружения столкновений. Вот как это работает:

  1. Игрок начинает перетаскивать фигуру
  2. Пользовательский интерфейс запрашивает игровую логику для области легального перемещения этой фигуры и позволяет игроку перетащить ее в эту область
  3. Игрок отпускает кусок
  4. Пользовательский интерфейс привязывает кусок к сетке (чтобы он находился в правильной логической позиции)
  5. Пользовательский интерфейс сообщает игровой логике новую логическую позицию (с помощью методов-мутаторов, которых я бы предпочел избежать)

Я не совсем доволен этим:

  • Я пишу юнит-тесты для своего игрового уровня логики, но не для пользовательского интерфейса, и оказалось, что весь хитрый код в пользовательском интерфейсе: предотвращение столкновения части с другими или границей и привязка ее к сетке.
  • Мне не нравится тот факт, что пользовательский интерфейс рассказывает игровой логике о новом состоянии, я бы предпочел, чтобы он вызывал movePieceLeft()метод или что-то в этом роде, как в других моих играх, но я не продвинулся далеко с этим подходом, потому что игровая логика ничего не знает о перетаскивании и привязке, которые возможны в пользовательском интерфейсе.

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

  1. Является ли такой физический слой обычным, или это более типично, чтобы игровой логический слой делал это?
  2. Будет ли привязка к сетке и коду перетаскивания принадлежать пользовательскому интерфейсу или физическому слою?
  3. Будет ли такой физический слой работать с размерами пикселей или с какой-то логической единицей, например, с моим игровым логическим слоем?
  4. Однажды я видел обнаружение столкновений на основе событий в базе кода игры, то есть игрок просто перетаскивал фигуру, пользовательский интерфейс послушно отображал бы ее и уведомлял физическую систему, а физическая система вызывала метод onCollision (). на части, как только столкновение обнаружено. Что чаще встречается? Этот подход или просить области легального движения в первую очередь?

[1] слой , вероятно, не подходит для того, что я имею в виду, но подсистема звучит раздутой, а класс вводит в заблуждение, потому что каждый слой может состоять из нескольких классов.


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

Ответы:

3

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

Насколько я понимаю, вы должны отделить код GUI от игровой логики и доменных объектов, то есть кусочков головоломки. Это действительно три отдельных слоя - и, layerна мой взгляд , это подходящий термин. Он часто используется для объяснения концепции разделения каждого уровня объектов системы на подсистемы, которые не зависят друг от друга.

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

Итак, вот мои мысли по теме - надеюсь, что это поможет:

  1. Слой GUI: этот слой должен содержать методы только для отображения фигур на игровом поле, чтобы обеспечить взаимодействие между самой игрой и игроком;
  2. Слой Game Controller: отвечает за входные данные игрока. Это слой, который должен указывать фигуре двигаться в разных направлениях и спрашивать игровое поле, будут ли столкновения при движении и т. Д .;
  3. Бизнес-уровень. Этот слой должен содержать все ваши бизнес-классы, то есть фрагменты вашей игры и объект игрового поля, содержащий фрагменты головоломки.

В этой архитектуре слой GUI показывает игроку состояние игры, расположение каждой части головоломки. Уровень GUI будет тогда отвечать за получение входных данных игрока и передавать его на нижележащий уровень Game Controller, который затем будет отвечать за обнаружение столкновений. Если их нет, то часть может быть приказана двигаться в этом направлении ввода. Чтобы сделать это, вам просто нужно вызвать этот кусок MoveLeft,MoveRightи т. д. способы заставить часть двигаться. С тем же успехом вы можете сообщить игровому столу, какую фигуру вы хотите переместить, и затем она самостоятельно упорядочивает движение фигуры, а затем фигура движется в требуемом направлении. Эта архитектура облегчает тестирование каждого фрагмента кода на разных уровнях, а затем позволяет выполнять модульное тестирование, интеграционное тестирование и функциональное тестирование.

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

Спасибо за прочтение! знак равно

Уилл Маркуиллер
источник
2
Что звучит очень похоже на Model View Controller.
Tenpn
Если честно, любое описание абстрагирования интерфейса от базовой реализации будет звучать как Model View Controller. Но это потому, что используемые терминология и методы одинаковы (абстрагирование от деталей реализации и отделение пользовательского интерфейса от реализации). Но это предполагает очень простую среду. Здесь есть несколько слоев, и в каждом слое есть контроллеры. Здесь недостаточно отделить представление от модели, необходимо также отделить элемент управления взаимодействием с пользователем и элемент управления игрой.
MrCranky
Интересно, что здесь сложного, так как мы перемещаем кусочки головоломки на игровую доску с разделителями? Элементы управления получены из графического интерфейса, что является хорошим способом, и передаются на уровень абстракции, то есть игровой контроллер. Игровой контроллер проверяет наличие столкновений при движении, а затем сообщает фигуре о необходимости перемещения, если столкновения не обнаружено. Затем кусок головоломки перемещается должным образом в требуемом направлении и открывает свою новую позицию с помощью Positionфункции получения свойства, поэтому игровому контроллеру теперь требуется графический интерфейс для отображения этой перемещенной части в этой новой позиции.
Уилл Маркуиллер
Хех, я писал о "MVC" в разработке игр несколько месяцев назад. Да, это хорошая концепция для тех, кто не связан
Джоэль Мартинес,
1
Извините за поздний приём, я, к сожалению, на какое-то время отвлекся от проекта. Мне очень нравится подход контроллера, я приму это!