Я вернулся. Еще раз. : 3 Прямо сейчас, я работаю над моим проектом RPG (просто для удовольствия, у меня нет иллюзий, что это будет легко), и я дошел до того, что написал основную структуру и Теперь я хочу написать элегантный метод рисования спрайтов со спрайта.Спрайты, XNA, C# и элегантность
На данный момент я использую карту спрайтов из алмаза pokémon (просто чтобы проверить, потому что она была легко доступна. Я не делаю следующую игру «покемон»), в которой главный герой, идущий во всех трех направлениях, одна строка, спрайты 37px x 37px, 12 спрайтов на изображении.
Изображение находится здесь: http://spriters-resource.com/ds/pkmndiamondpearl/lucas.png (Я работаю с подпрограммой «Ходьба», в настоящее время).
Я создал SpriteSheet класс (вместе с классом SpriteSheetData, который является представлением файла XML для коллекции spritesheets) и класса SpriteManager, все из которых перечислены ниже:
SpriteSheet.cs
namespace RPG.Utils.Graphics
{
/// <summary>
/// Represents a Sprite Sheet. A Sprite Sheet is a graphic that contains a number of frames for animations.
/// These are laid out a set distance apart.
/// </summary>
public struct SpriteSheet
{
/// <summary>
/// The name for the texture. Used internally to reference the texture.
/// </summary>
[ContentSerializer]
public string TextureName
{
get;
private set;
}
/// <summary>
/// The file name of the texture.
/// </summary>
[ContentSerializer]
public string TextureFile
{
get;
private set;
}
/// <summary>
/// The width of each sprite in the sprite sheet.
/// </summary>
[ContentSerializer]
public int SpriteWidth
{
get;
private set;
}
/// <summary>
/// The height of each sprite in the sprite sheet.
/// </summary>
[ContentSerializer]
public int SpriteHeight
{
get;
private set;
}
/// <summary>
/// The interval between each frame of animation.
/// This should be (by default) 100f or 100ms.
/// </summary>
[ContentSerializer]
public float AnimationInterval
{
get;
set;
}
/// <summary>
/// The number of frames per each individual animation.
/// </summary>
[ContentSerializer]
public int AnimationLength
{
get;
set;
}
/// <summary>
/// The texture for this sprite sheet.
/// </summary>
[ContentSerializerIgnore]
public Texture2D Texture
{
get;
set;
}
}
SpriteManager.cs
/// <summary>
/// A sprite manager. Just loads sprites from a file and then stores them.
/// </summary>
public static class SpriteManager
{
private static Dictionary<string, SpriteSheetData> m_spriteSheets;
public static Dictionary<string, SpriteSheetData> SpriteSheets
{
get
{
if (m_spriteSheets == null)
m_spriteSheets = new Dictionary<string, SpriteSheetData>();
return m_spriteSheets;
}
}
/// <summary>
/// Loads all the sprites from the given directory using the content manager.
/// Sprites are loaded by iterating SpriteSheetData (.xml) files inside the /Sprites/ directory.
/// </summary>
/// <param name="mgr">Content Manager.</param>
/// <param name="subdir">Directory to load.</param>
public static void LoadAllSprites(ContentManager mgr, string subdir)
{
// Get the files in the subdirectory.
IEnumerable<string> files = Directory.EnumerateFiles(mgr.RootDirectory+"/"+subdir);
foreach (string f in files)
{
// Microsoft, why do you insist on not letting us load stuff with file extensions?
string fname = f.Replace("Content/", "").Replace(".xnb", "");
SpriteSheetData data = mgr.Load<SpriteSheetData>(fname);
string spriteSheetDir = subdir +"/" + data.SpriteSheetName + "/";
int loaded = 0;
for (int i = 0; i < data.SpriteSheets.Length; i++)
{
loaded++;
SpriteSheet current = data.SpriteSheets[i];
current.Texture = mgr.Load<Texture2D>(spriteSheetDir + current.TextureFile);
data.SpriteSheetMap[current.TextureName] = current;
}
Console.WriteLine("Loaded SpriteSheetData file \"{0}\".xml ({1} sprite sheet(s) loaded).", data.SpriteSheetName, loaded);
SpriteSheets[data.SpriteSheetName] = data;
}
}
/// <summary>
/// Query if a given Sprite definition file is loaded.
/// </summary>
/// <param name="spriteName">
/// The sprite definition file name (ie, "Hero"). This should correspond with the XML file
/// that contains the definition for the sprite sheets. It should NOT be the name OF a spritesheet.
/// </param>
/// <returns>True if the sprite definition file is loaded.</returns>
public static bool IsLoaded(string spriteName)
{
return SpriteSheets.ContainsKey(spriteName);
}
}
SpriteSheetData.cs
/// <summary>
/// Represents data for a SpriteSheet. These are stored in XML files.
/// </summary>
public struct SpriteSheetData
{
/// <summary>
/// The collective name for the sprite sheets.
/// </summary>
[ContentSerializer]
public string SpriteSheetName
{
get;
set;
}
/// <summary>
/// The SpriteSheets in this data file.
/// </summary>
[ContentSerializer]
internal SpriteSheet[] SpriteSheets
{
get;
set;
}
[ContentSerializerIgnore]
private Dictionary<string, SpriteSheet> m_map;
/// <summary>
/// The sprite sheet map.
/// </summary>
[ContentSerializerIgnore]
public Dictionary<string, SpriteSheet> SpriteSheetMap
{
get
{
if (m_map == null)
m_map = new Dictionary<string, SpriteSheet>();
return m_map;
}
}
}
И файл, который я использую, чтобы «читать» спрайтов является: спрайты/Hero.xml
<?xml version="1.0" encoding="utf-8" ?>
<XnaContent>
<Asset Type="RPG.Utils.Graphics.SpriteSheetData">
<SpriteSheetName>Hero</SpriteSheetName>
<SpriteSheets>
<Item Type="RPG.Utils.Graphics.SpriteSheet">
<TextureName>HeroWalking</TextureName>
<TextureFile>hero_walk</TextureFile>
<SpriteWidth>37</SpriteWidth>
<SpriteHeight>37</SpriteHeight>
<AnimationInterval>400</AnimationInterval>
<AnimationLength>3</AnimationLength>
</Item>
</SpriteSheets>
</Asset>
</XnaContent>
Проблема, которую я имею что я неуверен способ элегантно организовать 1) загрузка спрайта и 2) спаривание листа спрайта (это «общая» часть игры, бит, который я намереваюсь повторно использовать, поэтому я не знаю КАК многие экземпляры объекта, который я могу создать) объекту/игровому объекту - особенно игроку (так как это то, что я пытаюсь сделать сейчас). Я не уверен, как продолжить, поэтому любая помощь ВОЗМОЖНО высоко ценится.
Если вам нужно больше кода (не дай Бог) просить и дастся вам: 3
Как в стороне, что-то, что мне нравится в целом с этими менеджерами, позволяет им иметь метод рисования. Этот метод принимает в SpriteBatch или GraphicsDevice и отображает его данные, а затем уходит. Это очень элегантно позволяет вам разделить вашу «Обновить логику» и «Рисовать» в вашем основном игровом цикле. Это также не дает вашим классам отделиться от знания слишком многого о другой логике игры и менеджерах. Мне нравится держать мои классы как можно более независимыми, чтобы предотвратить перенос ошибок. Надеюсь, что это поможет! Ура! –