Архитектура для Игры - Чтобы связаться или не связаться?

Используйте это для относительного расположения

android:layout_centerInParent="true"

и для другого расположения

android:gravity="center" 
10
задан bugfixr 25 June 2009 в 16:50
поделиться

8 ответов

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

С точки зрения программирования игр, самым простым решением является выбор набора «основных» или Engine "данные и поместите их в главный объект, а затем сделайте так, чтобы поведения могли получать доступ к этим данным и изменять их - потенциально через функциональный интерфейс.

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

obj.getBehaviorValue("movement", "speed")

obj.setBehaviorValue("movement", "speed", 4)

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

4
ответ дан 4 December 2019 в 01:31
поделиться

Вы можете позаимствовать шаблон из WPF (прикрепленные свойства). Ребятам из WPF нужен был способ привязки свойств к элементам управления во время выполнения. (например, если вы поместите элемент управления в сетку, было бы неплохо, если бы элемент управления имел свойство Row - они псевдо сделали это с прикрепленными свойствами.

Это работает примерно так: (обратите внимание, что это, вероятно, не точно соответствует реализации WPF, и я не учитываю регистрацию свойств зависимостей, поскольку вы не используете XAML)


public class MoveBehavior: Behavior
{
  private static Dictionary<Mob, int> MovementRateProperty;

  public static void SetMovementRate(Mob theMob, int theRate)
  {
     MovementRateProperty[theMob] = theRate;
  }

  public static int GetMovementRate(Mob theMob)
  {
      // note, you will need handling for cases where it doesn't exist, etc
      return MovementRateProperty[theMob];
  }
}

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


// retrieve the rate for a given mob
int rate = MoveBehavior.GetMovementRate(theMob);
// set the rate for a given mob
MoveBehavior.SetMovementRate(mob, 5);
2
ответ дан 4 December 2019 в 01:31
поделиться

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

Я бы сказал, что моб тьфу, я ненавижу это слово для обозначения игровых NPC, но это не ваша вина) должен при вызове addBehavior () получить объект BehaviorState , который возвращается из addBehavior (), и что он держится и привязан к добавленному поведению. Затем предоставьте интерфейс для MovingBehavior , чтобы легко получить его объект BehaviorState из movingMob , и он хранит все, что ему нужно, чтобы сохранить там.

0
ответ дан 4 December 2019 в 01:31
поделиться

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

Скорость движения имеет смысл только для чего-то что может двигаться. Это означает, что он должен храниться как часть объекта, который представляет его способность двигаться, что, по-видимому, является вашим MoveBehavior.

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

I можно придумать несколько способов реализовать это. Очевидным является простая функция-член класса Mob, которая позволяет вам выбирать индивидуальное поведение, примерно так:

class Mob {
  private List<Behavior> behaviors;
  public T Get<T>(); // try to find the requested behavior type, and return it if it exists
}

Другие могут сделать что-то вроде этого:

Mob m;
MovementBehavior b = m.Get<MovementBehavior();
if (b != null) {
  b.SetMovementRate(1.20f);
}

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

static class MovementHelper {
  public static SetMovementRate(Mob m, float movementrate){
    MovementBehavior b = m.Get<MovementBehavior();
    if (b != null) {
      b.SetMovementRate(1.20f);
    }
  }
}

а затем другие можно было бы использовать его так:

MovementHelper.SetMovementRate(m, 1.20f);

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

static class MovementHelper {
  public static SetMovementRate(Mob m, float movementrate){
    MovementBehavior b = m.Get<MovementBehavior();
    if (b != null) {
      b.SetMovementRate(1.20f);
    }
  }
}

, а затем другие могут использовать его так:

MovementHelper.SetMovementRate(m, 1.20f);

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

static class MovementHelper {
  public static SetMovementRate(Mob m, float movementrate){
    MovementBehavior b = m.Get<MovementBehavior();
    if (b != null) {
      b.SetMovementRate(1.20f);
    }
  }
}

, а затем другие могут использовать его так:

MovementHelper.SetMovementRate(m, 1.20f);

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

2
ответ дан 4 December 2019 в 01:31
поделиться

Так что вы пытаетесь сделать?

Какой самый простой способ сохранить данные о скорости передвижения?

Если он нужен только в классе MoveBehavior, тогда он должен быть там:

public class MoveBehavior {
    public int MovementRate { get; set; }
}

Если он нужен по своей сути классу Mob, тогда его будет легче раскрыть через класс Mob:

public class Mob {
    public int MovementRate { get; set; }
}

public class MoveBehavior {
    public MoveBehavior(Mob mob) { MobInEffect = mob; }

    public Mob MobInEffect {get; set;}

    // can access MovementRate through MovInEffect.MovementRate
}

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


Более прагматичное решение…

Я имею в виду, что вы реализуете все, что хотите, от перемещения в классе Mob первый:

public class Mob {

    // Constructors and stuff here

    public void Move(long ticks) 
    {
        // do some voodoo magic with movement and MovementRate here
    }

    protected int MovementRate { get; set; }
}

И когда это сработает,

0
ответ дан 4 December 2019 в 01:31
поделиться

Если бы я разрабатывал что-то подобное, я бы попробовал использовать интерфейсы для определения поведения моба:

public interface IMovable
{
    int MovementRate { get; set; }
    void MoveTo(int x, int y);
}

public class Monster : Mob, IMovable
{
    public int MovementRate { get; set; }

    public void MoveTo(int x, int y)
    {
         // ...
    }
}

Таким образом, вы можете проверить, может ли моб передвигаться, выполнив что-то вроде этого:

Monster m = new Monster();
if (m is IMovable)
{
    m.MoveTo(someX, someY);
}
0
ответ дан 4 December 2019 в 01:31
поделиться

ИМХО, скорость передвижения связана с движущимся поведением, а не с самим мобом, и, как вы сказали, он не обязательно движется. Таким образом, переменная должна быть связана с поведением, изменение motionRate - это изменение его поведения, а не самого моба.

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

- РЕДАКТИРОВАТЬ -

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

У вас может быть метод в каждом мобе, например

    public Behavior GetBehavior(Type type)
    {
        foreach (var behavior in behaviorHashSet)
        {
            if ( behavior.GetType() == type)
                return behavior;

        }
        return null;
    }

. Затем вы можете делать все, что хотите, с этим поведением, когда у вас есть моб. Кроме того, вы можете изменить методы GetHashCode () и Equals (), чтобы гарантировать отсутствие дубликатов, или сделать метод GetBehavior еще быстрее (постоянное время)

0
ответ дан 4 December 2019 в 01:31
поделиться

Если ваша цель - избежать ошибок при доступе к объектам DependencyObject , я предлагаю вместо явной игры с потоками и Dispatcher просто сделать убедитесь, что ваши тесты выполняются в (одном) потоке STAThread .

Это может или не может соответствовать вашим потребностям, по крайней мере, для меня этого всегда было достаточно для тестирования чего-либо, связанного с DependencyObject / WPF.

Если вы хотите попробовать это, я могу указать вам несколько способов сделать это:

  • Если вы используете NUnit> = 2.5.0, существует атрибут [RequiresSTA] , который может быть выбран для тестирования методы или классы. Однако будьте осторожны, если вы используете интегрированное средство выполнения тестов, поскольку, например, средство выполнения R # 4.5 NUnit, похоже, основано на более старой версии NUnit и не может использовать этот атрибут.
  • В более старых версиях NUnit,
2
ответ дан 4 December 2019 в 01:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: