XNA&Beyond:通往VS 2008的道路(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/xna-beyond-the-path-to-vs-2008-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 33 分钟阅读 - 16462 个词 阅读量 0XNA&Beyond:通往VS 2008的道路(译文)
原文地址:https://www.codeproject.com/Articles/22152/XNA-Beyond-The-Path-to-VS-2008
原文作者:Pedro Güida
译文由本站 robot-v1.0 翻译
前言
The article shows how to embed a XNA-based game into a WinForms control with ease. Also, it explains how to integrate an XNA GS project into VS2008 (this IDE is not currently supported by XNA GS), and in turn, to be able to use WPF with your XNA-based creation.
本文介绍了如何轻松地将基于XNA的游戏嵌入到WinForms控件中.此外,它还说明了如何将XNA GS项目集成到VS2008(XNA GS当前不支持此IDE),以及如何在基于XNA的创建中使用WPF.
内容(Contents)
- 介绍(Introduction)
- 背景(Background)
- 范围(Scope)
- 先决条件(Prerequisites)
- [让我们开始吧(Let’s Get Started)](https://www.codeproject.com#Let's Get Started)
- [XNA和WinForms:一种简单的方法(XNA and WinForms: A Simple Approach)](https://www.codeproject.com#XNA And WinForms: A Simple Approach)
- [XNA和VS2008:要做和不做(XNA and VS2008: Do’s and Don’ts)](https://www.codeproject.com#XNA And VS2008: Do’s And Don’ts)
- [WPF,现在的未来(WPF, The Future Now)](https://www.codeproject.com#WPF, The Future Now)
- 隧道尽头的"银光"(The “Silverlight” at the End of the Tunnel)
- 结论(Conclusion)
- [兴趣点(Points of Interest)](https://www.codeproject.com#Points Of Interest)
- 历史(History)
介绍(Introduction)
本文介绍如何轻松地将基于XNA的游戏嵌入到WinForms控件中.此外,它还说明了如何将XNA GS项目集成到VS2008中(XNA GS当前不支持此IDE),并进而可以在基于XNA的创建中使用WPF.(This article shows how to embed a XNA-based game into a WinForms control with ease. Also, it explains how to integrate an XNA GS project into VS2008 (this IDE is not currently supported by XNA GS), and in turn, be able to use WPF with your XNA-based creation.)
背景(Background)
任何游戏开发人员都知道,如今拥有"关卡编辑"工具来构建游戏世界已成为"必须".根据项目的不同,与使用记事本设计关卡时相比,它可以帮助您更快,更轻松地构建所有内容,例如:(Any game developer knows that having a level-editing tool to construct the game’s world is nowadays “a must”. Depending on the project, it helps you build everything up faster and easier than if you had to design the level with the Notepad, by using something like, say:)
00001110 00010000
00200100 02000000
0*000000***000 0
...........................
00030020000900010
而且,我们大多数人都梦想着制作一个能够满足项目需求的关卡编辑器.让我们面对现实:一件事是使用第三方工具,但是创建我们自己的定制关卡编辑器工具则完全不同.特别是,如果您打算使用XNA GS创建该工具.(What is more, most of us dream of making a level editor that fits our project’s needs. Just let us face it: one thing is using a third-party tool, but creating our own custom-made level editor tool is a whole different story. Specially, if you plan to use XNA GS to create that tool.)
当XNA Framework首次发布时,我说:“这就是我一直在等待的!".几天前发布第二版XNA GS时,我补充说:“它越来越好了!".作为C#(高级)程序员,我喜欢使用XNA GS来开发游戏,原型和"概念验证”.它很有趣,而且大多数时候都很简单.(When the XNA Framework was first released, I said “This is what I was waiting for!”. When the second version of XNA GS was released some days ago, I added: “This is getting better and better!”. As a C# (advanced) programmer, I love using XNA GS for the development of my games, prototypes, and “proof-of-concept”. It is fun and -most of the times- simple.)
不幸的是,如果您想创建自己的关卡编辑器,那么XNA GS似乎并不是那么简单,因为乍一看,没有简单的方法将XNA Game项目嵌入到WinForms控件中.(Unfortunately, XNA GS seems not to be that straightforward if you want to create your own level editor, given that at first sight, there is no easy way to embed a XNA Game project into a WinForms control.)
原计划在v2发行版中解决此问题,但由于时间问题,XNA团队将其推迟以进行后续更新.大家,请了解XNA团队在圣诞节前为发布XNA GS 2和所有新功能所做的所有努力.来吧!实际上,他们应该得到荣誉和休息!(This issue was planned to be solved for the release of v2, but due to time issues, it was postponed by the XNA team for a later update. Please guys, understand all the effort the XNA team put to release XNA GS 2 -with all the new functionality- before Christmas. Come on! In fact, they deserve kudos and a break!)
好的,但是这种情况会使我们离开哪里?很简单,我们必须找到一种自行处理的方法.(OK, but where does this situation leave us? Simple, we have to find a way to deal with it on our own.)
如果您进行Google搜索或阅读(If you do a Google search, or read) 这个线程(this thread) 在创建者的论坛上,您会找到实现同一目标的不同方法,其中大多数都意味着重新实现图形设备,隐藏(on the creator’s forums, you will find different ways to get to the same goal, which, most of them implies re-implementing the graphics device, hiding the) Game.Run()
功能等等.(functionality, and so on.)
如果您想利用该功能并将基于XNA的项目仍嵌入WinForms控件中怎么办?如果您因为像我这样的懒惰而不想只是重新感觉到什么而又不想重新实施该怎么办?(What if you want to take advantage of that functionality and still embed your XNA-based project into a WinForms control? What if you do not want to re-implement anything because you are lazy like me or you do not just feel like it?)
更糟糕的是,如果要使用VS2008处理基于XNA的项目怎么办?您知道X1 GS版本(v1(刷新)或刚刚发布的v2)尚不支持此出色IDE的2008版本.读(To make things worse, what if you want to use VS2008 to handle your XNA-based project? You know that both XNA GS versions, either v1 (the refresh), or the just-released v2, do not yet support 2008 editions of this great IDE. Read) 这个线程(this thread) 了解更多信息.(for more information.)
综上所述,是否有一种简单的方法将基于XNA的项目嵌入到WinForms控件中,同时使用VS2008?好吧,让我们找出答案.(To sum up, is there a simple way of embedding a XNA-based project into a WinForms control and at the same time of using VS2008? Well, let us find out.)
范围(Scope)
本文仅适用于Windows(XP或Vista).(This article is for Windows only (either XP or Vista).) 为什么?因为,为了为Xbox 360编译游戏,您只需要任何版本的VS2005(如上一节所述,尚不支持VS2008).另外,我不认为您可以在360中使用WinForms控件.否则,完全没有必要撰写本文;)(Why? Because, in order to compile your games for the Xbox 360, you will only need any edition of VS2005 (as said in the previous section, VS2008 is not yet supported). Plus, I do not believe you can use WinForms controls in the 360. Otherwise, there would be no point in writing this article at all ;)) 另外,如果您想创建一个关卡编辑工具,请考虑到本文的目的不是解释如何创建一个关卡编辑器.因此,尤其是不会显示如何在运行时动态加载自定义内容,例如,使用MSBuild.有很多(Also, if you are thinking of creating a level-editing tool, take into account that it is not the purpose of this article to explain how to create a level editor; therefore, and in particular, it will not show you how to dynamically load custom content at runtime, say, by using MSBuild. There are plenty of) 文章(articles) 和(and) 一个专案(a project) 它将教您如何实现这一目标.(that will teach you how to achieve that.) 实际上,本文的主要目的是演示如何使用VS2008创建和管理基于XNA的项目.(In fact, the main objective of this article is to demonstrate how to use VS2008 to create and manage XNA-based projects.)
先决条件(Prerequisites)
为了编译项目,您将需要安装:(In order to compile the projects, you will need to install:)
- VS C#Express 2005(或任何其他VS2005版本)(VS C# Express 2005 (or any other VS2005 edition))
- VS C#Express 2008(或任何其他VS2008版本)(VS C# Express 2008 (or any other VS2008 edition))
- 最新的DirectX SDK(The latest DirectX SDK)
- 显卡的最新驱动程序(The latest drivers of your graphics card)
- 以上所有可用的最新更新(要获取大多数更新,可以使用” Windows Update"),当然(The latest updates available for all the above (to get most of them, you can use “Windows Update”), and of course)
- XNA GS 2.0(刚刚发布:为此加油!)(XNA GS 2.0 (just released: cheers for that!))
让我们开始吧(Let’s Get Started)
在以下各节中,我将尝试使所有内容保持"简单明了",以确保轻松阅读和理解概念和示例代码.(In the following sections, I will try to keep everything just “plain and simple” to assure an easy reading and understanding of the concepts and the example code.) 本文所附,您将找到两个zip文件,其中包含每个部分的源代码.您可以按照"代码项目开放许可"(CPOL)的规定自由使用和修改二者.(Attached to this article, you will find two zip files containing the source code of each section. You are free to use and modify both, following “The Code Project Open License” (CPOL).) 为使文件大小较小,基于XNA的项目所做的全部工作就是使用SpriteFonts在屏幕上显示当前日期和时间.我假设您具有XNA框架的必需知识,所以我确信在阅读本文之后,您将根据需要扩展示例和模板,以满足您的需求和梦想.(To keep the file size small, all that the XNA-based project does is to show the current date and time on the screen by using SpriteFonts. I assume you have the required knowledge of the XNA framework, so I am sure that after reading this article, you will extend the examples and templates as desired to meet your needs and dreams.) 顺便说一句,这是我为"代码项目"撰写的第一篇文章,因此,我感谢您的评论和建议^尽管很好,但;)(By the way, this is the first article I write for “The Code Project”, so I appreciate your comments and suggestions … just be nice, though ;))
XNA和WinForms:一种简单的方法(XNA and WinForms: A Simple Approach)
尽管这不是本文的主要目的,但我发现我认为这是将基于XNA的游戏嵌入WinForms控件的一种优雅而简单的方法.(Although this is not the main purpose of the article, I have found what I deem as an elegant and simple way of embedding an XNA-based game into a WinForms control.) 请不要误会我.我仍然相信,当您需要超越XNA GS在这方面提供的功能时,处理和控制(a)应该如何创建Graphics设备以及(b)主循环应该如何运行是正确的方法. .没有讨论.(Please do not misunderstand me. I still believe that when you need to go beyond what XNA GS offers right now on this regard, handling and controlling (a) how the Graphics device should be created and (b) how the main loop should behave, is the right way to go. No discussion about that.) 但是,就像我在上面的几节中所说的那样,如果您像我一样懒惰,那么您可能会对我即将提出的替代方法感兴趣.因此,如果您愿意,请继续阅读,否则请继续阅读本节.(However, and as I said a couple of sections above, if you are lazy like me, you could then be interested in the alternative I will soon present. Thus, if you do, then read on, but if you do not, then just skip this section.) 第一件事:(First things first:)
- 创建一个Windows Game项目,(Create a Windows Game project,)
- 添加一个(Add a)
Form
控制(IDE将自动设置对(control (the IDE will automatically set a reference to)System.Windows.Forms
),(),) - 最后,在要呈现的位置添加WinForms控件,例如(Finally, add the WinForms control where you want to render, say a)
Panel
和(, and) - 实现一个属性,该属性返回与将用于呈现的控件关联的句柄.(Implement a property that returns the handle associated to the control you will use for rendering.)
遵循添加标准(Following the criteria of adding a)
Panel
控件,您的部分类的代码应类似于下图所示:(control, the code of your partial class should be something similar to what is shown next:)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace WindowsGame1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public IntPtr PanelHandle
{
get
{
return this.panel1.IsHandleCreated ?
this.panel1.Handle : IntPtr.Zero;
}
}
}
}
现在,让我们转到主游戏文件,默认名称为"(Now, let us go to main game file, by default named “)Game1.cs(Game1.cs)",以根据需要修改代码.(”, to modify the code as required.) 在这里,我们将做一些事情:(Here, we will do a few things:)
- 第一次显示游戏时,将其隐藏.(Hide the game’s window when it is first shown.)
- 显示我们新创建的(Show our newly created)
Form
控制.(control, instead.) - 复制我们绘制的所有内容到我们的(Copy everything we draw to our)
Panel
的画布.(’s canvas.) - 当我们的游戏退出时(Exit the game when our)
Panel
被摧毁.(is destroyed.) 为了完成除第三个任务以外的所有操作,我们需要修改(In order to do everything but the third task, we need to modify the)Initialize
方法一点:(method a little bit:)
...
...
using SysWinForms = System.Windows.Forms;
// to avoid conflicts with namespaces
...
...
namespace WindowsGame1
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
...
...
Form1 myForm;
...
...
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
SysWinForms.Form gameWindowForm = (SysWinForms.Form)SysWinForms.Form.
FromHandle(this.Window.Handle);
gameWindowForm.Shown += new EventHandler(gameWindowForm_Shown);
this.myForm = new Form1();
myForm.HandleDestroyed += new EventHandler(myForm_HandleDestroyed);
myForm.Show();
}
...
...
}
}
另外,我们需要实现如何处理上述两个事件:(Also, we need to implement how we will handle the two above-mentioned events:)
namespace WindowsGame1
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
...
...
void myForm_HandleDestroyed(object sender, EventArgs e)
{
this.Exit();
}
void gameWindowForm_Shown(object sender, EventArgs e)
{
((SysWinForms.Form)sender).Hide();
}
...
...
}
}
现在该做第三项任务了:展示我们绘制的所有东西(It is time to do the third task: to show all the things we draw in our) Panel
控制.为此,我们只需要在该行的末尾添加一条简单的行即可.(control. In order to do that, we just need to add one simple line at the end of the) Draw
方法:(method:)
...
...
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
...
...
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
...
...
base.Draw(gameTime);
// This one will do the trick we are looking for!
this.GraphicsDevice.Present(this.myForm.PanelHandle);
}
}
}
此时,不需要任何其他操作.您应该能够执行您的项目,并看到此实现完全可以正常工作.顺便说一句,现在您知道-如果您没有早发现它-为什么我们需要获得(At this point, nothing else is needed. You should be able to execute your project and see that this implementation simply works just fine. By the way, now you know -in case you did not discover it earlier- why we needed to get the) Panel
首先.(’s handle in the first place.)
在随附的zip文件中,您将找到完整的源代码,其中还包含一些附加内容:我们使用简单的方法在屏幕上绘制当前日期和时间(In the attached zip file, you will find the complete source code with a couple of additions: we draw the current date and time on screen by using a simple) SpriteFont
,我们还添加了一个(, and we also add a) PropertyGrid
控件-如本文顶部的图片所示-只是为了好玩.(control -as the picture shows at the top of this article- just for fun.)
关于此实现的最后一条评论:您可能会遇到开销,因为即使您隐藏了"主"游戏的窗口,也可能仍在吸引它.老实说,我没有测试这种情况,因为当我使用创建自己的关卡编辑器的技术时,我只是现在不在乎性能问题.另外,如您所见,我很懒;)(One final comment about this implementation: you could probably experience an overhead because even though you are hiding the “main” game’s window, you may be still drawing to it. Honestly, I did not test if that is the case because as I am using the technique for creating my own level editor, I just simply do not care that much about performance issues right now. Plus, as you can notice, I am lazy ;))
XNA和VS2008:要做和不做(XNA and VS2008: Do’s and Don’ts)
XNA框架背后的"神话"之一是,您无法在VS2008中创建项目.如本节所示,该假设是错误的.或者至少不是完全正确.(One of the “myths” behind the XNA framework is that you cannot create a project in VS2008. As it will be shown in this section, that assumption is wrong. Or at least, not completely true.) 尽管尚未正式支持VS2008,但是您可以在该IDE中找到创建和管理XNA项目的变通方法-编辑,编译,运行和调试,因为XNA框架程序集可以像通常那样手动设置为引用.使用我们的外部组件,第三方组件和所有必需的.NET Framework程序集来编译我们的代码.(Despite the fact that VS2008 is not yet officially supported, you can find workarounds to create and manage your XNA projects in that IDE -edit, compile, run, and debug- since the XNA framework assemblies can be manually set as references, as we usually do with our external components, third-party components and all of the required .NET Framework assemblies to compile our code.) 采取这种方法将导致的损失主要有两个关键方面:首先,您将无法将游戏部署到Xbox 360,其次,使用内容管道已成问题.(What you will lose by taking this path are mainly two crucial things: first, you will not be able to deploy your games to the Xbox 360, and second, using the content pipeline is out of the question.) 第一个限制对我们而言并不重要,因为我们的代码仅针对Windows平台.但是,第二个限制呢?由于这是一个临时的解决方法,因此这里的解决方案在概念上很简单,但实际情况却变得有些复杂.(The first restriction is not important to us, since we are targeting our code for the Windows platform only. But, what about the second restriction? Since this is a temporary workaround, here is where things get a bit more complicated in practice -even though the solution is simple in concept.) 除非我们使用MSBuild来编译资产,否则我们将同时需要VS2005和VS2008.我们要做的是将内容与其余代码分开,并在VS2005和VS2008中管理前者.使用此技巧,您将能够在需要时使用VS2005来编译内容,然后允许VS2008游戏项目以二进制输出的形式使用由内容管道生成的文件.(Unless we use MSBuild to compile the assets, we will need both VS2005 and VS2008. What we will do is separate the content from the rest of the code, and manage the former in VS2005 and the latter in VS2008. With this trick, you will be able to compile the content when needed, with VS2005, and then allow your VS2008 game project to use the files generated by the content pipeline in the form of binary output.) 适当注意,没有理由手动将输出从文件夹复制到文件夹以编译和执行"整个"项目,只需创建两个相关项目(即VS2005和VS2008的项目)并让它们共享相同的项目(Take due note that there is no reason to manually copy the output from folder to folder in order to compile and execute your “whole” project, just create both related projects -that is, the VS2005 and VS2008 ones- and let them share the same)**除错(Debug)**和(and)**发布(Release)**文件夹.要更改输出路径,请打开项目的"属性",提示输入"(folders. To change the output path, open your project’s Properties, prompt for the “)建立(Build)标签,然后在适当的字段中进行更改.(” tab, and make the changes in the proper field.) 不要忘记针对"(Do not forget to target your builds for the “)x86(x86)VS2008中的平台”,否则您将收到错误消息.(" platform in VS2008, or you will get an error.) 让我们总结一下我们已经遵循的步骤:(Let us summarize the steps we have just followed:)
- 创建一个 “(Create a “)
WindowsGame
VS2008中的项目,(” project in VS2008,) - 设置对(Set a reference to the)
Microsoft.Xna.Framework
部件,(assembly,) - 设置对(Set a reference to the)
Microsoft.Xna.Framework.Game
部件,(assembly,) - 仅针对” x86"平台的任何编译,(Target any compilation for “x86” platform only,)
- 创建一个 “(Create a “)
WindowsGameLibrary
VS2005中的项目,(” project in VS2005,) - 在”(Add all the assets you will use within the “)
Content
“项目,(” project,) - 让两个项目共享相同的(Let both projects share the same)**除错(Debug)**和(and)**发布(Release)**文件夹,(folders,)
- 编译VS2005项目以生成内容的二进制文件,(Compile the VS2005 project to generate the contents' binary files,)
- 编译并运行VS2008项目/解决方案,以及(Compile and run the VS2008 project/solution, and)
- 欣赏表演吧.(Enjoy the show.) 您将在附件的zip文件中找到带有源代码的完整示例.(You will find a complete sample with source code in the attached zip file.) 在VS2008中创建游戏项目的有趣之处在于,您可以使用.NET Framework 3.5提供的所有功能.即匿名类型,lambda,LINQ to SQL,LINQ to Object等.但是,我将让您将这些作为家庭作业.(An interesting thing about creating your game projects in VS2008 is that you can use all the goodies provided by the .NET Framework 3.5; that is, anonymous types, lambdas, LINQ to SQL, LINQ to Objects, and so on. But I will let you play around with these as a homework.) 在接下来的几节中,事情变得更加有趣.相信我!(In the next couple of sections, things turn out to be more interesting. Believe me!)
WPF,现在的未来(WPF, The Future Now)
上一节是关于将XNA集成到VS2008 WinForms控件中的.(The previous section was all about integrating XNA into a VS2008 WinForms control.) 您可能已经知道这一点:Windows Presentation Foundation允许我们使用一种新的基于XML的声明性语言为我们的应用程序构建UI元素:XAML(代表”(You may probably know this already: the Windows Presentation Foundation allows us to construct UI elements for our applications by using a new declarative XML-based language: XAML (which stands for “) 可扩展应用程序标记语言(eXtensible Application Markup Language) “).(").) 现在,是否可以将XNA游戏嵌入Windows Presentation Foundation的控件中?而且,我们可以使用XAML吗?(Now, is it possible to embed an XNA game into a Windows Presentation Foundation’s control? What is more, can we use XAML?) 这两个问题的简单答案:(Simple answer for both questions:)是(Yes)!(!) 让我们首先建立一个新的解决方案,然后:(Let us start by setting up a new solution, and then:)
- 创建一个 “(Create a “)WPF应用(WPF Application)VS2008中的项目,(” project in VS2008,)
- 设置对(Set a reference to the)
Microsoft.Xna.Framework
部件,(assembly,) - 设置对(Set a reference to the)
Microsoft.Xna.Framework.Game
部件,(assembly,) - 将任何编译目标定位为”(Target any compilation for “)x86(x86)“仅限平台,(” platform only,)
- 创建一个 “(Create a “)
WindowsGameLibrary
VS2005中的项目,(project in VS2005,) - 在”(Add all the assets you will use within the “)
Content
“项目,(” project,) - 相应地配置IIS,并(Configure IIS accordingly, and)
- 让两个项目共享相同的(Let both projects share the same)**除错(Debug)**和(and)**发布(Release)**文件夹(如上一节所述).(folders (as you did in the previous section).)
现在,与上一节的示例相比,这里出现了差异.(Now, here is where differences appear in comparison with the example of the previous section.)
首先,为了将WinForms控件嵌入到WPF窗口中,必须使用(First of all, in order to embed a WinForms control into a WPF window, you must use)
WindowsFormsHost
,它将作为前者的主机.打开”(, which will serve as a host of the former. Open “)Window1
在"设计"视图中,然后按如下所示编辑XAML代码:(” in Design view, and edit the XAML code as follows:)
<Window x:Class="WindowsGame1_WPF.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wfc="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
Title="XNA & Beyond: The Path To VS2008 (Example 3)"
Height="587" Width="484" Background="SteelBlue">
<Grid Name="myGrid">
<Button Height="23" Margin="104,0,99,11" Name="button1"
VerticalAlignment="Bottom" Click="button1_Click">Press Me!</Button>
<WindowsFormsHost Margin="20,20,20,45" Name="windowsFormsHost1">
<wfc:Panel x:Name="myXnaControl" BackColor="Black" />
</WindowsFormsHost>
</Grid>
</Window>
如您在上面的代码中看到的,我们直接创建WinForms(As you can see in the code above, we are directly creating the WinForms) Panel
在XAML代码中,我们将其命名为”(within the XAML code, and we are naming it “) myXnaControl
“.(”.)
现在轮到我修改该窗口后面的代码,使其看起来像:(It is now my turn to modify the code behind this window so that it looks quite like:)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace WindowsGame1_WPF
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
Game1 game;
public Window1()
{
InitializeComponent();
this.game = new Game1(this.myXnaControl.Handle);
this.Closing += new System.ComponentModel.CancelEventHandler(Window1_Closing);
}
void Window1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if(this.game != null)
{
this.game.Exit();
}
}
private void button1_Click(object sender, RoutedEventArgs e)
{
this.Background = Brushes.Black;
this.button1.IsEnabled = false;
this.game.Run();
}
}
}
这里有什么新东西?首先,当窗口关闭时,我们退出游戏(如果您还记得以前在游戏类本身内部处理过的示例).其次,在构建游戏时,我们通过了(What is new here? First, when the window is closed, we exit the game (if you remember the previous examples that were handled from within the game class itself). Second, when we construct the game, we are passing the) Panel
的句柄作为参数.第三,在我们按下按钮之前,游戏将无法运行(您可以修改此行为,以便在需要时运行游戏).(’s handle as a parameter. Third, the game will not run until we press a button (you can modify this behavior so that the game runs when you want).)
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using SysWinForms = System.Windows.Forms;
// to avoid conflicts with namespaces
namespace WindowsGame1_WPF
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteFont Font1;
Vector2 FontPos;
IntPtr myXnaControlHandle;
public Game1(IntPtr myXnaControlHandle)
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
this.myXnaControlHandle = myXnaControlHandle;
}
/// <summary>
/// Allows the game to perform any initialization
/// it needs to before starting to run.
/// This is where it can query for any
/// required services and load any non-graphic
/// related content. Calling base.Initialize
/// will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
SysWinForms.Form gameWindowForm = (SysWinForms.Form)
SysWinForms.Form.FromHandle(this.Window.Handle);
gameWindowForm.Shown += new EventHandler(gameWindowForm_Shown);
}
void gameWindowForm_Shown(object sender, EventArgs e)
{
((SysWinForms.Form)sender).Hide();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
Font1 = Content.Load<SpriteFont>("MyFont");
// TODO: Load your game content here
FontPos = new Vector2(graphics.GraphicsDevice.Viewport.Width / 2,
graphics.GraphicsDevice.Viewport.Height / 2);
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
base.Update(gameTime);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
// Draw the current date and time
string output = DateTime.Now.ToString();
// Find the center of the string
Vector2 FontOrigin = Font1.MeasureString(output) / 2;
// Draw the string
spriteBatch.DrawString(Font1, output, FontPos, Color.LightGreen,
0, FontOrigin, 1.0f, SpriteEffects.None, 0.5f);
spriteBatch.End();
base.Draw(gameTime);
// This one will do the trick we are looking for!
this.GraphicsDevice.Present(this.myXnaControlHandle);
}
}
}
上面代码的主要变化是:(The main changes in the above code are:)
- 我们没有注意(We are not paying attention to the)
HandleDestroyed
事件了,并且(event anymore, and) - 我们正在使用参数类型初始化类(We are initializing the class with a parameter of type)
IntPtr
.(.) 猜猜上一个项目符号中所述原因是什么?避免"互操作"问题.让我提醒您,在之前的所有示例中,我们都是从相应的(Guess the reason for what is stated in the last bullet? To avoid “interop” issues. Let me remind you that in all the previous examples, we used to get the handle from the respective)Panel
呈现时的属性.我们可以通过将句柄传递给游戏的构造函数来以相同的方式实现所有这些示例,但是我想证明两者之间的区别.(’s property when rendering. We could have implemented all those examples the same way, by passing the handle to the game’s constructor, but I wanted to show the difference.) 还有什么要做吗?只需编译两个项目即可看到如下图所示:(Anything left to do? Just compile both projects to see something like the picture below:)
当您按下窗口底部的按钮时,必须发生以下情况:(And the following must happen when you press the button located at the bottom of the window:)
小菜一碟吧?现在,您可以充分利用这项新技术并享受其好处.(Piece of cake, right? Now you can take full advantage of this new technology and enjoy its benefits.)
隧道尽头的"银光”(The “Silverlight” at the End of the Tunnel)
我将来会对此进行调查.(This is something I will investigate in the future.) 原因:也许有一种方法可以使用Silverlight技术将基于XNA的应用程序嵌入并运行到网页中.非常高兴看到我们的游戏已在浏览器中加载并播放.(The reason: maybe there is a way to embed and run an XNA-based application into a webpage by using the Silverlight technology. It would be really nice to see our games loaded and played within a browser.) 但是,大声考虑一下,我认为应适用一些限制:(However, thinking loud about it, I believe that some restrictions shall apply:)
- 客户端必须安装了最新的DirectX驱动程序(因此,任何仅基于OpenGL技术的操作系统都无法运行该游戏),因此,(The client must have installed the latest DirectX drivers (so any OS based solely on OpenGL technology cannot run the game), and as a corollary,)
- 鉴于最终找到的任何解决方案仅适用于Windows,因此不应考虑Xbox 360的实现.(Given that any solution eventually found is for Windows only, an implementation for the Xbox 360 should not be considered)先验(a priori)-我害怕.(-I am afraid.)
也许,一旦Silverlight 2.0最终发布,我的第二篇文章应该着重于此调查.据我所知,该版本将允许我们使用WinForms控件.(Perhaps, my second article should focus on this investigation once Silverlight 2.0 is finally released; as far as I know, that version will allow us to consume WinForms controls.)
同时,在这方面还有另一种解决方法,我在此仅出于学习目的.(In the meantime, there is another workaround in this regard, which I hereunder present for learning purposes, only.)
在继续阅读之前,要强烈警告您(A strong word of warning before you read on)注意:绝对不要授予任何程序集(或网站)完全信任特权,因为您的计算机可能会被第三方远程拥有,因此您可以打开系统来面对安全风险.如果这样做,是因为您认为自己知道自己在做什么或出于任何其他原因,则授予该信任/特权需要您自担风险.(: you should never give any assembly (and or a website) full-trust privileges because you can open your system to face security risks since your machine could get remotely owned by third-parties. If you do, because you think you know what you are doing or for any other reason, you are granting that trust/privileges at your own risk.)
当我试图找出一种在浏览器中运行基于XNA的游戏的方法时,我记得使用(When I was trying to figure out a way to run a XNA-based game within a browser, I remembered that using the)
<Object>
HTML标记和适当的设置,我们可以将.NET程序集嵌入到网页中.像这样说:(HTML tag and the proper settings, we can embed a .NET assembly into a webpage. Like, say:)
<Object id="myControl" name="myControl"
classid="myWinControl.dll#myNameSpace.myWinControl"
width="400" height="300" VIEWASTEXT></Object>
尽管上述方法确实有效,但应满足一些条件以避免出现问题和失望:(Although the above-mentioned method does work, some conditions shall be met to avoid problems and disappointment:)
- 它只能与Internet Explorer一起使用,(It may work with Internet Explorer, only,)
- 您不能使用强名来签署程序集,(You cannot sign your assembly with a strong name,)
- 每次修改和重建对象时,都应手动清除GAC(或手动查找和删除首先缓存的DLL文件),(Every time you modify and rebuild the object, you should manually clear the GAC (or manually locate and delete the DLL file first cached),)
- 您应该授予程序集完全信任特权,(You should grant your assembly full-trust privileges,)
- 如果要构建ASP.NET网站,则不应将DLL部署到(If you are building an ASP.NET site, you should not deploy your DLL to the)**箱子(bin)**文件夹-因为后者仅用于私人访问,(folder -since the latter is for private access only,)
- 您应该将您的网站(本地主机或远程站点)添加到信任区列表中,并且(You should add your website (localhost or remote one) to the trust-zone list, and)
- 您应该祈祷并等待我们太阳系中的所有行星完全对齐.(You should pray and wait for all the planets in our Solar System to get perfectly aligned.)
整个"混乱"不是我们想要的,不是吗?因此,我研究了第二种方法,这反过来又使我进入了这篇出色的文章:(This whole “mess” is not what we want, isn’t it? So, I looked into a second approach which, in turn, drove me to this great article: “) 在Visual FoxPro中托管.NET ActiveX控件(Hosting a .NET ActiveX Control in Visual FoxPro) “.(”.)
使程序集成为COM可见的,为该领域打开了广阔的大门,因为我们将.NET程序集公开为ActiveX控件.另外,它比以前的替代方法"麻烦更少”.另一方面,如前所述,它也可能会打开安全隐患的大门,因此(Making the assembly COM-visible opens the door for great possibilities in this field since we are exposing our .NET assemblies as ActiveX controls. Plus, it works “with less trouble” than the previous alternative. On the other hand, and as said before, it could also open the door to security risks, so)弄乱计算机或任何客户端计算机的安全策略时请多加注意(be careful when you mess around with the security policies of your machine or any clients' machines).我重复,(. I repeat,)此示例仅用于学习目的(this example is for learning purposes only).(.)
好,让我们看一些代码,好吗?顺便说一句,请记住这是一个"概念证明”,其唯一目的是表明该想法可以在实践中实现.因此,以下实现在设计上很简单,因此缺少某些理想的功能和控制.(OK, let us see some code, shall we? By the way, please bear in mind that this is a “proof-of-concept”, with the sole purpose of showing that the idea can be achieved in practice. Therefore, the following implementation is simple in design, and thus, it lacks certain desirable features and controls.)
首先,使用Visual Studio(或VC Express版)创建一个WinForms项目,将其命名为”(First, create a WinForms project with Visual Studio (or VC Express edition), name it “)
XnaGame
“,然后添加(”, and then add the)Game1
我们在前面的示例中使用的文件.另外,创建一个(file we used in the previous examples. Also, create a)UserControl
,并命名为”(, and name it “)XnaPanel
“.我们将不需要任何(”. We will not be needing any)Form
控件默认情况下已创建,因此只需将其删除即可.(control created, by default, so just delete it.) 打开项目的属性,并为COM互操作注册程序集;另外,进行组装(Open the properties of the project, and register the assembly for COM interop; also, make the assembly “)COM
通过修改(” visible by modifying the)**AssemblyInfo.cs(AssemblyInfo.cs)**文件(在(file (under the)**物产(Properties)**夹):(folder):)
...
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(true)]
...
这样做后,我们的代码(Having done so, the code of our) XnaPanel
类应为以下内容:(class should be the following:)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;
using System.IO;
namespace XnaGame
{
/// <summary>
/// This is the control that will host our XNA-based game.
/// </summary>
[Guid("2CD2873E-2A50-4ac9-98CA-B13ACFCC6DFA")]
[ProgId("XnaGame.XnaPanel")]
[ComVisible(true)]
public partial class XnaPanel : UserControl
{
static string localPath;
/// <summary>
/// Main constructor of the control.
/// </summary>
public XnaPanel()
{
InitializeComponent();
this.HandleCreated += new EventHandler(XnaPanel_HandleCreated);
}
/// <summary>
/// Executes when the control's handle is created.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">An System.EventArgs object that contains event data.</param>
void XnaPanel_HandleCreated(object sender, EventArgs e)
{
// Set the path to the local Content folder
localPath =
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
localPath += @"\Temp\XnaGame\Content";
// Check whether the folder exists, locally
while(!Directory.Exists(localPath))
{
// If not just wait ...
// (you can create a timeout control, instead, to avoid
// running this check for ever!)
}
// Run the game in a new thread.
Thread gameThread = new Thread(RunGame);
gameThread.Start();
}
/// <summary>
/// Creates and executes the game.
/// </summary>
void RunGame()
{
new Game1(this.Handle, localPath).Run();
}
}
}
我们在这里所做的工作与我们之前看到的没什么不同,除了:(What we are doing here is nothing different from what we had seen before, with the exception of:)
- 内部循环(The loop inside the)
XnaPanel_HandleCreated
方法,(method,) - 游戏将在其自己的线程上运行的事实(如(The fact that the game will run on its own thread (as suggested by) 唐`克罗科(DonCroco) ),以及(), and)
- 与COM相关的属性(您必须为此类提供一个(The COM-related attributes (you must provide this class with a)
GUID
).().) 从上面的代码中可以看到,我们将等到(As you can see from the code above, we will wait until the)**内容(Content)**文件夹是在本地创建的.(folder is created locally.) 为什么?好吧,我们如何访问(Why? Well, how can we access the)**内容(Content)**服务器中的文件夹?到目前为止,如果我错了,请纠正我,我们不能.鉴于COM对象是在客户端执行的,并且内容管道当前不允许我们将Internet上的文件夹设置为游戏的内容(folder in the server? So far, and please correct me if I am wrong, we cannot. Given that the COM object is executed on the client-side and that the Content Pipeline does not currently allow us to set a folder on the Internet as our game’s)**内容(Content)**文件夹,我们必须创建(folder, we must create the)**内容(Content)**文件夹并在本地复制所有资产.(folder and copy all the assets, locally.) 谁创造的?什么时候?我们将在下面的几段中看到.(Who creates it? And when? We shall see in a couple of paragraphs below.) 为了给这个项目带来最后的感动,让我们更改游戏的构造函数,使其考虑到本地路径.(In order to give the final touches to this project, let us change the constructor of our game so that it takes into account the path to the local)**内容(Content)**文件夹并正确通知内容管道:(folder and notifies the content pipeline properly:)
...
/// <summary>
/// Main constructor of the game.
/// </summary>
/// <param name="myPanelHandle">The handle of the XnaPanel control.</param>
/// <param name="localPath">The path to the local Content folder.</param>
public Game1(IntPtr myPanelHandle, string localPath)
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = localPath;
this.myPanelHandle = myPanelHandle;
}
...
我们现在处于建设该项目的条件.首次执行此操作时,VS将通过在Windows注册表中包含以下条目来注册COM互操作程序集:(We are now in conditions of building the project. When doing so for the first time, VS will register the assembly for COM interop by including the following entries to the Windows Registry:)
[HKEY_CLASSES_ROOT\CLSID\{2CD2873E-2A50-4AC9-98CA-B13ACFCC6DFA}]
@="XnaGame.XnaPanel"
[HKEY_CLASSES_ROOT\CLSID\{2CD2873E-2A50-4AC9-98CA-B13ACFCC6DFA}\Implemented Categories]
[HKEY_CLASSES_ROOT\CLSID\{2CD2873E-2A50-4AC9-98CA-B13ACFCC6DFA}\Implemented Categories\
{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}]
[HKEY_CLASSES_ROOT\CLSID\{2CD2873E-2A50-4AC9-98CA-B13ACFCC6DFA}\InprocServer32]
@="mscoree.dll"
"ThreadingModel"="Both"
"Class"="XnaGame.XnaPanel"
"Assembly"="XnaGame, Version=1.0.0.0, Culture=neutral, PublicKeyToken=99c20c94ca29957b"
"RuntimeVersion"="v2.0.50727"
"CodeBase"="<ThePathToTheFolderWhereYourAssemblyIsLocated>/XnaGame.dll"
[HKEY_CLASSES_ROOT\CLSID\{2CD2873E-2A50-4AC9-98CA-B13ACFCC6DFA}\InprocServer32\1.0.0.0]
"Class"="XnaGame.XnaPanel"
"Assembly"="XnaGame, Version=1.0.0.0, Culture=neutral, PublicKeyToken=99c20c94ca29957b"
"RuntimeVersion"="v2.0.50727"
"CodeBase"="<ThePathToTheFolderWhereYourAssemblyIsLocated>/XnaGame.dll"
[HKEY_CLASSES_ROOT\CLSID\{2CD2873E-2A50-4AC9-98CA-B13ACFCC6DFA}\ProgId]
@="XnaGame.XnaPanel"
[HKEY_CLASSES_ROOT\XnaGame.XnaPanel]
@="XnaGame.XnaPanel"
[HKEY_CLASSES_ROOT\XnaGame.XnaPanel\CLSID]
@="{2CD2873E-2A50-4AC9-98CA-B13ACFCC6DFA}"
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{2CD2873E-2A50-4AC9-98CA-B13ACFCC6DFA}]
@="XnaGame.XnaPanel"
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\
{2CD2873E-2A50-4AC9-98CA-B13ACFCC6DFA}\Implemented Categories]
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\
{2CD2873E-2A50-4AC9-98CA-B13ACFCC6DFA}\Implemented Categories\
{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}]
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\
{2CD2873E-2A50-4AC9-98CA-B13ACFCC6DFA}\InprocServer32]
@="mscoree.dll"
"ThreadingModel"="Both"
"Class"="XnaGame.XnaPanel"
"Assembly"="XnaGame, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=99c20c94ca29957b"
"RuntimeVersion"="v2.0.50727"
"CodeBase"="<ThePathToTheFolderWhereYourAssemblyIsLocated>/XnaGame.dll"
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\
{2CD2873E-2A50-4AC9-98CA-B13ACFCC6DFA}\InprocServer32\1.0.0.0]
"Class"="XnaGame.XnaPanel"
"Assembly"="XnaGame, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=99c20c94ca29957b"
"RuntimeVersion"="v2.0.50727"
"CodeBase"="<ThePathToTheFolderWhereYourAssemblyIsLocated>/XnaGame.dll"
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{2CD2873E-2A50-4AC9-98CA-B13ACFCC6DFA}\ProgId]
@="XnaGame.XnaPanel"
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\XnaGame.XnaPanel]
@="XnaGame.XnaPanel"
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\XnaGame.XnaPanel\CLSID]
@="{2CD2873E-2A50-4AC9-98CA-B13ACFCC6DFA}"
<ThePathToTheFolderWhereYourAssemblyIsLocated>
不是实际的输出,仅是出于示例目的的虚拟占位符.相反,如果您检查注册表,则该伪路径应替换为DLL在计算机上的文件夹的真实路径(或远程(如果您将其上载到Internet上的网站)).(is not the actual output, just a dummy placeholder for example purposes. Instead, if you check your Registry, that fake path should be substituted with the real path to the folder where the DLL is located on your machine (or remotely, in case you uploaded it to your website on the Internet).)
而且,这是VS的"自动"完成,但是将项目部署到Internet时,必须提供一种注册COM对象的方法,如文章”(Also, this is “automagically” done by VS, but when you deploy your project to the Internet, you must provide a way to register the COM object, as explained by the article “) 在Visual FoxPro中托管.NET ActiveX控件(Hosting a .NET ActiveX Control in Visual FoxPro) “(请参阅(” (please refer to the sample implementation of the) RegisterClass
/(/) UnregisterClass
static
该文章中的方法).(methods in that article).)
第二项目(Second project):创建一个新的ASP.NET Web项目(使用VS或VWD Express),将其命名为”(: Create a new ASP.NET web project (with VS or VWD Express), name it “) XnaOnWebSite
“,然后添加(”, and add the)**内容(Content)**文件夹,其中包含该项目的字体文件(如前几节所述).(folder with the font file to that project (as we had seen in the previous sections).)
首先,我们如下修改内联代码:(First, we modify the code inline as follows:)
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs"
Inherits="XnaOnWebSite._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Xna-Based Game On A WebPage</title>
</head>
<body bgcolor="Black">
<form id="form1" runat="server" style="margin-top: 50px;">
<div style="text-align: center;">
<object id="myXnaGameControl" name="myXnaGameControl"
classid="clsid:2CD2873E-2A50-4ac9-98CA-B13ACFCC6DFA"
width="640" height="480" VIEWASTEXT>
</object>
</div>
</form>
</body>
</html>
请注意,不要使用(Please notice that instead of using) classid="XnaGame.dll#XnaGame.XnaPanel"
,我们正在使用该类(, we are using the class) GUI
我们提供给COM可见的类.(we provided to the COM-visible class.)
然后,我们修改后面的代码:(Then, we modify the code-behind:)
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.IO;
namespace XnaOnWebSite
{
/// <summary>
/// This class is responsible of copying all the content files
/// from the server to the local Content folder.
/// </summary>
public partial class _Default : System.Web.UI.Page
{
/// <summary>
/// Executes when the page loads.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">An System.EventArgs
/// object that contains event data.</param>
protected void Page_Load(object sender, EventArgs e)
{
// Get the physical Path of the Content folder in the server
string serverPath = Server.MapPath(@"\Content");
// Get the properties of the Content folder
DirectoryInfo serverFolder = new DirectoryInfo(serverPath);
// Check whether the folder exists on the server
if (!serverFolder.Exists)
{
throw new DirectoryNotFoundException("The Content" +
" folder is not present on the server.");
}
// Set the path to the local Content folder
string localPath = Environment.GetFolderPath(
Environment.SpecialFolder.LocalApplicationData);
localPath += @"\Temp\XnaGame\Content";
// Check whether the folder exists locally
if (Directory.Exists(localPath))
{
DirectoryInfo localFolder = new DirectoryInfo(localPath);
localFolder.Delete(true);
}
// Create the folder locally
Directory.CreateDirectory(localPath);
// Get the properties of the unique content file
FileInfo serverFile = new FileInfo(serverPath + @"\myFont.xnb");
// Check whether the file exists on the server
if (!serverFile.Exists)
{
throw new FileNotFoundException("The file 'myFont.xnb' is" +
" not present in the server's Content folder.");
}
// Copy the file to the local Content folder
serverFile.CopyTo(localPath + @"\myFont.xnb", true);
}
}
}
我猜上面的代码是不言自明的,但是基本上,我们正在做的是复制服务器的内容.(I guess the code above is self-explanatory, but basically, what we are doing is copying the content of the server’s)**内容(Content)**归档到本地(file to a local)**内容(Content)**文件.对于该示例,由于我们知道仅要复制一个文件,因此无需使用递归操作.(file. For the example, there is no need to use recursive operations since we know there is only one file to copy.) 好.在构建和执行项目时,浏览器将打开新的"本地"网站(您必须已将其添加到"受信任区域"列表中).(OK. When you build and execute the project, your browser will open the new “local” website (which you must have added to the trusted-zone list).) 您会注意到程序集仍缓存在本地计算机上(您的某个位置(You will notice that the assembly is still cached on your local machine (somewhere on you)**应用程序数据(AppData)**夹;寻找一个名为"的文件夹(folder; look for a folder named “)dl2(dl2)” 要么 “(” or “)dl3(dl3)"),并且该DLL带有一个(") and that the DLL is accompanied by one)伊尼(ini)文件,默认情况下名为”(file, by default named “)AssemblyInfo.ini(AssemblyInfo.ini)",其内容类似于以下内容:(”, which includes a content similar to this:)
X n a G a m e , 1 . 0 . 0 . 0 , , 9 9 c 2 0 c 9 4 c a 2 9 9 5 7 b
<ThePathToTheFolderWhereYourAssemblyIsLocated> / X n a G a m e . d l l
一个有趣的注意事项:首次构建COM可见程序集时,可以修改VS创建的注册表项.所以,让我们说您正在托管您的(One interesting note: You can modify the Registry entries created by VS when you first build the COM-visible assembly; so, let us say that you are hosting your)**XnaGame.dll(XnaGame.dll)**文件放在URI上的文件夹中(file in a folder on the URI “)http://yoursite.com/MyBins(http://yoursite.com/MyBins)";您可以修改注册表,使用新的路径更改"旧"路径,并在下次检查该文件时,将获得以下内容:("; you can modify the Registry, changing the “old” path with the new one, and the next time you check for that file, you will get the following:)
X n a G a m e , 1 . 0 . 0 . 0 , , 9 9 c 2 0 c 9 4 c a 2 9 9 5 7 b
h t t p : / / y o u r s i t e . c o m / M y B i n s / X n a G a m e . d l l
含义?每次您打开网站时,文件都会从该远程位置下载并缓存.(Meaning? Every time you open the website, the file will be downloaded and cached from that remote location.)
最后!好的部分:如果一切顺利,您应该会看到类似下面的屏幕截图:(At last! The nice part: if everything went OK, you should see something like the screenshot below:)
如果出现问题,请不要忘记为了运行示例代码,您必须:(If something went wrong, do not forget that in order to run the example code, you must:)
-
用强名在程序集上签名,(Sign the assembly with a strong name,)
-
注册COM对象,并(Register the COM object, and)
-
将您的网站添加到"受信任的区域"列表中.(Add your website to the Trusted-Zone list.) 根据您的浏览器的配置,COM对象可能会被阻止-因为它不能验证提供者,因为我们尚未将任何证书附加到我们的程序集中-但是,如果您执行了上述任务,那么就可以了.(Depending on your browser’s configuration, the COM object could get blocked -because it cannot verify the provider since we have not attached any certificate to our assembly- but if you did the above-mentioned tasks, you will do just fine.) 如前所述,该示例只是一个简单的基础.起点.基于此,一个有趣的想法是创建一个”(As said before, this example is just a simple base. A start point. An interesting idea based on this would be creating a “)XNA Web Player(XNA Web Player)",玩家集会与游戏本身保持分离.(”, where the player assembly remains separated from the game itself.) 一种实现方法是创建一个安装程序,将COM可见程序集保存在客户端的”(A way to implement this is by creating an installer that saves the COM-visible assembly on the client’s “)**程序文件(Program Files)**目录;并且该程序集(a)包括某种插件系统,而(b)由浏览器执行时,它:(” directory; and this assembly (a) includes, say, a sort of plug-in system and (b) when executed by the browser, it:)
-
检查是否(Checks whether the)**内容(Content)**该文件夹在本地存在(folder exists, locally,)
-
检查是否应将新文件复制到该文件夹,(Checks whether new files should be copied to that folder,)
-
复制资产的任何新版本,(Copies any new version of the assets,)
-
将游戏下载到内存或”(Downloads the game to memory or to a “)温度(temp)“文件夹,(” folder,)
-
执行游戏,显然(Executes the game, and obviously)
-
在浏览器中充当游戏的主机.(Serves as a host for the game within the browser.) 换句话说,类似于通常的” Web播放器",或者类似于安装播放器和包含游戏引擎DLL的DLL的游戏相关框架所提供的内容.(In other words, something similar to the usual “web players”, or to those offered by game-related frameworks where you install the player and the DLL containing the game-engine DLLs.) 你猜怎么了?当客户的机器上首先安装XNA GS 2可分发程序集时,它们的基本DLL已经存在于它们的机器上.唯一要处理的是您的游戏消耗的第三方DLL.(Guess what? Our basic DLLs are already present on the clients' machines when they installed XNA GS 2 distributable assemblies in the first place. The only ones to handle would be third-party DLLs your game consumes.) 然后,只需在网页中的某些位置插入以下代码即可:(Then, it would be just a matter of inserting the following code somewhere in the webpage:)
<Object id="myControl" name="myControl"
classid="clsid:2CD2873E-2A50-4ac9-98CA-B13ACFCC6DFA"
width="400" height="300" VIEWASTEXT>
<param name="Game" value="/myServerFolder/myGame.dll">
<param name="Content" value="/myServerFolder/Content/">
...
</Object>
我无法想象像这样的东西来展示我们的演示,原型等等会多么方便.而且,我想你也有这种感觉…(I cannot imagine how handy something like this would come for showing off our demos, prototypes, and so on. And, I guess you share this feeling …)
结论(Conclusion)
如本文所示,我们只需花费很少的精力,就可以并排使用XNA GS 2.0和VS2008来创建和管理Windows项目.(As demonstrated in this article, with “some little” effort, we can use XNA GS 2.0 and VS2008 side by side without problems to create and manage our Windows projects.)
提出的解决方法很简单,使我们可以利用.NET Framework 3.5中包含的所有新功能.(The workaround presented is simple, and allows us to take advantage of all the new features included in .NET Framework 3.5.)
还演示了如何通过使用来将基于XNA的游戏嵌入到网页中.(It is also demonstrated how to embed a XNA-based game into a webpage by using the) <Object>
标签和COM与.NET程序集互操作.在这方面提供的示例只是"启动",以供将来调查.(tag and COM interop with .NET assemblies. The example provided in this regard is just a “kick off” for future investigation.)
我希望您觉得这篇文章对您有所帮助-并喜欢阅读和撰写本文一样愉快.(I hope you have found this article useful - as well as enjoyed reading it as much as I have writing it.)
兴趣点(Points of Interest)
当我们等待XNA团队提供正式解决方案时,以下是一些有趣的想法供您使用:(As we wait for an official solution from the XNA team, here is a list of interesting ideas for you to play with:)
- 使用您自己的基于XNA的项目中说明的所有"技巧"(我已经能够使用XNA团队的"(Use all the “tricks” explained with your own XNA-based projects (I have been able to test all my example codes with the XNA team’s “) 净隆隆声(Net Rumble) “入门工具包,因此我只能说代码可以正常工作.)在基于XNA的项目中获得.NET 3.5中可用的大多数新功能;即使用匿名类型,LINQ,lambdas等. ,(” starter kit, so all I can say is that the code works). Get the most of the new features available in .NET 3.5 in your XNA-based projects; that is, to use anonymous types, LINQ, lambdas, and so on,)
- 使用代码为每个WinForms控件渲染一个视口-如果关卡编辑器不能同时提供游戏世界的不同视图,则没有一个关卡编辑器是好的关卡编辑器:透视图,前视图,顶视图,左视图等.(Use the code for rendering one viewport per WinForms control - no level editor is a good level editor if it cannot provide different views of the game world at the same time: perspective view, front view, top view, left view, etc.)
- 并且,当然,不要忘记实现一个不错的网格对象.(And, of course, do not forget to implement a nice grid object.)
历史(History)
这是本文的第二版.(This is the second version of the article.) 自第一个版本以来的更改:(Changes since first version:)
- 添加了显示如何将基于XNA的游戏嵌入到网页中的内容(Added content showing how to embed an XNA-based game into a webpage)
- 重大修复将示例代码更新为XNA GS 3.1和.NET Framework 3.5(感谢(Updated example code to XNA GS 3.1 and .NET Framework 3.5 with a great fix (thanks) 唐`克罗科(Don Croco) !)(!))
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
C#3.0 C# C#2.0 WinXP Win2003 .NET2.0 Visual-Studio VS2008 Dev Architect 新闻 翻译