3

我正在为我正在构建的 XNA 游戏构建一个游戏编辑器,该游戏将接受 JPEG/PNG,并输出一个包含 Texture2D 内容的 XNB 文件。

我有用于我的自定义等的自定义序列化程序,我正在挖掘所有内容以使用反射等调用 ContentCompiler,进入真正的脏位,我实际上可以让这部分为我自己的格式工作。但是我现在需要序列化为 XNA 知道如何编译的常规 Texture2D 格式(在构建项目时在 Visual Studio 中)和加载(在游戏中使用最常用的 Content.Load 方法。我不想制作自己的图像这显然是文件格式。当我尝试编译 Texture2D 时,它不会给我一个错误,它会创建 XNB 文件,但文件内容不是图像数据,它只是大约 3-4 KB 的开销(我认为是 Texture2D 对象的其他非图像属性)。

这是我用于编译的代码:

    protected void InitializeWriter()
    {
        Type compilerType = typeof(ContentCompiler);
        cc = compilerType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0].Invoke(null) as ContentCompiler;
        compileMethod = compilerType.GetMethod("Compile", BindingFlags.NonPublic | BindingFlags.Instance);
    }

    internal void Write(string objectName, string path, object objectToWrite) 
    {
        if (basePath == null)
        {
            throw new InvalidOperationException("The base path to write has not been set.");
        }
        if (cc == null) { InitializeWriter(); }
        string fullPath = Path.Combine(basePath, path, objectName + ".xnb");
        using (FileStream fs = File.Create(fullPath))
        {
            compileMethod.Invoke(cc, new object[]{
            fs, objectToWrite, TargetPlatform.Windows, GraphicsProfile.Reach, false/*true*/, fullPath, fullPath
        });
        }
    }

我有自己的内容处理器,这段代码可以完美地与它们配合使用。这只是调用 ContentCompiler 的 Compile 方法,但使用了反射(因为它是一个内部类)。

我不明白为什么 Texture2D 会序列化,但没有实际的位图数据。

编辑 对不起,它不编译Texture2D(它抱怨我的GraphicsDevice的循环引用),如果我尝试编译一个Bitmap对象,它编译没有错误但不序列化实际的位图数据)

4

1 回答 1

1

好的,经过一些挖掘和数小时的研究,我已经解决了我的问题。

这是做什么:

您不能序列化 Texture2D 并将其加载回来。尽管加载显然没有问题(因为我们在任何 2D XNA 游戏中使用内容管理器加载 Texture2D),但我们无法保存它以便从游戏中加载它。在对该问题进行进一步调查后,我发现了一个 Texture2DContent 类(在图形管道中),我认为它会序列化为 Texture2D(结果证明是完全正确的)。

所以我只是连接了一个 Texture2DContent 类的新实例,但没有办法将它的数据设置为我的位图。搜索了所有 DLL 和基类/派生类,但没有办法。然后我实现了一个具有导入方法的 TextureImporter 类。它需要一个文件名和一个 ContentImporterContext,这是一个复杂的类,它也有来自其他深层内部工作类的构造函数,我只知道我无法正确初始化它。所以我尝试将 null 作为我的参数传递给导入方法,单步执行代码以查看我的 NullPointerException,但奇怪的是,它起作用了,并输出了我的文件。我检查了 XNB,它只是一个有效的纹理。这是我的代码:

    TextureImporter importer = new TextureImporter();
    Texture2DContent tc = importer.Import(item, null) as Texture2DContent;
    AssetWriter.Write(item.Substring(item.Replace('\\', '/').LastIndexOf('/') + 1), tc);

其中item只是一个文件名,而 AssetWriter 实际上是这样做的(其中有一些方法,但我在下面将它们粘贴在一起):

   Type compilerType = typeof(ContentCompiler);
   cc = compilerType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0].Invoke(null) as ContentCompiler;
   compileMethod = compilerType.GetMethod("Compile", BindingFlags.NonPublic | BindingFlags.Instance);
   string fullPath = Path.Combine(basePath, path, objectName + ".xnb");
   using (FileStream fs = File.Create(fullPath))
   {
      compileMethod.Invoke(cc, new object[]{
      fs, objectToWrite, TargetPlatform.Windows, GraphicsProfile.Reach, false/*true*/, fullPath, fullPath
      });
   }

它就是这样工作的。该程序将所需的一切传递给内容编译器,然后编译器完成这项工作。它正确处理 Texture2DContent 并将其映射到 Texture2D 的 XNB 输出,然后可以使用 contentManager 的加载方法加载。

于 2012-01-15T02:12:00.407 回答