Подтвердить что ты не робот

Внедрение Model-View-Controller правильным способом

Работа над игрой в Objective-C/Cocoa для OS X, и я закончил прототип так же, как и его завершение. Это беспорядок кода, являющийся моей первой игрой, но все работает. Я читал лучший способ собрать вещи, и MVC, кажется, имеет наибольший смысл, но я немного смущен.

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

Как мне настроить игровой мир? В настоящее время я использую два массива: один для мира (Стены, Полы, Двери, Вода, Лава и т.д.), И один для предметов (я буду добавлять третий для символов). Загружается карта (.plist), а затем объекты создаются и добавляются в массив, к которому она принадлежит. Куда идут массивы? В прототипе они также являются частью представления, поэтому, я думаю, вы могли бы сказать, что я объединил их (View и Controller) вместе. Будет ли создан объект Map для каждой карты? Будет ли объект Maps, содержащий все карты?

Как все это работает вместе? Игрок нажимает клавишу, которая перемещает персонажа в игре. Представление будет обрабатывать вход, правильно? Вы отправите это контроллеру, который будет проверять все (стены, монстры и т.д.) На карте/других массивах, а затем возвращать результат? Или вы отправите его игроку, который отправится на контроллер, который выполнит все проверки, а затем вернет результат?

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

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

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

4b9b3361

Ответ 1

Вам может быть интересна презентация, которую я дал ACCU '09 - " Принятие модели-View-Controller в Cocoa и Objective-C".

С чего это начинается? С контроллер? Это, похоже, делает для меня это самый здравый смысл, но как это начало?

Создайте новый проект приложения Cocoa, и вы увидите, что уже есть класс контроллера, предоставляемый шаблоном - это класс делегата приложения. Теперь посмотрите MainMenu.xib. Там экземпляр делегата приложения, и он подключен к объекту владельца файла delegate. В этом случае NSApplication является файловым владельцем; это то, что захотелось MainMenu быть распакованным. Так что это действительно делегат приложения.

Это означает, что у нас есть что-то, что является объектом контроллера, может разговаривать с экземпляром NSApplication и может иметь выходы для всех других объектов в XIB. Это отличное место для настройки начального состояния приложения - то есть для "точки входа" для вашего приложения. Фактически точкой входа должен быть метод -applicationDidFinishLaunching:. Это вызвало, как только приложение завершило все, что необходимо для того, чтобы ваше приложение стало стабильным, работающим состоянием - другими словами, Cocoa рад, что он сделал то, что ему нужно, и все остальное зависит от вас.

-applicationDidFinishLaunching: - это место, где вы хотите создать или восстановить исходную модель, которая является представлением состояния приложения (вы также можете думать о ней как о представлении пользовательского документа, если эта аналогия подходит для вашего приложения - приложения на основе документов немного сложнее, чем стандартные) и сообщают View, как представлять вещи пользователю. Во многих приложениях вам не нужно загружать всю модель при запуске приложения; для начала он может быть медленным и использовать больше памяти, чем вам нужно, а во-вторых, первый вид, вероятно, не отображает каждый бит о модели. Поэтому вы просто загружаете нужные вам биты, чтобы показать пользователю, что; вы контролируете взаимодействие между представлением и моделью.

Если вам нужно отобразить другую информацию в другом представлении - например, если ваш основной вид является основным видом, и вам нужно показать подробный редактор, - тогда, когда пользователь скажет вам, что они хотят сделать, вам нужно установить, что вверх. Они расскажут вам, выполнив какое-то действие, с которым вы могли бы справиться в делетете приложения. Затем вы создаете новый контроллер для поддержки нового представления и рассказываете, где получить требуемую информацию о модели. Вы можете удерживать другие объекты View в отдельном XIB, поэтому они загружаются только тогда, когда они необходимы.

Как мне настроить игровой мир? я в настоящее время используются два массива, один для мир (Стены, Полы, Двери, Вода, Лава и т.д.), И один для предметов (Я добавлю третий для персонажи). Карта (a.plist) является и затем объекты создано и добавлено в массив принадлежит. Куда идут массивы? В прототип, они также являются частью взгляд, поэтому, я думаю, вы могли бы сказать, что я объединили два (View и Controller) вместе. Будет ли объект карты создано для каждой карты? Будет ли Объект Карты, содержащий все карты?

Мы можем определить, какие объекты мы моделируем, анализируя ваше утверждение выше - вы не можете этого понять, но вы набросали спецификацию:-). Там есть мир, который содержит стены, двери и т.д., Поэтому мы знаем, что нам нужны объекты для них и что они должны принадлежать объекту World. Но у нас также есть предметы и персонажи - как они взаимодействуют с миром? Может ли место содержать воду и характер? Если это так, возможно, мир состоит из локаций, и каждое местоположение может иметь стену или дверь или что-то еще, а также может содержать предметы и символы. Обратите внимание: если я пишу его так, кажется, что элемент принадлежит местоположению, а не местоположению элемента. Я бы сказал, что "у кота есть кошка", а не "у кота есть под ним".

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

Теперь некоторые из ваших существительных станут объектами в программном обеспечении, некоторые станут атрибутами других объектов. Глаголы будут действиями (т.е. Методами). Но в любом случае, будет легче подумать, если вы сначала подумаете над тем, что вы пытаетесь моделировать, а не прыгаете прямо к программному обеспечению.

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

Мне нравится следовать политике "рассказать, не спрашивать", в которой говорится, что вы приказываете объекту что-то делать, а не просите его предоставить вам информацию для принятия решения. Таким образом, если поведение изменяется, вам нужно только изменить объект, который будет указан. Что это означает для вашего примера, так это то, что View обрабатывает событие нажатия клавиши (это происходит потому, что обрабатывается с помощью NSControl), и он сообщает контроллеру, что это событие произошло. Пусть говорят, что "Вид" получает "левую стрелку", а контроллер решает, что игрок должен двигаться влево. Я бы просто сказал игроку "двигаться влево" и позволить игроку разобраться, что происходит, когда движение влево означает натыкаться на стену или монстра.

Чтобы объяснить, почему я хочу сделать это так, представьте, что вы добавляете в игру 1.1 возможность плавать игроком. Теперь у игрока есть свойство ableToSwim, поэтому вам нужно изменить плеер. Если вы говорите игроку двигаться влево, то вы обновляете игрока, чтобы знать, что перемещается по воде, в зависимости от того, могут ли они плавать. Если вместо этого Контролер попросит игрока о перемещении налево и примет решение, то Контролер должен знать, чтобы спросить о возможности плавать, и ему нужно знать, что это означает возле воды. Как и любой другой объект контроллера в игре, который может взаимодействовать с игроком, как и контроллер в игре для iPhone; -).

Ответ 2

Кажется, что ваше основное замешательство заключается в том, как вещи создаются во время запуска приложения. Многие люди застряли на этом, потому что кажется, что происходит что-то волшебство, но позвольте мне посмотреть, могу ли я сломать его.

  • Приложение запускается пользователем
  • Функция C main() называется
  • main() вызывает NSApplicationMain()
  • NSApplicationMain() загружает MainMenu.nib(или другой nib, указанный в файле info.plist)
  • Загрузка Nib инициализирует все объекты, определенные в nib (включая делегат приложения)
  • Загрузка Nib делает все соединения, определенные в nib
  • Загрузка Nib вызывает awakeFromNib для всех объектов, которые он только что создал.
  • -applicationWillFinishLaunching: вызывается в делетете приложения.
  • NSApplication (или подкласс, указанный в Info.plist) инициализируется
  • -applicationDidFinishLaunching: вызывается в делетете приложения.

Обратите внимание, что делегат приложения инициализируется перед классом NSApplication (sub). Вот почему приложение (Will | Did) FinishLaunching: принимает уведомление, в отличие от NSApplication, это делегат.

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

Ответ 3

Вы должны создать модель для всей игры. Он должен содержать все, что касается игры, кроме взаимодействия с графическим интерфейсом. Представления, с другой стороны, содержат все материалы GUI, ничего не зная о потоке игры.

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

Затем контроллер заполняет промежуток. Он реагирует на ввод пользователя, просит классы моделей выполнить конкретный ход игры и просит взгляды показать новую ситуацию. Ожидается, что контроллер не будет использоваться повторно. Это клей, который держит игру вместе. Контроллер гарантирует, что классы моделей и классы классов остаются незаменимыми и многоразовыми.

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

Всегда помните третье правило проектирования системы X Window: "Единственное, что хуже, чем обобщение из одного примера, вообще не обобщает ни одного примера".

Ответ 4

В вашей игре модель будет включать в себя такие вещи, как текущая позиция персонажа, количество точек здоровья и другие значения, которые включают в себя "состояние" игры. Он уведомлял бы мнение всякий раз, когда что-то менялось, чтобы представление могло обновляться. Представление было бы просто кодом, необходимым для отображения всего пользователю. Контроллер отвечает за ответ на ввод пользователя и при необходимости обновляет модель.

Контроллер является центральным компонентом в этом, и это то, что должно создавать экземпляр модели и просматривать.

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

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

Ваша игра звучит так, как будто она достаточно сложна, чтобы гарантировать структуру архитектуры, такую ​​как MVC. Есть несколько случаев, когда часть программного обеспечения достаточно проста, чтобы MVC переборщил и излишне усложнил ситуацию, но порог использования MVC довольно низок.