Использование SpriteBatch.Begin() внутри другого SpriteBatch.Begin()

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

Class Game
{
    Character x;

    public Draw(...)
    {
        spriteBatch.Begin(transformation1);
        x.Draw();
        spriteBatch.End();

        spriteBatch.Begin(transformation2);
        otherThing.Draw();
        spriteBatch.End();
    }
}

Class Character
{
    Animation[] animations;
    int currentAnimation;

    public Draw(...)
    {
        this.animations[this.currentAnimation].Draw();
    }
}

Class Animation
{
    Frame[] frames;
    int currentFrame;

    public Draw(...)
    {
        this.frames[this.currentFrame].Draw();
    }
}
Class Frame
{
    Texture2D texture;
    Texture2D shadow;

    public Draw(...)
    {
        spriteBatch.Begin(sub_transformation1);
        spriteBatch.Draw(texture1, ...);
        spriteBatch.End();

        spriteBatch.Begin(sub_transformation2);
        spriteBatch.Draw(shadow, ...);
        spriteBatch.End();
    }
}

Если я попробую эту логику, я получу «Начало не может быть вызвано снова, пока End не будет успешно вызван». ошибка. Поэтому я спрашиваю, возможна ли / имеет ли смысл эта логика? Я использую Begin() внутри Begin() для выполнения аддитивных преобразований. Если у меня есть символ на x = 100 и y = 100, и я хочу, чтобы текстура и тень кадра и все остальное, что я хочу (ограничивающие рамки и т. д.), были нарисованы с использованием этого перевода 100 100 плюс -Xscale или +Xscale для горизонтального отражения персонажа (я знаю, что мог бы использовать SpriteEffects.FlipHorizontally в .Draw, но я хотел что-то, что автоматически применялось бы к нижним уровням (анимация и кадр)), и, наконец, на уровне кадра текстура имеет преобразование на сверху один от персонажа, а у тени есть еще один. Не знаю, хорошо ли я объяснил, но спросите, есть ли у вас сомнения.

Большое спасибо.


person xlar8or    schedule 14.03.2011    source источник


Ответы (2)


Я вроде понимаю, откуда вы, но это просто невозможно. SpriteBatch не может быть иерархическим, как вы хотите. Однако ваши объекты могут.

Немного отредактировано, чтобы ответить на ваш вопрос ниже:

Class Frame
{
    // World - parent transformation to build from, passed 
    // from animation, from character, on up the chain...
    // localTransform - local coordinates
    // shadowTransform - maybe not needed?
    public Draw(Matrix world, Matrix localTransform, Matrix shadowTransform)
    {
        spriteBatch.Begin();
        spriteBatch.Draw(
            texture1, 
            ..., 
            Matrix.Transform(world * localTransform),
            ...);

        spriteBatch.Draw(
            shadowTexture, 
            ..., 
            Matrix.Transform(world * localTransform * shadowTransform), 
            ...);

        spriteBatch.End();
    }
}

Вам не нужно передавать всю информацию о символе или объекте во фрейм — просто нужно, чтобы преобразование было установлено родительским фреймом. Ваш исходный код уже откуда-то получал преобразование (sub_transformation1 и 2) — здесь мы просто передаем это значение в функцию Draw. Вы также можете сделать localTransform переменной класса, установить ее при создании экземпляра.

Класс Animation будет иметь аналогичную сигнатуру Draw(Matrix world...). Я думаю, что он достигает того, что вы ищете, и отчасти похож на то, как OpenGL обрабатывает вещи - просто более ручной (из того немногого, что я помню об этом много лет назад).

Примечание: есть gamedev.stackexchange.com для вопросов, связанных с игрой.

person Leniency    schedule 14.03.2011
comment
Это имеет смысл, но это будет означать, что анимация и кадр были переданы вместе с позицией, направлением взгляда и т. д. от персонажа. Я хочу что-то более независимое и универсальное, чтобы я мог использовать их с высшими классами, которые применяют преобразования помимо символов. У меня опыт работы с OpenGL/DirectX, поэтому неспособность делать эти простые вещи меня немного смущает. Я знаю, что в XNA есть способ делать вещи в большей степени DirectX, используя CreateOrthoMatrix и DrawPrimitives, хотя это намного больше работы, чем использование SpriteBatch, но похоже, что я должен использовать это, чтобы делать то, что я хочу. - person xlar8or; 16.03.2011
comment
Отредактированный ответ на адрес комментария. - person Leniency; 16.03.2011

Если вы думаете о SpriteBatch с точки зрения традиционной модели трансформации World/View/Project:

Вы должны выполнять преобразование «Мир» в вызове Draw. То есть, если ваш спрайт находится в position, вы должны нарисовать его в position. Если у него есть тень в точке position + 100, нарисуйте ее и там.

Вы должны выполнять преобразование View (и Project, если вам интересно) — это преобразование «камеры» — в вызове Begin.

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

Вы не можете «складывать» преобразования с помощью SpriteBatch, вам придется реализовывать такую ​​​​вещь извне.

person Andrew Russell    schedule 15.03.2011