Nano Hash - криптовалюты, майнинг, программирование

Архитектура игры

У меня есть вопрос об игре XNA, которую я делаю, но это также общий вопрос для будущих игр. Я делаю игру в понг, и я не знаю точно, что и где обновлять, поэтому я лучше объясню, что я имею в виду. У меня есть класс Game, Paddle и Ball и, например, я хочу проверить столкновения мяча с пределами экрана или ракетками, но я встречаю 2 подхода для этого:

Подход более высокого уровня. Сделать свойства ракетки и мяча общедоступными, а в Game.Update проверять наличие столкновений?

Подход нижнего уровня. Я предоставляю всю необходимую мне информацию (ограничения экрана и информацию о веслах) классу мяча (по параметру или в общедоступном статическом классе) и в Ball.Update, который я проверяю. столкновения?

Я предполагаю, что мой вопрос в более общем виде:

Должен ли объект знать, как обновлять и рисовать себя, даже имея зависимости от более высоких уровней, которые каким-то образом им предоставляются?

или

Что лучше обрабатывать на более высоких уровнях в Game.Update или Game.Draw или использовать Менеджеры для упрощения кода?

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

28.03.2011

  • Я думаю, что когда вы говорите о логике, вы на самом деле имеете в виду архитектуру. 28.03.2011
  • (Я продолжаю ссылаться на этот вопрос, поэтому я сам исправлю заголовок...) 15.08.2011
  • Это больше подходит для gamedev.stackexchange.com. 18.03.2013

Ответы:


1

Трудная часть ответа на ваш вопрос заключается в том, что вы спрашиваете одновременно: «что мне делать сейчас для Pong» и «что мне делать позже в какой-то общей игре».


Чтобы играть в Pong, вам даже не нужны классы Ball и Paddle, потому что это просто позиции. Просто вставьте что-то вроде этого в свой класс Game:

Vector2 ballPosition, ballVelocity;
float leftPaddlePosition, rightPaddlePosition;

Затем просто обновите и нарисуйте их в любом удобном для вас порядке в функциях Update и Draw вашей игры. Легкий!


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

Но оставьте концепцию дизайна прежней — вся обработка взаимодействия объекта с объектом (т. е. игровой процесс) происходит в вашем классе Game.

Все это прекрасно, если у вас есть два или три разных элемента геймплея (или класса).


Однако предположим более сложную игру. Давайте возьмем базовую игру в понг, добавим некоторые элементы пинбола, такие как мультибол и управляемые игроком ласты. Давайте добавим некоторые элементы из Змеи, скажем, у нас есть «змея», управляемая ИИ, а также некоторые объекты для захвата, в которые могут попасть либо шары, либо змея. И на всякий случай скажем, что весла также могут стрелять лазерами, как в Space Invaders, а лазерные стрелы делают разные вещи в зависимости от того, во что они попадают.

Боже мой, это огромный беспорядок взаимодействия! Как мы собираемся справиться с этим? Мы не можем поместить все это в игру!

Простой! Мы создаем интерфейс (или абстрактный класс, или виртуальный класс), из которого будет происходить каждая «вещь» (или «действующее лицо») в нашем игровом мире. Вот пример:

interface IActor
{
    void LoadContent(ContentManager content);
    void UnloadContent();

    void Think(float seconds);
    void UpdatePhysics(float seconds);

    void Draw(SpriteBatch spriteBatch);

    void Touched(IActor by);

    Vector2 Position { get; }
    Rectangle BoundingBox { get; }
}

(Это только пример. Не существует «одного истинного интерфейса актера», который будет работать для каждой игры, вам нужно будет создать свой собственный. Вот почему мне не нравится DrawableGameComponent.)

Наличие общего интерфейса позволяет Game просто говорить об Актерах — вместо того, чтобы знать о каждом отдельном типе в вашей игре. Осталось сделать общие для всех типов вещи — обнаружение коллизий, отрисовка, обновление, загрузка, выгрузка и т. д.

Освоив в актера, вы можете начать беспокоиться об определенных типах актеров. Например, это может быть метод в Paddle:

void Touched(IActor by)
{
    if(by is Ball)
         ((Ball)by).BounceOff(this.BoundingBox);
    if(by is Snake)
         ((Snake)by).Kill();
}

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

В конце вы сможете объединить всех своих актеров в большой список, который вы сможете просто просмотреть в игре.

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

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


Теперь вы можете пойти еще дальше и иметь несколько интерфейсов. Например: один для рендеринга, один для сценариев и ИИ, один для физики и т. д. Затем создайте несколько реализаций, которые можно объединить в объекты.

Это подробно описано в этой статье. И у меня есть простой пример в этом ответе. Это подходящий следующий шаг, если вы начинаете обнаруживать, что ваш интерфейс с одним субъектом начинает превращаться в «дерево» абстрактных классов.

28.03.2011
  • Удивительный ответ - Однако давайте постулируем более сложную игру. звучит классная игра... разрабатываем что-то подобное :) 10.09.2015

  • 2

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

    Ball и Paddle, оба являются объектами в игре и в данном случае визуализируемыми, подвижными объектами. Весло имеет следующие критерии

    Он может двигаться только вверх и вниз

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

    Мяч имеет следующие критерии

    Не может выйти за пределы экрана

    1. Это может быть отображено
    2. В зависимости от того, где он попал на весло, вы можете управлять им косвенно (некоторая простая физика).
    3. Если он уходит за весло, раунд заканчивается.
    4. Когда игра начинается, мяч обычно прикрепляется к ракетке проигравшего.

    Определив общие критерии, вы можете извлечь интерфейс

    public interface IRenderableGameObject
    {
       Vector3 Position { get; set; }
       Color Color { get; set; }
       float Speed { get; set; }
       float Angle { get; set; }
    }
    

    У вас также есть немного GamePhysics

    public interface IPhysics
    {
        bool HasHitBoundaries(Window window, Ball ball);
        bool HasHit(Paddle paddle, Ball ball);
        float CalculateNewAngle(Paddle paddleThatWasHit, Ball ball);
    }
    

    Тогда есть некоторая игровая логика

    public interface IGameLogic
    {
       bool HasLostRound(...);
       bool HasLostGame(...);
    }
    

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

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

    Знайте свой домен и записывайте свои идеи. Неспособность планировать — значит планировать неудачу

    28.03.2011

    3

    Вы можете рассматривать свой мяч и весло как компонент вашей игры, а XNA предоставляет вам базовый класс GameComponent, имеющий ссылку Update(GameTime gameTime), который вы можете переопределить, чтобы выполнить логику. Кроме того, существует также класс DrawableGameComponent, который поставляется с собственным методом Draw переопределить. Каждый класс GameComponent имеет также Game свойство, которое содержит игровой объект, создавший их. Там вы можете добавить некоторые Сервисы, которые ваш компонент может использовать для получения информации сам по себе.

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

    28.03.2011

    4

    Я согласен с тем, что сказал Андрей. Я просто изучаю XNA и на своих уроках, например, на вашем уроке с мячом. У меня был бы как минимум метод Update(gametime) и метод Draw(). Обычно также Initialize(), Load(). Затем из основного игрового класса я буду вызывать эти методы из их соответствующих кузенов. Это было до того, как я узнал о GameComponent. Вот хорошая статья о том, стоит ли вам это использовать. http://www.nuclex.org/blog/gamedev/100-to-gamecomponent-or-not-to-gamecomponent

    28.03.2011
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

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

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

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

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..