Подтвердить что ты не робот

Рекомендации: эффективный рисунок спрайта в XNA

Каков эффективный способ рисования спрайтов в моей 2D-игре XNA? Чтобы быть более конкретным, я разделил этот вопрос на 4 вопроса.


Я использовал объявление Game1 spriteBatch static и называл SpriteBatch.Begin и .Close в каждом IDrawable.Draw. Это не сработало. Предоставление каждому из своих собственных SpriteBatch тоже не получилось.

Q1. Я полагаю, что лучше всего иметь один экземпляр SpriteBatch и только вызывать begin/close один раз. Правильно ли это?


В настоящее время мой Game1.Draw выглядит примерно так:

spriteBatch.Begin();

base.Draw(gameTime); // draws elements of Game.Components

// ...

spriteBatch.End();

Q2: Таким образом, Begin вызывается только один раз. Это путь? Как вы, ребята, решили это?


Q3. Кроме того, каждый компонент имеет собственный метод IGameComponent.LoadContent. Должен ли я загружать там свой контент? Или лучше загружать контент в родительский класс, например Game1.LoadContent?


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

static Texture2D defaultTexture;
public Texture2D MyTexture;

public Enemy()
    : this(defaultTexture) { }

public Enemy(Texture2D texture)
{
    MyTexture = texture;
}

protected override void LoadContent()
{
    if (MyTexture == null)
    {
        if (defaultTexture == null)
        {
            defaultTexture = Content.Load<Texture2D>("enemy");
        }

        MyTexture = defaultTexture;
    }
}

Таким образом, текстуры по умолчанию для класса загружаются только при первом вызове LoadContent в этом классе. Однако, когда параметр texture указан в конструкторе, мне придется предварительно загрузить эту текстуру.

Q4: Я думаю, что должны быть лучшие способы сделать это. Я думаю о создании словаря текстур с именами их активов как строки. Что бы вы предложили?

4b9b3361

Ответ 1

Я использовал, чтобы объявлять статическую игру Game1 spriteBatch

Вам не обязательно статично. Просто сделайте синглтон. Метод Draw

SpriteBatch spriteBatch = ScreenManager.SpriteBatch; // singletion SpriteBatch
spriteBatch.Begin();
// Draw the background
spriteBatch.Draw(background, ...
foreach (var enemy in enemys)
{
     enemy.Draw(gameTime);
}
// etc.
spriteBatch.End(); // call here end 
base.Draw(gameTime); // and then call the base class

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

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

Вы добавляете свои элементы в глобальную коллекцию компонентов? Это плохая идея добавить в эту коллекцию. Вы не можете контролировать порядок рисования, компоненты являются глобальными. См. этот ответ.

Внедрите в свои компоненты IUpdatable и IDrawable и вызовите их в своем коде, где вам это нужно. Избавьтесь от статического материала и используйте Injection Dependency istead.

Кроме того, каждый компонент имеет свой собственный метод IGameComponent.LoadContent. Должен ли я загружать там свой контент? Или лучше загружать контент в родительский класс, например Game1.LoadContent?

Вы должны загружать активы, когда они вам нужны, и вы несете ответственность за это. Вы не должны загружать все 30 уровней, когда пользователь только начал игру, не так ли? Например, когда ваша игра начинается, вы загружаете все активы, которые вам нужны для стартового экрана и главного меню. Если вы загружаете только то, что вам нужно, игрок счастлив, что игра начнется быстро. Затем игрок хочет начать геймплей. Здесь вы можете загружать активы в отдельный поток, чтобы поддерживать приложение в обратном порядке.

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

Content.Load уже кэшируется, поэтому вам не нужно это делать.

Ответ 2

насколько можно почерпнуть из tutorials вокруг

вызов begin и end только один раз является предпочтительным методом.

Ответ 3

Q4: Я думаю, что должны быть лучшие способы сделать это. Я думаю о создании словаря текстур с именами их активов как строки. Что бы вы предложили?


A4. Обычно я создаю Dictionary<string, Texture2D> NameTextureDic в моем классе TextureLib (который обрабатывает загрузку png-изображений во время выполнения), поэтому я могу получить любую текстуру следующим образом:

var t2d = textureLib.NameTextureDic["tree-4"];