Обновление (резюме)
Поскольку я написал довольно многословный ответ, вот что все сводится к следующему:
- Пространства имен хороши, используйте их всякий раз, когда это имеет смысл
- Использование
inGameIO
и playerIO
классы, скорее всего , представляют собой нарушение SRP. Это, вероятно, означает, что вы связываете способ обработки ввода-вывода с логикой приложения.
- Есть пара общих классов ввода-вывода, которые используются (или иногда совместно используются) классами обработчиков. Эти классы-обработчики затем переведут необработанный ввод в формат, понятный вашей логике приложения.
- То же самое касается вывода: это может быть сделано довольно общими классами, но передают игровое состояние через объект обработчика / картографа, который переводит внутреннее игровое состояние в то, что могут обрабатывать универсальные классы ввода-вывода.
Я думаю, что вы смотрите на это неправильно. Вы отделяете IO в зависимости от компонентов приложения, тогда как для меня более разумно иметь отдельные классы IO, основанные на источнике и «типе» IO.
Имея несколько базовых / универсальных KeyboardIO
классов MouseIO
для начала, а затем основываясь на том, когда и где они вам нужны, есть подклассы, которые по-разному обрабатывают указанный IO.
Например, ввод текста - это то, что вы, вероятно, хотите обрабатывать иначе, чем внутриигровые элементы управления. Вы обнаружите, что хотите отображать определенные ключи по-разному в зависимости от каждого варианта использования, но это сопоставление не является частью самого IO, это то, как вы обрабатываете IO.
Придерживаясь SRP, у меня будет пара классов, которые я могу использовать для ввода-вывода клавиатуры. В зависимости от ситуации, я, вероятно, захочу по-разному взаимодействовать с этими классами, но их единственная задача - рассказать мне, что делает пользователь.
Затем я вставил бы эти объекты в объект-обработчик, который либо отобразил бы необработанный ввод-вывод на что-то, с чем могла бы работать логика моего приложения (например: пользователь нажимает «w» , обработчик отображает это на MOVE_FORWARD
).
Эти обработчики, в свою очередь, используются, чтобы заставить персонажей двигаться, и соответственно рисовать экран. Грубое упрощение, но суть его в следующем:
[ IO.Keyboard.InGame ] // generic, if SoC and SRP are strongly adhered to, changing this component should be fairly easy to do
||
==> [ Controls.Keyboard.InGameMapper ]
[ Game.Engine ] <- Controls.Keyboard.InGameMapper
<- IO.Screen
<- ... all sorts of stuff here
InGameMapper.move() //returns MOVE_FORWARD or something
||
==> 1. Game.updateStuff();//do all the things you need to do to move the character in the given direction
2. Game.Screen.SetState(GameState); //translate the game state (inverse handler)
3. IO.Screen.draw();//generate actual output
Теперь у нас есть класс, который отвечает за ввод-вывод клавиатуры в необработанном виде. Другой класс, который переводит эти данные во что-то, что игровой движок действительно может иметь смысл, эти данные затем используются для обновления состояния всех задействованных компонентов, и, наконец, отдельный класс позаботится о выводе на экран.
У каждого отдельного класса есть одно задание: обработка ввода с клавиатуры выполняется классом, который не знает / не заботится / должен знать, что означает ввод, который он обрабатывает. Все, что он делает, это знает, как получить входные данные (буферизованные, небуферизованные, ...).
Обработчик переводит это во внутреннее представление для остальной части приложения, чтобы понять эту информацию.
Движок игры берет переведенные данные и использует их для уведомления всех соответствующих компонентов о том, что происходит. Каждый из этих компонентов делает только одну вещь, будь то проверка столкновений или изменение анимации персонажа, это не имеет значения, это зависит от каждого отдельного объекта.
Эти объекты затем возвращают свое состояние обратно, и эти данные передаются Game.Screen
, что по сути является обратным обработчиком ввода-вывода. Он отображает внутреннее представление на то, что IO.Screen
компонент может использовать для генерации фактического вывода.