Как вы можете организовать код для игры, чтобы соответствовать шаблону MVC? - PullRequest
71 голосов
/ 17 февраля 2009

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

У меня есть класс Java, поэтому я отказался от исследований и разработок на C ++ и перешел на Java и JOGL (Java OpenGL). Это замечательно! Но это не относится к делу.

Я хочу сделать небольшую ролевую игру, но этот вопрос действительно применим к любой игре. Как вы организуете игровые объекты в структурированном виде, как шаблон Model-View-Controller? Это удивительный шаблон, очень широко используемый и имеющий много смысла, но мне сложно понять, как его реализовать.

Например, мне нужно отслеживать объект GL для рисования на экране. У меня должны быть классы, которые реализуют MouseListener, MouseMotionListener, MouseWheelListener и KeyListener (или один класс, менеджер ввода «все в одном»). И я должен поместить свои игровые данные где-нибудь, где все эти различные классы могут получить доступ и изменить их; если кто-то нажимает кнопку на клавиатуре, класс управления вводом должен каким-то образом выполнить действие, которому назначена клавиша; когда необходимо нарисовать кадр, класс графики должен найти способ перебрать все «вещи» и нарисовать их все.

И моя самая большая проблема, GUI; где все это связано? Это что-то вроде ввода, но не совсем, и ему нужно и установить, и получить фрагменты данных из реальной игровой симуляции ... И усложнить это даже БОЛЬШЕ, если я решу попробовать добавить сеть, которая (похожа на GUI) ) также необходимо иметь доступ к большому количеству данных для изменения и чтения ...

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

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

-Ricket

Редактировать: Нашел хорошую диаграмму, которая может помочь мне разобраться во всем этом ... Источник: (будьте осторожны, файл PS!) http://www.tucs.fi/publications/attachment.php?fname=TR553.ps.gz

http://img10.imageshack.us/img10/6278/mvcdiagramgamesbl5.png

Edit2: мне также нравится объяснение этого парня о том, как он планировал свою игру MVC: http://interactivesection.wordpress.com/2007/11/19/dum-de-dum-drum-my-first-mvc-game-development/

Edit3: еще одна замечательная статья! http://dewitters.koonsolo.com/gamemvc.html

Ответы [ 6 ]

55 голосов
/ 17 февраля 2009

Это может помочь вам представить модель как своего рода игровой API. К чему бы сводилась ваша игра, если бы для игры, назначенной с самого начала, вообще не было пользовательского интерфейса? Вы упоминаете, что вы имеете в виду РПГ, поэтому в этом случае вы можете представить, что персонаж модели, его / ее инвентарь, заклинания, способности, неигровые персонажи и даже такие вещи, как карта и правила боя, являются частью модели. , Это подобно правилам и частям Монополии без специфики того, как финальная игра отображает это или как пользователь будет взаимодействовать с ней. Это похоже на Quake как абстрактный набор трехмерных объектов, движущихся по уровню с вычисленными вещами, такими как пересечение и столкновение, но без рендеринга, теней или звуковых эффектов.

Помещая все это в модель, сама игра теперь не зависит от пользовательского интерфейса. Он может быть подключен к текстовому интерфейсу ASCII, как в играх Rogue, или к интерфейсу командной строки, похожему на Zork, или к веб-интерфейсу или к 3D-интерфейсу. Некоторые из этих интерфейсов могут быть ужасно приспособлены в зависимости от игровой механики, но все они будут возможны.

Уровень просмотра является зависимым от интерфейса уровнем. Он отражает конкретный выбор пользовательского интерфейса, с которым вы работали, и будет в значительной степени посвящен этой технологии. Он может быть ответственным за чтение состояния модели и отображение его в 3D, ASCII или изображениях и HTML для веб-страницы. Он также отвечает за отображение любых механизмов управления, которые игрок должен использовать для взаимодействия с игрой.

Слой контроллера - это клей между ними. Он никогда не должен содержать никакой реальной игровой логики, и при этом он не должен отвечать за управление слоем View. Вместо этого он должен преобразовывать действия, предпринимаемые в слое «Просмотр» (нажатие кнопок, нажатие на области экрана, действия джойстика и т. Д.), В действия, выполняемые с моделью. Например, сброс предмета, нападение на NPC, что угодно. Он также отвечает за сбор данных и выполнение любого преобразования или обработки, чтобы слой View мог легче их отображать.

Теперь, как я описал это выше, как будто есть очень четкая последовательность событий, управляющая игрой, которая, вероятно, действительно подходит только для веб-игры. Это потому, что на это я потратил свое время в последнее время. В игре, которая не управляется запросом пользователя и ответом сервера, таким как сеть (например, игра, запущенная на компьютере пользователя), вы, вероятно, захотите убедиться, что на уровне модели хорошо реализован шаблон Observer. Например, если действия выполняются в модели из-за того, что время идет, вы можете не захотеть, чтобы слой «Вид» постоянно опрашивал модель на предмет обновлений. Вместо этого, используя шаблон Observer, Модель может уведомлять любых наблюдателей об изменениях объектов Модели по мере их возникновения. Это, в свою очередь, может быть использовано для немедленного обновления представления, чтобы отразить изменение.

Тогда, если 60 секунд прохождения привели к некоторому ремонту базы игрока, база может произвести ремонт и немедленно уведомить всех прикрепленных к ней наблюдателей, что база обновлена. Вид может быть присоединен в качестве наблюдателя, и имейте в виду, что ему необходимо повторно отобразить базу, поскольку ее состояние изменилось. В самом уведомлении могло содержаться достаточно информации для обновления представления, или ему может потребоваться развернуться и обратиться к модели для обновления, но результат будет таким же.

19 голосов
/ 17 февраля 2009

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

Если это изменит внешний вид без изменения базовых данных, то оно в поле зрения. Если это данные, которые можно просматривать разными способами, то это модель. А если это то, как ты играешь, то это контроль.

Так что, если вы рисуете «топор» с двумя лезвиями или одним, это вид. Если это количество очков жизни, которые вы наносите топором, то это модель. И если вы качаете топор, набирая «s» или щелкая правой кнопкой мыши, это контроль.

8 голосов
/ 17 февраля 2009

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

То, что я предлагаю, это прочитать «Шаблоны проектирования» бандой из четырех человек. Есть много полезных шаблонов, кроме MVC. Иногда не имеет никакого смысла использовать MVC вообще. Специально для игр я не уверен, является ли MVC такой хорошей идеей. Причина в том, что вы не хотите отображать игровой объект многими различными способами (представлениями), но вы хотите повторно использовать чертежный код для множества различных типов игровых объектов.

Для моего собственного 2D игрового движка я довольно активно использовал шаблон стратегии . Объекты игры, такие как игрок и монстры, которых я назвал Спрайт . Я позволил рисовать спрайт с помощью стратегии . Именно тогда я позвонил sprite.draw () Я бы сделал что-то вроде этого:

class Sprite {
  void draw() {
    this.view.draw(this.currentPosition, this.currentOrientation);
  }

  Point  currentPosition;    // Current position of this sprite
  double currentOrientation; // Facing angle of sprite
};

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

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

class Sprite {
  void setUpdateAction(Action action) {
    this.updateAction = action;
  }

  void update(double start_time, double delta_time)
  {
    this.prevPosition = position();  
    advance(delta_time); // Advance to next position based on current speed and orientation

    this.updateAction.execute(this, start_time, delta_time);
  }

  Action updateAction;
};

Существует множество вариантов этого. В моей текущей реализации я даже выделил currentPosition , speed , direction и advance () в отдельный объект с именем MotionState . Это позволяет мне строить деревья поиска возможных позиций и ориентаций при выполнении алгоритмов поиска пути. Тогда я не хочу нести с собой информацию о том, как вести себя при каждом обновлении или как рисовать спрайт.

2 голосов
/ 17 февраля 2009

Концепция MVC централизации логики взаимодействия с пользователем - хорошая модель для разработки игр.

Я немного поработал над разработкой Flash-игр. Здесь - статья о пулах объектов во Flash. Концепция является кроссплатформенной и может дать вам некоторые идеи.

Вы правы, что беспокоитесь обо всем, что происходит одновременно. В зависимости от вашего игрового дизайна, ваш игровой цикл может иметь много общего. Здесь вы узнаете все грязные приемы оптимизации, часто трудный путь:)

Есть много способов организовать ваш код, например, можно написать класс GameManager как Singleton. Все игровые объекты привязаны к нему для управления и взаимодействия с пользователем. GameManager обрабатывает весь пользовательский ввод и отправляет сообщения в свой пул объектов. Вы можете использовать интерфейсы для определения общих шаблонов связи между игровыми объектами и GameManager.

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

1 голос
/ 16 ноября 2015

Мое мышление о MVC такое, как MDUC
Модель
Дисплей
Контроллер пользовательского ввода

Модель содержит объекты модели предметной области
На экране отображается текущее состояние и поведение объектов модели домена на экране.
Контроллер пользовательского ввода обрабатывает все пользовательские вводы.

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

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

1 голос
/ 17 февраля 2009

Все ваши слушатели и обработчики должны входить в класс Controller, состояние объектов на экране (например, положение, цвет и т. Д.) Должно быть частью ваших классов Model, и любой код, который рисует объекты на экране, будет быть частью зрения.

...