WinForms Content Loading示例

程序截图

本示例展示了如何通过动态运行Content Pipeline导入器和处理器在运行时导入任意模型,你无需事先生成内容。

原文地址:http://creators.xna.com/en-US/sample/winforms_series2。

示例概览

XNA Framework Content Pipeline负责将内容文件(模型、纹理、声音等)转换为游戏易于加载和使用的格式。通常,这些内容文件会被添加到Visual Studio项目中,Content Pipeline生成过程是在Visual Studio中,当你生成代码时运行的。编译过的.xnb文件和游戏执行文件一起被发布。事先进行内容处理的操作可以让速度更快,这样游戏就可以尽可能快地加载已经编译过的内容文件。而且,Visual Studio也能在生成项目时发现内容可能包含的错误,这个做法比在运行时发现错误更好。

但这个方法有一个问题:如果我们事先不知道需要使用哪些内容怎么办?或许你想让用户可以在游戏中添加一个新模型,或许你想编写一个关卡编辑器需要通过一个实时运行的文件选择窗口加载任意文件。

解决方法是通过自己的代码实时调用Content Pipeline生成过程。Content Pipeline是作为一个MSBuild任务实现的,你可以使用MSBuild API构建一个临时的content项目,添加你想要的任何文件,并将它生成到一个临时文件夹中,然后通过ContentManager加载最后的.xnb文件。这个操作可以进行任意次。

本示例建立在前面的WinForms Graphics Device示例的基础上。它实现了一个3D模型观察控件,这个控件使用了一个文件选择器让用户选择任意的.fbx或.x格式的模型,然后它导入并加载模型,然后显示在屏幕上。

Content Pipeline生成过程是增量的(incremental),意思就是如果内容已经在前一次生成中处理过,它就会避免做同样的工作。如果临时文件夹已经存在,本示例会删除它。这会强迫下一次生成重新生成内容。根据你的需要,你可能想用一个更简单的固定路径代替这个目录管理系统,这样做的话,你可以牺牲一点磁盘空间用来改善增量重新生成的性能。

注意这个示例只能运行在Windows平台上,WinForms,MSBuild和Content Pipeline在Xbox 360上不可用。如果你想让游戏运行在Xbox 360上,你必须将所有内容文件作为Visual Studio项目的一部分事先生成。还要注意XNA Framework redistributable安装包不包含Content Pipeline,这个示例只能运行在完整安装XNA Game Studio的计算机上。

最小Shader配置

Vertex Shader Model 1.1

Pixel Shader Model 1.1

工作原理

这个示例重用了WinForms Graphics Device示例中的 GraphicsDeviceControl.cs,GraphicsDeviceService.cs和ServiceContainer.cs文件。

程序的主窗体包含一个ModelViewerControl,这个控件从GraphicsDeviceControl继承,可以处理任意Model对象 ,将模型显示在屏幕上并进行旋转。当模型改变时,MeasureModel方法用来确定新模型的大小和中心,让模型总是以合适的大小放置在屏幕中心。

MainForm构造函数创建了两个主要的类:ContentBuilder用来动态地导入和处理内容文件,ContentManager用来加载生成后的模型。在显示了一个文件选择器让用户选择一个3D模型文件之后,MainForm.LoadModel方法进行了以下操作:

1.调用 ContentManager.Unload方法卸载前一个模型数据。

2.调用ContentBuilder.Add方法指定生成哪个文件、使用何种处理器。本示例总是使用内建的ModelProcessor,但其他更高级的程序可以使用某些自定义的处理器。

3.调用ContentBuilder.Build生成选择的内容。

4.检查是否有生成错误,如果有误则显示一个信息框。

5.调用ContentManager.Load读取刚才生成的模型,并使用ModelViewerControl显示这个新模型。

ContentBuilder类很简单。它声明了一个用于生成内容的内容编译器的列表(本例使用了四个内建于XNA Game Studio中的四个标准导入器)。然后声明了三个用于生成操作的辅助类:一个MSBuild Engine对象,一个MSBuild Project对象和一个自定义的ErrorLogger类型用于实现MSBuild Ilogger接口。CreateBuildProject方法使用MSBuild对象模型创建一个简单的项目用来生成XNA Framework content,这个方法在项目的最后添加了一个指向标准ContentPipeline.targets文件的引用,这个引用表明MSBuild targets需要进行content生成。Add和Clear方法改变包含在项目中的content文件。最后,Build方法进行生成操作,如果出错还会返回错误信息的列表。

临时文件夹的管理

ContentBuilder类型将content生成到一个临时文件夹,这样ContentLoader就可以从这个临时文件夹中加载生成的内容。问题是:你将使用哪个文件夹?你想要一个还没有使用的位置,最好当程序存在时删除这些临时文件。

ContentBuilder.CreateTempDirectory通过调用Path.GetTempPath查找一个合适的位置作为临时文件夹,然后制作一个叫做GetType().FullName的目录,它返回"WinFormsContentLoading.ContentBuilder",这和其他程序不同,其他程序需要使用一个使用这个名称的文件夹(而它不需要)!

但是如果用户在同一时间中运行了程序的另一个副本该如何处理呢?这两个实例都要使用相同的临时目录,这样就会导致冲突。解决方法是将Process.GetCurrentProcess().Id作为目录的一部分,这样不同的进程就会选择不同的目录名称。

但是如果一个程序创建了多个ContentBuilder对象该如何处理呢?本示例不会这样做,但其他程序有可能,而且,也应该有一个更强壮的实现。如果两个ContentBuilder对象使用相同的临时目录也会发生冲突。解决方法是包含一个名为“salt”的唯一整数值,将它作为目录名称的一部分。每次创建一个新ContentBuilder时,我们就将这个值加1,第一个实例为1,第二个为2,以此类推,这样每个对象就会选择一个不同的目录名称了。

当操作完成后如何清理临时目录?这是由ContentBuilder.DeleteTempDirectory处理的,这个方法由Dispose调用。DeleteTempDirectory可以在大多数情况下做好这个工作。但是还有一个缺点:如果程序在清理目录之前发生冲突或在调试中被打断时怎么办?理想情况是你可以顺利结束程序而不发生任何冲突,但不幸的是,在开发和测试过程中总是会遇到冲突。如果每次发生冲突都会在你的硬盘上留下额外的临时文件夹是非常令人讨厌的。解决方法是PurgeStaleTempDirectories方法。这个方法在程序开始时被调用。它不是在每次冲突之后进行清理操作,而是在下一次程序运行时进行,你可以检查是否有过时的文件夹在上次程序运行之前被遗留下来,如有必要就删除它们。

基于你的应用程序,你可能更希望总是使用相同的临时目录名称而不删除它。这样做会在硬盘上留下文件。内容生成过程是增量运行的,如果你的程序试图加载前一次运行生成的相同内容文件,就无需进行实际的处理工作了。例如:在关卡编辑器中在每次开始运行时会加载相同的文件,如果你使用相同的临时目录而不删除它,这可以加快程序的加载速度。

文件下载(已下载 1937 次)

发布时间:2010/8/29 上午6:53:00  阅读次数:8130

2006 - 2024,推荐分辨率 1024*768 以上,推荐浏览器 Chrome、Edge 等现代浏览器,截止 2021 年 12 月 5 日的访问次数:1872 万 9823 站长邮箱

沪 ICP 备 18037240 号-1

沪公网安备 31011002002865 号