Есть хитрая настольная игра, хочется сделать её компьютерную реализацию, и хочется сделать её по принцыпам, схожим с MVC - есть модель, описывающая правила и ход игры, есть контроллер, передающий дествия игрока, и есть вид - собственно отображение происходящего в игре. Нужно это чтобы легко можно было менять контроллеры (локальный игрок/удалённый игрок/AI) и виды (GUI/Curses/Web UI, заодно контролировать из модели кому какие данные разрешено видеть). На деле получилось как-то не особо по канонам MVC, в связи с чем следующие непонятки:
1) Взаимодействие модели и контроллера. У игры куча фаз хода игрока, которые могут прерываться другими игроками, и ОЧЕНЬ хочется реализовать это в виде императивного кода, дёргая контроллер когда нужно действие игрока. Т.е.
void Game::Turn() {
DoFoo();
m_Controller->AskForAction(SELECT_UNIT);
DoBar();
m_Controller->AskForAction(CAST_SPELL);
DoBaz();
m_Controller->AskForAction(BUY_STUFF);
...
}
допустим, это будет работать с Curses, где в контроллере можно просто ждать нажатия клавиши. Но как быть, например, с GUI, где есть внешний цикл обработки событий? Придётся либо запустить копию цикла в контроллере, что, как мне кажется, криво и скорее всего возможно не во всех тулкитах, либо GUI банально не будет отрисовываться, пока пользователь не нажмёт нужную кнопку. Можно сделать отдельный поток, но это выглядит как костыль. Единственная альтернатива что мне видится - выходить из Turn когда нужно действие и его перезапуск когда действие получено (что-то типа FSM):
RequiredPlayerAction Game::Turn() {
switch (m_TurnPhase) {
case 0:
DoFoo();
m_Phase = 1;
return SELECT_UNIT;
case 1:
DoBar();
m_Phase = 2;
return CAST_SPELL;
case 2:
DoBaz();
m_Phase = 3;
return BUY_STUFF;
...
}
}
Но так код катастрофически раздувается, теряет наглядность, очень легко ошибиться, и становится невозможно использовать вложенные функции, что, в свою очередь, ещё больше уродует код.
Как бы вы решили задачу, может я упустил какой-нибудь вариант?
2) Взаимодействие модели и вида: push или pull? Вроде в классическом MVC вид просит у модели данные и отображает их. Мне же более удобным видится вариант когда модель при изменении данных пинает вид. Второй вариант выгдятит гораздо лучше потому что взаимодействие происходит через жёстко определённый интерфейс вида, что обеспечивает хорошую абстракцию, тогда как в первом случае придётся либо давать виду const-доступ к кишкам модели, либо гененировать структуру данных, представляющую состояние игры (что по сути просто копия тех же кишок), а структура этих кишок может меняться в процессе разработки модели.
Ну тут вроде всё понятно, но на всяких случай спрошу - push модель это в целом нормально?