随着WP7热度的逐渐提高,XNA作为一套低廉而又简单的开发环境,非常适用于为手机平台游戏开发游戏。当然,XNA本身的架构也非常适合制作不太复杂的游戏。
最近实验室要求用XNA做一个基于WinForm的类似于3D模型查看的软件,该软件能够打开任意的.X后缀的模型文件,并要求显示在WinForm窗口中。
虽然XNA很好用,为开发者提供的接口很丰富,本人也曾花过一个月的时间学习了XNA入门作《Learning XNA 3.0》,但在例子程序都是使用的XNA本身的架构。
首先,如何在WinForm下使用XNA就是摆在面前的第一个难题。
上网查了下,microsoft想的很全面,为一些“非主流”开发者提供了这方面的代码:示例代码网站
原文是:
This sample shows you how to use an XNA Framework GraphicsDevice object to display 3D graphics inside a WinForms application.
---本示例将告诉你如何使用一个XNA Framework GraphicsDevice 对象在WinForm窗口中显示3D图像。(值得注意的是实现winform窗口显示还有其他的方法,感兴趣的可以上网查,本文所讲到的是只是其中一种,是结合所给的示例代码来实现的)
文件目录如下图:
这里我们只关注标识的三个文件,在这之前先来看看整个工程的思路:
就我看到来讲,其核心是不断调用Control本身的OnPaint()方法达到类似XNA本身的重绘效果,这个效果需要你在实现具体控件时,在重写的Initializae()方法中插入以下代码
// Hook the idle event to constantly redraw our animation.
Application.Idle += delegate { Invalidate(); };
解决完了上述问题,接下来就要做关于动态content管道的工作
microsoft给出这方面的示例代码
XNA Framework Content Pipeline负责将内容文件(模型、纹理、声音等)转换为游戏易于加载和使用的格式。通常,这些内容文件会被添加到Visual Studio项目中,Content Pipeline生成过程是在Visual Studio中,当你生成代码时运行的。编译过的.xnb文件和游戏执行文件一起被发布。事先进行内容处理的操作可以让速度更快,这样游戏就可以尽可能快地加载已经编译过的内容文件。而且,Visual Studio也能在生成项目时发现内容可能包含的错误,这个做法比在运行时发现错误更好。但这样随之而来的问题是对于事先并不知道的模型文件,不可能全部编译,需要在运行时动态编译后再拿起所用。
基于这样的需求,结合所给的示例代码,我们要做的就是在代码在代码中手动实现本由编译器完成的模型文件的编译几家在工作:ContentBuilder用来动态地导入和处理内容文件,ContentManager用来加载生成后的模型。对于编译好的content文件,将其放入临时文件夹中并统一管理。
模型从编译到载入的简单实现:
/// <summary>
/// Loads a new 3D model file into the ModelViewerControl.
/// 载入一个新的3D模型文件到ModelViewControl控件中
/// </summary>
void LoadModel(DataTable dt)
{
Cursor = Cursors.WaitCursor;
// Unload any existing model.
// 卸载任何存在的模型
// modelViewerControl1.Models.Clear();
contentManager.Unload();
// Tell the ContentBuilder what to build.
// 告诉ContentBuilder去生成什么
contentBuilder.Clear();
foreach (DataRow dataRow in dt.Rows)
{
string ModelName = dataRow["ModelName"].ToString();
string fileName = dataRow["fileFullPath"].ToString();
contentBuilder.Add(fileName, ModelName, null, "ModelProcessor");
}
//添加Effect,告诉ContentBuilder去处理Effect文件
//MessageBox.Show(System.IO.Directory.GetCurrentDirectory() + @"\Effect\RedLighting.fx");
// Build this new model data.
// 生成新的模型数据
string buildError = contentBuilder.Build();
if (string.IsNullOrEmpty(buildError))
{
// If the build succeeded, use the ContentManager to
// load the temporary .xnb file that we just created.
// 如果生成成功,使用ContentManager装载创建的临时.xnb文件
foreach (DataRow dataRow in dt.Rows)
{
string ModelName = dataRow["ModelName"].ToString();
}
modelViewerControl1.Models = models;
//模型变红特效
modelViewerControl1.RedLightingEffect = contentManager.Load<Effect>("RedLighting");
//
modelViewerControl1.GetEffectParameters();
}
else
{
// If the build failed, display an error message.
// 如果生成失败,显示错误信息
MessageBox.Show(buildError, "Error");
}
Cursor = Cursors.Arrow;
}