XNA дразнят Игровой объект или разъединение Вашей Игры

Вы должны убедиться, что идентификатор существует. Если Engagespot.identifyUser('daniel') не было выполнено, идентификатор не будет отображен, и API выдаст эту ошибку.

Решение состоит в том, чтобы убедиться, что Engagespot.identifyUser('daniel') выполняется правильно.

10
задан Andriy Drozdyuk 9 May 2009 в 17:43
поделиться

6 ответов

На этом форуме есть несколько хороших сообщений по теме модульного тестирования. Вот мой личный подход к модульному тестированию в XNA:

  • Игнорировать метод Draw ()
  • Изолируйте сложное поведение в собственных методах класса
  • Проверяйте сложные вещи, не переживайте остальное

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

[TestFixture]
public class EntityTest {
    [Test]
    public void testMovement() {
        float speed = 1.0f; // units per second
        float updateDuration = 1.0f; // seconds
        Vector2 moveVector = new Vector2(0f, 1f);
        Vector2 originalPosition = new Vector2(8f, 12f);

        Entity entity = new Entity("testGuy");
        entity.NextStep = moveVector;
        entity.Position = originalPosition;
        entity.Speed = speed;

        /*** Look ma, no Game! ***/
        entity.Update(updateDuration);

        Vector2 moveVectorDirection = moveVector;
        moveVectorDirection.Normalize();
        Vector2 expected = originalPosition +
            (speed * updateDuration * moveVectorDirection);

        float epsilon = 0.0001f; // using == on floats: bad idea
        Assert.Less(Math.Abs(expected.X - entity.Position.X), epsilon);
        Assert.Less(Math.Abs(expected.Y - entity.Position.Y), epsilon);
    }
}

Изменить: Некоторые другие примечания из комментариев:

Мой класс сущности : Я решил заключить все свои игровые объекты в централизованный класс Entity, который выглядит примерно так:

public class Entity {
    public Vector2 Position { get; set; }
    public Drawable Drawable { get; set; }

    public void Update(double seconds) {
        // Entity Update logic...
        if (Drawable != null) {
            Drawable.Update(seconds);
        }
    }

    public void LoadContent(/* I forget the args */) {
        // Entity LoadContent logic...
        if (Drawable != null) {
            Drawable.LoadContent(seconds);
        }
    }
}

Это дает мне большую гибкость для создания подклассов Entity (AIEntity, NonInteractiveEntity ...), которые, вероятно, переопределяют Update () , Это также позволяет мне создавать подклассы Drawable свободно, без чертовски n ^ 2 подклассов, таких как AnimatedSpriteAIEntity , ParticleEffectNonInteractiveEntity и AnimatedSpriteNoninteractiveEntity . Вместо этого я могу сделать следующее:

Entity torch = new NonInteractiveEntity();
torch.Drawable = new AnimatedSpriteDrawable("Animations\litTorch");
SomeGameScreen.AddEntity(torch);

// let's say you can load an enemy AI script like this
Entity enemy = new AIEntity("AIScritps\hostile");
enemy.Drawable = new AnimatedSpriteDrawable("Animations\ogre");
SomeGameScreen.AddEntity(enemy);

Мой класс Drawable : у меня есть абстрактный класс, от которого происходят все мои нарисованные объекты. Я выбрал абстрактный класс, потому что часть поведения будет совместно использоваться. Было бы вполне приемлемо вместо этого определить это как интерфейс , если это не так в вашем коде.

public abstract class Drawable {
    // my game is 2d, so I use a Point to draw...
    public Point Coordinates { get; set; }
    // But I usually store my game state in a Vector2,
    // so I need a convenient way to convert. If this
    // were an interface, I'd have to write this code everywhere
    public void SetPosition(Vector2 value) {
        Coordinates = new Point((int)value.X, (int)value.Y);
    }

    // This is overridden by subclasses like AnimatedSprite and ParticleEffect
    public abstract void Draw(SpriteBatch spriteBatch, Rectangle visibleArea);
}

Подклассы определяют свою собственную логику Draw. В примере с резервуаром вы могли бы сделать несколько вещей:

  • Добавить новую сущность для каждой пули
  • Создать класс TankEntity, который определяет список и переопределяет Draw () для перебора маркеров (которые определяют метод Draw самостоятельно)
  • Сделайте ListDrawable

Вот пример реализации ListDrawable, игнорируя вопрос о том, как управлять самим списком.

public class ListDrawable : Drawable {
    private List<Drawable> Children;
    // ...
    public override void Draw(SpriteBatch spriteBatch, Rectangle visibleArea) {
        if (Children == null) {
            return;
        }

        foreach (Drawable child in children) {
            child.Draw(spriteBatch, visibleArea);
        }
    }
}
14
ответ дан 3 December 2019 в 17:22
поделиться

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

public class MyGameObject : Game, IGame
{
    //you can leave this empty since you are inheriting from Game.    
}

public IGame
{
    public GameComponentCollection Components { get; set; }
    public ContentManager Content { get; set; }
    //etc...
}

Это немного утомительно, но позволяет вам достигнуть насмешливости.

2
ответ дан 3 December 2019 в 17:22
поделиться

каркасы типа MOQ и Rhino Mocks специально не нуждаются в интерфейсе. Они могут издеваться над любым незапечатанным и / или абстрактным классом. Игра является абстрактным классом, поэтому у вас не должно возникнуть никаких проблем с его насмешкой: -)

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

Кроме того, вы можете также проверить мой проект, который мог бы помочь в создании модульных тестов для игр XNA без необходимости делать насмешки: http://scurvytest.codeplex.com/

3
ответ дан 3 December 2019 в 17:22
поделиться

Не надо издеваться над этим. Почему бы не создать поддельный игровой объект?

Унаследуйте от Game и переопределите методы, которые вы намереваетесь использовать в своих тестах, для возврата стандартных значений или быстрых вычислений для любых методов / свойств, которые вам нужны. Затем передайте фальшивку своим тестам.

Перед тем, как создавать фреймворки, люди скручивали свои собственные макеты / заглушки / фальшивки - возможно, это не так быстро и просто, но вы все равно можете это сделать.

3
ответ дан 3 December 2019 в 17:22
поделиться

В качестве отправной точки для чего-то вроде этого я бы выбрал XNA Пример WinForms . Используя этот образец в качестве модели, кажется, что один из способов визуализации компонентов в WinForm - это создать для него элемент управления в том же стиле, что и SpinningTriangleControl из этого примера. Это демонстрирует, как визуализировать код XNA без экземпляра Game. На самом деле Игра не важна, важно то, что она делает для вас. Итак, что вам нужно сделать, это создать проект библиотеки, который имеет логику загрузки / рисования компонента в классе и в других ваших проектах, создать класс Control и класс компонента, которые являются оболочками для кода библиотеки в своих соответствующих средах. Таким образом, код, который вы тестируете, не дублируется, и вам не нужно беспокоиться о написании кода, который всегда будет жизнеспособным в двух разных сценариях.

0
ответ дан 3 December 2019 в 17:22
поделиться

Я вернусь к вашему посту, если вы не возражаете, поскольку мой кажется менее активным, и вы уже поставили на карту свою репутацию;)

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

Фреймворк можно было разработать таким образом, чтобы его было проще расширить. Мне трудно поверить в главный аргумент Шона о том, что перфоманс на интерфейсах . Чтобы поддержать меня , его коллега говорит, что от перфоманса легко уклониться.
Обратите внимание, что во фреймворке уже есть интерфейсы IUpdatable и IDrawable. Почему бы не пройти весь путь?

С другой стороны, я также думаю, что действительно мой (и ваш) дизайн небезупречен. Там, где я не зависим от объекта Game, я сильно зависим от объекта GraphicsDevice. Я посмотрю, как я могу это обойти. Это сделает код более сложным, но я думаю, что действительно смогу сломать эти зависимости.

1
ответ дан 3 December 2019 в 17:22
поделиться
Другие вопросы по тегам:

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