在 XNA 中读取 spritesheet XML 文件

Posted

技术标签:

【中文标题】在 XNA 中读取 spritesheet XML 文件【英文标题】:Reading a spritesheet XML file in XNA 【发布时间】:2012-10-31 17:13:15 【问题描述】:

嘿,我已经四处寻找了一段时间,但我仍然找不到这个问题的直接答案。我有一个 XNA 游戏,其中部分 UI 显示一个图标,该图标会经常更改(多久不相关)。我决定使用一个简单的 spritesheet 制作器来输出 spritesheet 以及一个简单的 XML 文件,其中包含每个单独图标的位置。

我希望能够将相应图标的精灵表位置和图标大小从 XML 文件读取到 Rectangle 中。然后我可以将它用作绘图位的源矩形。

但是,我还没有遇到过一个简单的解释,说明如何在不编写自己的内容管道的情况下将 XML 文件加载到 XNA 4.0 项目中(如果可能的话,我想避免这样做)并且一旦加载后如何有效地加载(通常) 将数据提取到Rectangle 变量中。

XML 文件如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with TexturePacker http://texturepacker.com-->
<!-- $TexturePacker:SmartUpdate:748fc56befb00c22540f953093f731a7$ -->
<!--Format:
n  => name of the sprite
x  => sprite x pos in texture
y  => sprite y pos in texture
w  => sprite width (may be trimmed)
h  => sprite height (may be trimmed)
oX => sprite's x-corner offset (only available if trimmed)
oY => sprite's y-corner offset (only available if trimmed)
oW => sprite's original width (only available if trimmed)
oH => sprite's original height (only available if trimmed)
r => 'y' only set if sprite is rotated
-->
<TextureAtlas imagePath="Loadout_Icons.png"  >
    <sprite n="Charge_Down.png" x="0" y="0" w="37" h="43"/>
    <sprite n="Charge_Up.png" x="37" y="0" w="37" h="43"/>
    <sprite n="Damage_Down.png" x="74" y="0" w="37" h="43"/>
    <sprite n="Damage_Up.png" x="111" y="0" w="37" h="43"/>
    <sprite n="FireRate_Down.png" x="148" y="0" w="37" h="43"/>
    <sprite n="FireRate_Up.png" x="0" y="43" w="37" h="43"/>
    <sprite n="Health_Down.png" x="37" y="43" w="37" h="43"/>
    <sprite n="Health_Up.png" x="74" y="43" w="37" h="43"/>
    <sprite n="Speed_Down.png" x="111" y="43" w="37" h="43"/>
    <sprite n="Speed_Up.png" x="148" y="43" w="37" h="43"/>
</TextureAtlas>

我也不确定我是否会因为不制作自己的 XML 文件而自取其辱,那会更容易吗?

我已经阅读了 msdn 提供的大部分内容,但无济于事,但任何指向相关页面或问题的链接将不胜感激。 提前致谢。

【问题讨论】:

您要求避免使用内容管道,这是为什么呢?您希望在运行时手动加载它吗? @William'MindWorX'Mariager 我不想完全避免管道但是我读过的一些教程涉及以我无法理解的相当复杂的方式对其进行扩展。如果有一种内置的方法或简单的方法,那将是最佳的。 虽然出于学习原因,我当然赞成自己实施内容管道导入器和处理器,但其他人已经这样做了:thirdpartyninjas.com/blog/2012/08/02/… @NikoDrašković 感谢您的链接,非常有帮助,我决定使用他们的扩展来解决我最初的问题。在这种情况下,对于不使用纹理打包器的其他人,我找不到更通用的解决方案。 【参考方案1】:

以下应该可以工作,但是,它完全未经测试:

[XmlRoot("TextureAtlas", IsNullable = false)]
public class TextureAtlasXml

    public static TextureAtlasXml FromFile(String file)
    
        using (var stream = File.OpenRead(file))
        
            return FromStream(stream);
        
    

    public static TextureAtlasXml FromStream(Stream stream)
    
        var serializer = new XmlSerializer(typeof(TextureAtlasXml));
        return (TextureAtlasXml)serializer.Deserialize(stream);
    


    [XmlAttribute("imagePath")]
    public String ImagePath;

    [XmlAttribute("width")]
    public Int32 Width;

    [XmlAttribute("height")]
    public Int32 Height;

    [XmlElement("sprite")]
    public List<SpriteXml> Sprites;


public class SpriteXml

    [XmlAttribute("n")]
    public String Name;

    [XmlAttribute("x")]
    public Int32 X;

    [XmlAttribute("y")]
    public Int32 Y;

    [XmlAttribute("w")]
    public Int32 Width;

    [XmlAttribute("h")]
    public Int32 Height;

    public Rectangle Rectangle  get  return new Rectangle(this.X, this.Y, this.Width, this.Height);  

我建议您考虑使用内容管道,因为它提供了一个不错的解决方案,但是代码应该可以按照您的意愿运行。

【讨论】:

感谢您的解决方案和您为回答问题所付出的努力,有没有办法可以提供指向“不错的解决方案”的链接,以便我可以比较这两种方式。最终,如果使用部分内容管道更简单、更容易理解,我会倾向于这样做。再次感谢! @WillBagley,这需要更多时间。我会看看我回家后能不能做这件事。但基本上,您需要创建一个 ContentImporter 和一个 ContentProcessor。好消息是,您只需加载 spritesheet,它还会自动加载必要的 Texture2D。【参考方案2】:

如果您愿意使用 Sprite Vortex(实际上是特定版本),您可以使用以下类。 您必须使用 Sprite Vortex 1.2.2,因为在较新的版本中 XML 格式发生了变化。确保您添加属性的 XML 文件更改为“不编译”。

如果您需要一个工作示例,我可以给您发送一个非常简单的示例。

附言Sprite Vortex 应该做与使用其他程序相同的事情,但是 v 1.2.2 有很多错误,但还不错。

课程在这里:http://pastebin.com/sNSa7xgQ

【讨论】:

【参考方案3】:

正如仅在评论中提到的那样,我决定说我最终使用了 Niko Drašković 的建议,即专门为纹理打包器制作的专用管道扩展,可以在 http://thirdpartyninjas.com/blog/2012/08/02/texturepacker-xna-content-pipeline-extension/ 找到。这使得处理纹理打包器生成的 XML 文件变得非常容易。

不过,作为一个附带说明,以及我重新审视这个问题的另一个原因是,我最近一直在使用 XML 做一些工作(试图更好地理解它们)以及最好的方法我发现在不为每个文件编写新的管道扩展的情况下处理读取自定义 XML 文件(就像现在看起来那样优雅)如下。我将 XML 文件添加到内容目录,就像您添加任何其他纹理等一样。在 XML 的属性中,我将 Build Action 设置为“内容”,然后 复制到输出目录 到“始终复制”。从这里我有一个单独的类,我在其中传递文件的名称,并在其中处理我需要的来自 XML 的所有内容。这些类以:

开头
Stream stream = TitleContainer.OpenStream("Content\\" + fileName + ".xml");
XDocument doc = XDocument.Load(stream);

然后继续(使用 System.Xml.Linq 库的其余部分)读取和存储适当的数据,以及轻松访问数据的方法。这可能不是解决问题的最佳方法,但它对我有用,并且足够简单,可以快速理解和实施。希望这可以帮助其他有类似问题的人。

【讨论】:

以上是关于在 XNA 中读取 spritesheet XML 文件的主要内容,如果未能解决你的问题,请参考以下文章

使用 XNA/Monogame 从 spritesheet 中绘制一个 sprite

XNA Sprite 帧不一致

XNA 减速动画

精灵表动画上的像素完美碰撞,XNA

尝试从 spritesheet 为 sprite Phaser 3 设置动画 - 出现错误无法读取未定义的属性“框架”

XNA如何使xna不能读取透明颜色