Используйте это для относительного расположения
android:layout_centerInParent="true"
и для другого расположения
android:gravity="center"
Это классическая проблема «поведенческой композиции». Компромисс заключается в том, что чем более независимыми являются поведения, тем сложнее им взаимодействовать друг с другом.
С точки зрения программирования игр, самым простым решением является выбор набора «основных» или Engine "данные и поместите их в главный объект, а затем сделайте так, чтобы поведения могли получать доступ к этим данным и изменять их - потенциально через функциональный интерфейс.
Если вам нужны данные, специфичные для поведения, это нормально, но чтобы избежать конфликтов имена переменных, вы можете сделать так, чтобы интерфейс для доступа к ним включал имя поведения. Например:
obj.getBehaviorValue("movement", "speed")
obj.setBehaviorValue("movement", "speed", 4)
Таким образом, два поведения могут определять свои собственные переменные, называемые скоростью, и не сталкиваться. Этот тип геттеров и сеттеров перекрестного поведения позволяет осуществлять обмен данными, когда это необходимо.
Вы можете позаимствовать шаблон из 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);
Изменить: ответ ниже имеет смысл только в том случае, если вы не создаете экземпляр нового MovingBehavior для каждого моба, а просто имеете одноэлементное MovingBehavior.
Я бы сказал, что моб тьфу, я ненавижу это слово для обозначения игровых NPC, но это не ваша вина) должен при вызове addBehavior ()
получить объект BehaviorState
, который возвращается из addBehavior (), и что он держится и привязан к добавленному поведению. Затем предоставьте интерфейс для MovingBehavior
, чтобы легко получить его объект BehaviorState
из movingMob
, и он хранит все, что ему нужно, чтобы сохранить там.
Если это связано с поведением и имеет смысл только в контексте этого поведения, то оно должно быть сохранено как его часть.
Скорость движения имеет смысл только для чего-то что может двигаться. Это означает, что он должен храниться как часть объекта, который представляет его способность двигаться, что, по-видимому, является вашим 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)
Какой самый простой способ сохранить данные о скорости передвижения?
Если он нужен только в классе 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; }
}
И когда это сработает,
Если бы я разрабатывал что-то подобное, я бы попробовал использовать интерфейсы для определения поведения моба:
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);
}
ИМХО, скорость передвижения связана с движущимся поведением, а не с самим мобом, и, как вы сказали, он не обязательно движется. Таким образом, переменная должна быть связана с поведением, изменение motionRate - это изменение его поведения, а не самого моба.
Вы также можете создать базовый класс Mob и получить класс MovingMob. Но я полагаю, что на самом деле это не применимо, раз уж очевидно, что у вас может быть произвольная комбинация различных поведений ...
- РЕДАКТИРОВАТЬ -
Во-первых, очевидно, у вас не будет одного и того же типа поведения дважды в одном и том же мобе (например, ни один моб не имеет двух движений одного и того же типа), поэтому в этом случае лучшим вариантом будет набор, поскольку он позволяет избежать дублирования
У вас может быть метод в каждом мобе, например
public Behavior GetBehavior(Type type)
{
foreach (var behavior in behaviorHashSet)
{
if ( behavior.GetType() == type)
return behavior;
}
return null;
}
. Затем вы можете делать все, что хотите, с этим поведением, когда у вас есть моб. Кроме того, вы можете изменить методы GetHashCode () и Equals (), чтобы гарантировать отсутствие дубликатов, или сделать метод GetBehavior еще быстрее (постоянное время)
Если ваша цель - избежать ошибок при доступе к объектам DependencyObject
, я предлагаю вместо явной игры с потоками и Dispatcher
просто сделать убедитесь, что ваши тесты выполняются в (одном) потоке STAThread
.
Это может или не может соответствовать вашим потребностям, по крайней мере, для меня этого всегда было достаточно для тестирования чего-либо, связанного с DependencyObject / WPF.
Если вы хотите попробовать это, я могу указать вам несколько способов сделать это:
[RequiresSTA]
, который может быть выбран для тестирования методы или классы. Однако будьте осторожны, если вы используете интегрированное средство выполнения тестов, поскольку, например, средство выполнения R # 4.5 NUnit, похоже, основано на более старой версии NUnit и не может использовать этот атрибут.