Windows Phone 8 的 MonoGame Invasion 游戏






4.99/5 (29投票s)
本文介绍了我将《入侵》游戏从 XNA/WP7 移植到 MonoGame/WP8 的经验,并包含了《入侵》的完整源代码。

简介
《入侵》是一款开源的2D休闲射击游戏,已经存在了将近12年。2011年7月,我将《入侵》从 Windows 上的 Managed-DirectX 移植到了 Windows Phone 7 上的 XNA。最新针对 WP7 的版本在 Windows Phone 8 上运行良好,但 WP7 代码无法用 VS2012 和 WP8 SDK 构建,因为 Microsoft 不支持使用它们进行 XNA 开发。所以是时候再次移植《入侵》了,虽然我考虑过移植到 DirectX、Unity 或 Cocos2d-X,但我最终选择首先尝试 MonoGame,因为它的 API 最接近 XNA。
MonoGame 仍在开发中,在移植游戏时必须牢记这一点。一些 XNA API 缺失,另一些则有些古怪,还有一个类相当有问题。但是,如果您能解决这些问题,MonoGame 是将您的 XNA WP7 游戏移植到 WP8 以及通常构建跨平台游戏的好选择。本文解释了我如何将《入侵》移植到 MonoGame for WP8,此版本《入侵》中有什么变化,以及《入侵》和 MonoGame 中还有哪些需要改进的地方。我希望本文和源代码能帮助其他开发人员更轻松地将他们的 XNA/WP7 游戏移植到 MonoGame/WP8,并开始使用 MonoGame for Windows Phone 创建新游戏。
请记住给这篇文章评分,如果您从 Windows Phone 商店安装《入侵》,请也在那里评分和评论《入侵》 - 谢谢!
背景
2002年1月,Mauricio Ritter 在 CodeProject 上发布了他的“Invasion”UFO射击2D游戏。它最初是用 C++/DirectX 6 编写的,他为他的 CodeProject 文章将其移植到了 DirectX 7(使用 DirectDraw)。2003年,Steve Maier 将《入侵》移植到了 C# 和 Managed DirectX,这是一个托管游戏 SDK,Microsoft 在2005年取消了它。这两个《入侵》的遗留版本都运行在 Windows XP 上。
2011年,我使用 XNA 4 将《入侵》移植到 Windows Phone 7,并撰写了我的第一篇 CodeProject 文章,希望能帮助其他希望开始 Windows Phone XNA 游戏开发的开发者。自发布游戏和文章以来,《入侵》在 Windows Phone 商店已被下载超过8000次,该文章已被浏览38143次,源代码已被浏览5157次。
以下是《入侵》前三个版本的 CodeProject 文章链接
- 入侵 - 使用 DirectDraw 的电脑游戏(作者:Mauricio Ritter,2002)
- 入侵 - C#风格(作者:Steve Maier,2003)
- 入侵 - XNA for WP7(作者:Dan Colasanti,2011)
2012年,微软停止了 XNA 的开发,解散了 XNA 团队,发布了 Windows Phone 8 和 Windows 8,但没有 XNA 的路线图。开发者仍然可以使用 XNA 针对 Windows Phone 7 SDK,并在 WP8 上运行这些应用程序,但 XNA 无法使用新的 WP8 SDK API,也无法将 XNA 游戏发布到 Windows 商店。尽管 XNA 是独立游戏开发者创建 WP7 和 Xbox 360 游戏的最爱,但微软似乎正在悄然扼杀 XNA。
幸运的是,MonoGame 团队独自一人保持着 XNA 的生命力——几乎遵循了所有 XNA 的 API,并通过使其开源和跨平台来扩大其影响力。
MonoGame 可以面向 Windows Phone 8、Windows 8、iOS、Android、PS Vita 和其他操作系统!MonoGame 集成了 Visual Studio 2010/2012、MonoDevelop 3.0 和 Xamarin Studio。本文中,只讨论 Visual Studio 2012 的 MonoGame。
Using the Code
Invasion 1.8 是使用 Windows Phone 8 SDK、MonoGame 3.0.1 SDK 以及我为 MonoGame 手势处理代码打的一个小补丁创建的。您需要安装这些软件,以及 Visual Studio 2012,才能构建和运行本文随附的源代码。
要将您的游戏从 VS2010/WP7/XNA 移植到 VS2012/WP8/MonoGame,您需要保持 VS2010/WP7/XNA 开发环境完好无损,因为您将需要它来创建 MonoGame 使用的 XNB 和 WMA 格式的内容文件。下面的“MonoGame for WP8 入门”部分提供了您在开始使用 MonoGame 进行游戏开发之前应该安装的软件列表。
MonoGame for WP8 游戏开发入门
以下是我开始将《入侵》移植到 MonoGame 的步骤。所有引用的软件都已超链接到您可以下载/购买的地方(如果需要)。
- 安装 Windows 8 Pro (或 Windows 8.1 Pro)
- 安装带有最新 Service Pack 的 Visual Studio 2010、Windows Phone 7.1 SDK、Windows Phone 7.8 SDK,以及您构建当前 XNA 游戏所需的任何其他 SDK(例如 pubCenter Advertising SDK、AdDuplex 和 AdRotator)。
请注意,XNA Game Studio 4 for WP7.1 包含在 Windows Phone 7.1 SDK 中,您将需要它来为图形、音效、音乐和字体创建将在 MonoGame 项目中使用的 *.xnb* 文件。 - 安装带有最新 Service Pack 的 Visual Studio 2012、现已包含 Microsoft Advertising SDK 的 Windows Phone 8 SDK,以及 Windows Phone 8 SDK 更新。
- 从 CodePlex.com 安装适用于 Visual Studio 2010/2012 的 MonoGame 3.0.1 SDK。
- 从 CodePlex 安装 Paint.net 和 Paint.net 的 XNB 插件。这允许您编辑未压缩的 XNB 文件并将其保存为 PNG 文件,然后 XNA Game Studio 4 可以将其重新构建为 XNB 文件。
- 安装 Audacity,用于将 SoundEffects 的格式转换为 MonoGame 可以播放的格式。
- 将 MonoGame 解决方案模板和示例游戏 从 Marios Karagiannis 复制到一个新文件夹。构建并运行其中包含的跳跃怪物演示,以验证其是否正常工作。然后从示例中剥离怪物演示代码,并根据需要重命名解决方案和项目名称。
或者,您可以从第4步中随 MonoGame SDK 安装的 VS2012 模板创建新的 MonoGame 解决方案。 - 使用您的数据更新*Assembly.cs* 和 *WMAppManifest.xml* 中的字段,并更改 *App.xaml* 和 *GamePage.xaml* 文件。
- 为 MonoGame 的 TouchPanel 手势处理代码应用 我的补丁。
- 在 Visual Studio 的解决方案资源管理器中创建项目所需的任何文件夹,并将您的代码和内容文件复制到其中。
您会注意到,我上面没有推荐“去 github 克隆最新的 MonoGame 和 SharpDX 存储库”,这是有意为之的。除非您熟悉 github 和 MonoGame 并希望帮助开发 MonoGame SDK,否则我真的不建议这样做。我最初就是从那里开始的,因为这个选择浪费了很多时间。
移植笔记
本节解释了将 XNA/WP7 游戏移植到 MonoGame for WP8 所需的代码和内容更改。
游戏项目属性
在 Visual Studio 2012 (VS2012) 解决方案资源管理器面板中,右键单击游戏项目名称,打开“属性”页,然后从页面左侧的菜单中选择“应用程序”。这将允许您更改默认命名空间、程序集信息、*.xap* 文件名、启动对象和支持的区域性。请注意,如果您以后更改游戏的命名空间或类名,则需要返回此处更新启动对象。
WMAppManifest.xml 文件
WMAppManifest.xml 文件将在设计器视图中打开,因此您不再需要直接编辑 XML 代码。我通常在 VS2012 中使用深色主题(可在“工具/选项/环境/常规”中设置),但 WMAppManifest.xml 文件最好在浅色主题下查看,因为 VS2012 有一个错误,即在深色主题下无法正确显示复选框。在“应用程序 UI”选项卡中,请确保您已勾选所有三个屏幕分辨率,勾选“支持大磁贴”,并设置了应用程序磁贴图像。
请注意,“支持大磁贴”下方的文本框是“磁贴标题”名称。如果您不希望在将游戏的应用程序磁贴固定到手机的“开始”屏幕时显示磁贴标题,则清空此文本框。
如果您的游戏播放音乐,请使用“功能”选项卡设置`ID_CAP_MEDIALIB_AUDIO`和`ID_CAP_MEDIALIB_PLAYBACK`;如果它出于任何原因连接到互联网(例如显示广告、显示 Windows Phone 商店评论页面等),请设置`ID_CAP_NETWORKING`;如果它使用加速计,请设置`ID_CAP_SENSORS`;如果它启动浏览器,请设置`ID_CAP_WEBBROWSERCOMPONENT`。
使用“要求”选项卡来指示您的游戏“必需”的任何手机可选设备(例如 NFC、摄像头、陀螺仪、磁力计)。仅在这些设备确实必需时才勾选它们,因为 Windows Phone 商店将不会在没有所需硬件的手机上显示您的应用程序。
App.xaml
MonoGame 就像一个混合的 Silverlight+XNA 游戏——它使用 XAML 来承载你的 XNA 游戏。正因为如此,XNA 的 *Program.cs* 文件被 *App.xaml* 和 *App.xaml.cs* 取代,并且它还包含应用程序事件处理程序(例如应用程序激活/停用)和属性(例如禁用 `UserIdleDetectionMode`),这些是 XNA 开发人员通常在其 XNA 游戏类中找到的。如果你更改了游戏的命名空间,你需要确保 *App.xaml* 文件顶部的“`Application x:Class`”标签设置得当。
GamePage.xaml
*GamePage.xaml* 文件是一个 XAML 页面,它指定了游戏屏幕的 UI 布局和方向,以及将显示游戏的 Drawing Surface 元素。*GamePage.xaml.cs* 中相关的局部 `GamePage` 类将包含您的游戏类对象。在 *GamePage.xaml* 文件中
- 与 *App.xaml* 文件类似,确保 *GamePage.xaml* 的“`phone:PhoneApplicationPage x:Class`”标签的值为您的 `GamePage` 类指定了正确的命名空间。
- 将 `shell:SystemTray.IsVisible` 设置为“`False`”以防止系统托盘遮挡您的游戏屏幕。
- 将 `SupportedOrientations` 和 `Orientation` 元素设置为“`Portrait`”或“`Landscape`”,请注意 MonoGame 3.0 尚未支持这些字段的“`PortraitOrLandscape`”。
- 设置绘图表面(更多关于此主题的内容见下文)。
绘图表面
在 `GamePage.xaml` 的 `phone:PhoneApplicationPage` 上创建绘图表面有两种选择
绘图表面
DrawingSurfaceBackgroundGrid
为了简化这个选择,可以将它们分别视为“简单方式”和“困难方式”。通常情况下,除非有充分的理由,否则您应该总是选择简单方式。
使用`DrawingSurface`,您可以快速在绘图表面上设置缩放和转换变换,以使您的游戏适应任何屏幕尺寸,然后轻松使用现有的 WP7 XNA 游戏代码在这些屏幕上绘制并接收触摸输入,而无需重写代码或在软件中转换每个参考点。
`DrawingSurfaceBackgroundGrid` 是更困难的方式。在 `DrawingSurfaceBackgroundGrid` 上设置缩放或平移变换将不起作用(截至 MonoGame 3.0.1)。因此,您需要找到另一种方法来将屏幕缩放到其他手机分辨率,并单独将触摸点平移到其缩放的屏幕位置。可能有人有代码可以帮助您做到这一点,但这超出了本文的范围。
当我第一次开始在《入侵》移植中使用 `DrawingSurface` 时,一些使用 `DrawingSurfaceBackgroundGrid` 的开发者警告我 `DrawingSurface` 的性能不如 `DrawingSurfaceBackgroundGrid`——这是真的——`DrawingSurface` 估计慢了 5% 到 7%。但我坚持使用 `DrawingSurface`,我很高兴我这样做了,因为它对我 2.5D 的《入侵》游戏来说性能绰绰有余。即使在《入侵》的第三关,屏幕上同时有大约 30 架 UFO 旋转,飞船飞行,激光和光子发射,以及爆炸发生,`DrawingSurface` 仍然在我的设备上输出 30 帧/秒。
所以这是性能与便利性之间的权衡,除非您正在进行高强度3D渲染并需要“全速前进”的速度,否则我建议选择便利性并使用`DrawingSurface`。您可以在StackOverflow上阅读更多关于此主题的信息。
为了在《入侵》中使用 `DrawingSurface`,我用以下 `Grid` 和 `DrawingSurface` 替换了 Marios 的怪物示例中的 `DrawingSurfaceBackgroundGrid` 代码块。
<Grid x:Name="LayoutRoot">
<MediaElement/>
<DrawingSurface x:Name="XnaSurface"/>
</Grid>
WVGA 游戏自动缩放到 WXGA 和 720P 屏幕分辨率
WP7 手机屏幕具有 WVGA 屏幕分辨率 (800x480)。为 WP7 构建的 XNA 游戏在 WP8 设备上运行时,在 WVGA 手机上运行良好,并将自动缩放以填充 720P (1280x720) 和 WXGA (1280x768) 手机屏幕。将这些 WVGA 游戏移植到 MonoGame for WP8 时,我们需要自己缩放绘图表面以适应更大的屏幕尺寸。幸运的是,使用 `DrawingSurface` 做到这一点非常容易,我曾在七月撰写了一篇关于“WVGA 游戏自动缩放到 WXGA 和 720P 屏幕分辨率”的博客,并在诺基亚开发者维基上用代码片段进行了总结。使用那里提供的方法,屏幕将在 WXGA 设备上自动全屏缩放(因为 WXGA 和 WVGA 都具有 1.667 的纵横比),并缩放到 1200x720,并在居中视口的任一侧出现“黑边”信箱(这样做是为了保持 1.667 的 WVGA 纵横比,因为 720P 的纵横比为 1.778)。这种方法不仅能正确缩放屏幕图形,还能缩放和平移触摸点。简单易行!
在《入侵》游戏中,屏幕自动缩放是在 *InvasionGame.cs* 的 `InvasionGame.SetupScreenAutoScaling()` 函数中实现的。请注意,此实现存在局限性。我特意将此解决方案设计为从 WVGA “向上”自动缩放到更高分辨率——这对于将游戏从 WP7 移植到 WP8 非常有用。但是,如果您正在使用 MonoGame 创建一个新的 WP8 游戏,并希望从 WXGA 开始并向下缩放到 720P 和 WVGA,则需要调整一些代码。理想情况下,我应该编写此代码来处理向上和向下的自动缩放,如果您有兴趣这样做,请随时将您的代码发送给我,我将不胜感激地将其包含在此处并给予您完整的荣誉。
处理屏幕方向变化
XNA 默认游戏为 `Landscape` 方向,而 MonoGame 默认游戏为 `Portrait`。要创建 `Landscape` 方向的游戏,您必须
- 在 *GamePage.xaml* 中,设置这些 `phone:PhoneApplicationPage` 元素
SupportedOrientations="Landscape" Orientation="Landscape" - 处理 `GamePage.OnOrientationChanged` 事件
static internal PageOrientation PageOrientation = PageOrientation.Portrait; protected override void OnOrientationChanged(OrientationChangedEventArgs e) { PageOrientation = e.Orientation; base.OnOrientationChanged(e); }
- 使用 `GamePage.PageOrientation` 而不是 `DisplayOrientation`
由于屏幕在 `LandscapeLeft` 和 `LandscapeRight` 方向之间自动旋转,所以可能看起来游戏不需要处理 `OnOrientationChanged`,因为屏幕大小保持不变,但是《入侵》需要 `DisplayOrientation` 才能正确处理加速度计输入方向。
游戏内容
在 XNA 中,您的游戏解决方案的内容项目用于将您的内容(图形、音效、字体和音乐)构建成一个 .xnb 格式文件库,XNA 知道如何处理这些文件。因此,当您将 .png、.wav、.spritefont 和 .mp3 文件放入此内容项目时,XNA 内容管道会在构建过程中将它们转换为 .xnb 格式,然后 XNA 在运行时使用这些文件。
截至本文撰写之时,MonoGame 3.0 尚无内容管道,尽管内容管道目前正在开发中。因此,将现有 XNA 游戏的内容导入 MonoGame 项目的简单解决方法是使用 Visual Studio 2010 和 WP7 SDK 构建现有 XNA 游戏。这将生成 MonoGame 将使用的 *.xnb* 文件。对于新的 MonoGame 项目,您需要创建一个 VS2010 WP7 项目,仅仅是为了将内容构建为 *.xnb* 文件。
与 XNA 游戏解决方案不同,在 MonoGame 中,无需为游戏内容创建另一个 Visual Studio 项目。相反,创建一个名为“*Content*”的文件夹,并将您的 *.xnb* 文件放入其中。如果您愿意,可以将内容组织到子文件夹中,就像您在 XNA 中所做的那样。
播放旧版音效
当我第一次开始将《入侵》移植到 MonoGame 时,我发现它无法播放“XNA for WP7 版《入侵》”项目中的大多数 `SoundEffects`。为了让它们播放,我使用了 Audacity 重新格式化它们,并在我的文章“让旧版 DirectX 和 XNA 音效在 MonoGame for WP8 中播放”中对此进行了记录。
播放音乐
MonoGame 将播放您现有 XNA 游戏的音乐文件,但您必须以稍微不同的方式在 MonoGame 中设置音乐文件。在 XNA 中,您将 .mp3 音乐文件放在 *Content* 文件夹中,内容管道将其转换为两个文件——一个 .xnb 文件和一个 .wma 文件。在 MonoGame 中,您只需将 *Content* 文件夹中的 .mp3 文件替换为这两个文件。 .xnb 文件内部引用要加载的 .wma 文件,因此请务必同时包含这两个文件。
请注意,MonoGame 中目前存在一个 MediaPlayer 错误,即如果用户当前正在播放音乐,游戏启动时 MediaPlayer 对象未正确初始化,这会阻止游戏停止用户的音乐。Windows Phone 商店要求,如果用户在游戏开始时正在播放音乐,游戏应询问用户是否可以停止正在播放的音乐,以便让游戏播放自己的音乐。由于此错误,您的游戏可以查询用户,但当用户表示可以时,它将无法停止音乐。此错误已报告给 Github 上的 MonoGame 项目团队:https://github.com/mono/MonoGame/issues/2075[^]
MonoGame 的 MediaPlayer 错误可能导致播放背景音乐的游戏无法通过微软的认证测试,因此需要尽快解决。一种解决方法可能是在您的 WP8 游戏中使用微软真正的 `Microsoft.Xna.Framework.Media` 库。微软允许这种情况,正如这里所指出的:http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj207003(v=vs.105).aspx[^]。
振动 API 差异
MonoGame 支持 `Microsoft.Devices.VibrateController` 来使手机振动一段时间,但它没有实现 `Microsoft.Xna.Framework.Input.GamePad.SetVibration` 函数来调整振动强度。因此,虽然 XNA 版本的《入侵》在玩家的 `StarShip` 被 UFO 的光子鱼雷击中时会使手机振动,并根据 `StarShip` 护盾受损量调整振动强度,但 MonoGame 版本的《入侵》仍然会使手机振动,但强度不再基于护盾受损量。缺失的 API 已报告给 Github 上的 MonoGame 项目团队:https://github.com/mono/MonoGame/issues/2079[^]
MonoGame 的手势处理漏洞
我之所以没有在今年早些时候发布 Invasion v1.8,尽管我已经将游戏移植到 MonoGame,是因为 MonoGame 的手势处理代码中存在一个讨厌的 bug。尽管许多其他开发者告诉我他们移植的游戏运行良好,并且他们已经在 WP 商店发布了它们,但 Invasion 在 MonoGame 下表现非常糟糕——有时会
- 不允许处理任何进一步的点击或其他手势
- 游戏 UI 锁定,并且发生后无法正常重启
- 锁死 Windows Phone 操作系统,不响应重启,需要拔电池
我在调试器中见过#1和#2发生。#1很容易重现,#2发生频率较低。#3今年夏天只发生在我身上两次,幸运的是我当时使用的是 Lumia 620 作为测试设备,这让我可以轻松打开外壳并拔下电池。如果我使用的是无法打开的手机,那将不是美好的一天!我从未见过 XNA/WP7 版本的游戏发生这些问题。
那么,为什么《入侵》暴露了这个问题而其他游戏没有呢?我真的不知道,但这可能是因为《入侵》使用了点击、水平拖动、轻拂和按住手势,而其他游戏只使用了点击,或者根本没有使用手势——例如,使用原始触摸输入来处理点击。也可能是《入侵》的`ScreenManager`和输入状态管理并非实现这些功能的最佳示例——这也在一定程度上导致了问题。
我已经向 Github 上的 MonoGame 项目团队报告了这个问题:https://github.com/mono/MonoGame/issues/2076[^]
在 *TouchPanel.cs* 中还有另一个地方,混乱的 `TouchPanel` 状态导致 Tap 手势事件无法处理。我相信这只发生在也配置了其他手势的情况下,例如 `Flicks`、`Holds` 和 `HorizontalDrags`。但是由于我无法找到一个可行的补丁,我决定停止使用手势来处理游戏画面上的 Tap,而是使用原始的 Touch 输入。Invasion v1.8 不再使用 Hold 手势——现在在游戏画面上只要求 `HorizontalDrag` 和 `Flick` 手势。
MonoGame 的手势处理补丁
幸运的是,我对 MonoGame 做了一个小补丁,它显然可以防止 MonoGame 手势处理状态混乱时出现的不良行为。因此,虽然它是一个“补丁”,但不应将其视为“修复”,因为它只是对混乱状态做出响应,而不是从一开始就防止状态混乱。
补丁 1:在 *TouchPanel.cs* 中,将 `IsGestureAvailable` 更改为以下内容
public static bool IsGestureAvailable {
get {
// Process the pending gesture events.
while (_gestureEvents.Count > 0) {
int count = _gestureEvents.Count;
var stateChanged = RefreshState(true, _gestureState, _gestureEvents);
UpdateGestures(stateChanged);
//The Patch: added this if-blockto prevent infinite
//loop when gesture events don't get processed.
if (count == _gestureEvents.Count) {
TouchLocationState unprocdState = _gestureEvents[0].State;
if (_dragGestureStarted == GestureType.HorizontalDrag &&
unprocdState == TouchLocationState.Moved) {
// Letting this one go to maintain the Horizontal Drag state.
// Drags & flicks still not smooth though.
}
else
_gestureEvents.RemoveAt(0);
}
}
return GestureList.Count > 0;
}
}
没什么特别的。我发现有时手势没有被处理,如果它们留在列表中并且从未被处理,`while` 循环就会无限循环,UI 就会锁定。通过从列表中删除未被处理的项目,我们消除了循环变得无限的情况。这个补丁并不理想,但似乎有效。
补丁 2:在对 Invasion 1.8 代码应用补丁 1 后,我注意到另一位开发者推荐了一个更简单的补丁,它似乎从一开始就阻止了 MonoGame 的 TouchPanel 状态被破坏。这个新补丁在这里描述:https://github.com/nickdarnell/MonoGame/commit/84016f8c4c59d0fcf6b78d83bba6c7fa13ddc3d7[^]
补丁 1 和 2 的问题:我非常喜欢补丁 2 的想法,因此在 Invasion 1.9 源代码中用它替换了补丁 1,但您不应将这些解决方案中的任何一个视为问题的“修复”。补丁 1 试图在 TouchPanel 状态混乱后进行清理——这不是一个好策略。补丁 2 试图阻止状态混乱,但其他开发者报告称这并非在所有情况下都有效。此外,由于补丁 2 的行为与 XNA 的工作方式略有不同,MonoGame 团队仍在寻找一个不同的“更匹配 XNA”的解决方案来解决此问题,因此此问题远未解决。
其他想法:一位游戏开发者今天告诉我,补丁 2 对他的游戏不起作用,所以他打算尝试同时使用这两个补丁。但还有另一种解决方案应该进行调查,因为它解决了 WP8 上所有这些手势处理问题:在 WP8 上的 MonoGame 中使用真正的 `Microsoft.Xna.Framework.Input.Touch` 软件。微软允许这种情况,正如这里所指出的:http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj207003(v=vs.105).aspx[^]。
关注点
将游戏固定到开始屏幕而无磁贴标题
在 XNA 中,从“开始”屏幕的应用程序磁贴中删除磁贴标题相当棘手。幸运的是,对于基于 XAML 的应用程序(例如 MonoGame 应用程序),删除应用程序的磁贴标题就像清除 *WMAppManifest.xml* 文件中的磁贴标题文本框一样简单。
从 WMAppManifest.xml 获取应用程序版本号
在我的其他一些应用程序中,我从 *WMAppManifest.xml* 文件获取主菜单和关于屏幕的版本号。这消除了在 C# 中硬编码版本号的需要。Invasion v1.8 现在也在 *Invasion.cs* 的 `LoadContent` 函数中这样做,如下所示
// Get the App Version Number from the WMAppManifest.xml file
System.Version Version;
var version = System.Xml.Linq.XDocument.Load(
"WMAppManifest.xml").Root.Element("App").Attribute("Version");
if (version != null && !string.IsNullOrEmpty(version.Value))
Version.TryParse(version.Value, out Version);
else
Version = new Version("0.0.0.0"); //Something went wrong!
显示“请求评论”消息框
在 MonoGame 中,`Guide.BeginShowMessageBox` 仍然可以用于显示消息框,但是使用 MonoGame,您也可以像任何基于 XAML 的应用程序一样使用 `System.Windows.MessageBox.Show` 来显示消息框。在带有 MonoGame 的 Invasion 应用程序中,我以两种方式实现了消息框,以便向您展示它们在调用方式和功能上的区别。
我喜欢 `Guide.BeginShowMessageBox` 的一点是,您可以指定按钮上的文本,因此您的按钮不再局限于“确定”和“取消”,而是可以显示“是”和“否”,或者“立即购买!”。您也不必担心在调用它时出现跨线程 UI 异常。
`System.Windows.MessageBox.Show` 在调用时需要填写的参数较少,如果您只需要弹出一个简单的“确定”消息框,这是个好消息。但它确实将您限制在“确定”或“确定/取消”按钮,并且要求您使用 `Deployment.Current.Dispatcher.BeginInvoke` 调用它,否则会抛出跨线程 UI 异常。例如
Deployment.Current.Dispatcher.BeginInvoke(() => {
MessageBox.Show(
"Thanks for trying to Rate & Review Invasion, but your phone doesn't currently have " +
"an Internet connection. Please try again when your phone is online.",
"No Internet Connection", MessageBoxButton.OK);
});
加速度计输入
我有一段时间没看加速度计代码了,但我知道模拟器的加速度计输入对玩家的飞船没有影响——这不应该!幸运的是,当《入侵》在设备上运行时,加速度计输入运行良好。
持久设置
Invasion v1.8 是第一个在运行之间持久保存游戏设置(计分板位置、游戏音乐、难度级别和自动选择武器)的版本。因此,如果您喜欢计分板在屏幕左侧,或者喜欢关闭音乐,Invasion 现在会记住这些设置。使用 `System.IO.IsolatedStorage` 命名空间中的 `IsolatedStorageSettings.ApplicationSettings` 轻松管理此类游戏设置。请在 *Settings.cs* 文件中查找实现。
处理未处理异常
在 XNA for WP7 中,理论上你可以处理“未处理异常”,有时它确实有效。有时 XNA 游戏在你有机会设置处理程序之前就会崩溃,但即使它有效,你的游戏也总是会被终止。对于 WP8 上基于 XAML 的应用程序,我注意到当 `App.Current.UnhandledException` 被处理时,应用程序会保持运行。
构建你的游戏
在 VS2010 中构建和调试 XNA 游戏非常容易。您可以选择构建发布版还是调试版,以及目标是模拟器还是设备,当您按下 F5 时,一切都正常工作。模拟器代码目标是 x86,设备代码目标是 ARM——这是当然的。
不幸的是,目前 MonoGame 并非如此。由于 MonoGame 使用的库 (SharpDX) 存在构建问题,因此不会自动选择目标处理器——因此您需要在构建的配置管理器中每次在设备和模拟器之间切换时选择 ARM 或 x86。由于 VS2012 中的一个小 bug,您应该在选择目标设备/模拟器之前更改配置管理器中的目标处理器,因为 VS2012 会在目标处理器更改时重置该字段。
调试
调试在模拟器中运行良好,但在设备上(连接调试器)调试 MonoGame 应用程序通常会降低性能,直到游戏变得无法使用。当这种情况发生时,会很明显——帧率会降至每秒 1 或 2 帧,并且触摸输入会很多秒甚至完全不处理。一些开发者表示,通过停用游戏(通过 Windows 按钮)并重新进入游戏(通过返回按钮),可以消除这种行为,但这对我不起作用。
关于 MonoGame 的思考
MonoGame 3.0.1 具备功能,但仍在开发中,还有很多工作要做。MonoGame 团队欣然承认他们需要一些帮助——所以如果您有时间、知识和意愿,请从 Github 下载最新的 MonoGame 位并与他们联系。但是,如果您不打算帮助开发 MonoGame,那么我建议远离 MonoGame 和 SharpDX 存储库,而是按照本文中建议的步骤进行。
虽然 MonoGame 3.0.1 的大部分功能似乎非常稳定,但我对 MonoGame 的 TouchPanel 类的实现和稳定性存在严重担忧。我为了防止 UI 锁定而使用的笨拙补丁恰恰表明这个类应该完全重写。这个特殊的类不具备“版本 3”的质量——充其量也就是 Beta 版的质量。正确地重新实现 `TouchPanel` 类将不是一项简单的任务,而且做到这一点极其重要。
我相信 MonoGame 最终会成功并持久,但 SDK 的进展似乎比我预期的要慢。3.0 Beta 版于 2012 年 10 月发布(一年前!),而最新的 3.0.1 稳定版是 7 个月前发布的。我原本期待现在能有一个新的稳定版,但没人真正知道它何时到来。在我看来,这似乎是一个资源问题——资金或 SDK 开发人员不足以使其加速发展。
在过去的7个月里,微软帮助Unity和Cocos2d-x SDK适用于Windows 8和Windows Phone——这是一个将iOS和Android开发者引入微软移动应用平台的伟大策略。
微软也可以通过从 XNA 中移除任何专有代码,并将其余部分在 CodePlex 上以 MS-PL 许可开源,从而帮助 MonoGame 以闪电般的速度发展。MonoGame 可以快速实现一个防弹的 `TouchPanel` 类,功能齐全的内容管道,以及其他仍需要的东西。XNA 开发人员将再次赞美微软!那么,微软,意下如何?
展望未来,MonoGame 的跨平台目标有可能使 XNA 比在微软的“仅限微软”方法下更具影响力。这对于游戏开发者来说非常重要,他们更希望一次性制作游戏,并能将其发布到所有流行的平台。
Invasion v1.8 中的游戏更改
Invasion 1.8 不仅仅是 XNA Windows Phone 7.1 版本的直接移植。趁此机会,我做了一些改动
- “选项”现在称为“设置”,并保存在独立存储中
- 设置屏幕现在有一个屏幕上的“返回”按钮
- 设置屏幕现在允许在游戏过程中移动计分板位置
- 点击游戏屏幕上新的设置图标可导航到设置屏幕
- 在游戏过程中按住计分板不再导航到设置屏幕——那是个糟糕的主意(抱歉!)
- 玩家击落UFO可获得更多分数!
- 添加了“评分与评论”消息框(迟早,我们都需要一个)
- 主菜单现在包括“评分 + 评论”而不是“退出”
- 用简单文件夹替换了大部分入侵解决方案的项目
- 在 *WMAppManifest.xml* 中添加了所有 3 种尺寸的应用程序磁贴(提交游戏到 DVLUP 所需)
- 使红色UFO波次更具挑战性。
- 添加了摇晃动画以表示 UFO 损坏。
- Bug 修复:横向右屏幕方向下加速度计输入颠倒
- Bug 修复:关卡转换屏幕上的返回按钮应打开暂停屏幕
- Bug 修复:即使禁用音乐管理器,音乐也会播放
- Bug 修复:许多 Update & Draw 调用发生两次,降低了性能。
- Bug 修复:红色 UFO 离开屏幕左侧时加速。
未来入侵游戏改进
以下是《入侵》可以改进的一些方面。如果您愿意提供帮助,请告诉我。
- 更好的屏幕管理器代码
- 高分(本地和/或全球)
- 保存游戏并稍后加载的能力
- 模拟器的加速度计输入
- 基于形状的碰撞检测
- 增加 UFO 人工智能和更多攻击策略
- 当 MonoGame 有内容管道时使用内容管道
- 让飞船也能上下移动
- 创建更高分辨率的 UFO、飞船和爆炸效果
- 用视差星空替换静态背景图像
- 添加更多武器、奖励道具和 UFO 类型
- 支持国际化的字体
文章历史
- 1.0 (2013年10月8日) - 从 XNA/WP7 到 MonoGame/WP8 的首次移植 (Invasion v1.8)
- 1.1 (2013年10月14日) - 许多 bug 修复,清理了更多代码并改进了变量名,使中等和困难难度级别的红色 UFO 波次更具挑战性,在第2波及以上添加了摇摆动画以表示受损的 UFO。游戏代码更新到 v1.9。