Windows Phone:您准备好游戏了吗?第一部分






4.77/5 (18投票s)
Windows Phone 的 XNA 游戏开发入门 - 包括 XNAImage,XNA 的图像处理
引言
随着 Windows Phone 7.5 的发布,新的 Microsoft 手机操作系统开始受到积极关注。因此,是时候仔细研究一下该平台的开发了。
Windows Phone 操作系统有两种用户界面开发编程模型:Silverlight 和 XNA。
Silverlight 是 .NET Framework 功能较弱的“兄弟”,为企业业务应用程序开发提供了相对高效的生态系统。Silverlight 包含广泛的用户界面控件,并且第三方控件的市场正在不断增长,这使我们能够快速设计出我们希望为企业业务应用程序提供的那种用户界面。如果您要为 Windows Phone 7.5 创建 Silverlight 应用程序,请从 http://silverlight.codeplex.com/ 下载“Silverlight for Windows Phone Toolkit”。
另一方面,XNA 允许我们编写使用 DirectX 9 加速图形输出的代码。视频播放和图形渲染等任务从 CPU 转移到 GPU,从而释放 CPU 来处理其他事情。

在为 Windows Phone 的初始版本进行开发时,我们必须在 Silverlight 和 XNA 之间做出选择并坚持使用该模型。在 Windows Phone 7.5 上,Silverlight 应用程序可以嵌入 XNA 模型,XNA 应用程序可以嵌入 Silverlight 用户界面元素——这是一个巨大的改进。
我假设您熟悉 Visual Studio 2010、.NET 和 C#。您还需要安装 Windows Phone 软件开发工具包 (SDK) 7.1,它提供了为 Windows Phone 7.0 和 Windows Phone 7.5 设备开发软件所需的工具。SDK 包括 XNA Game Studio 4.0 Refresh,因此无需单独安装。
游戏的构成
在为 Windows Phone 上的 XNA 进行开发时,我们是在一个框架内工作的,因此掌握基础知识至关重要。
XNA Game Studio 4.0 在 Visual Studio 中添加了许多项目模板,我们将使用的是名为“Windows Phone Game (4.0)”的模板,位于 Visual C# -> XNA Game Studio 4.0 下。我将项目命名为“AnatomyOfAGame
”,并将生成的“Game1
”类重命名为“GameSkeleton
”。
我们确实需要理解生成的代码,因为框架就是这样期望我们的游戏工作的。
public class GameSkeleton : Microsoft.Xna.Framework.Game
{
XNA Framework 的“Game
”类实现了游戏循环;它提供了显示我们游戏的窗口——“Game
”还包含许多虚拟方法,可实现我们游戏与 XNA Framework 之间的通信。
GraphicsDeviceManager graphics;
“GraphicsDeviceManager
”提供了允许我们处理图形设备的配置和管理的功能。
SpriteBatch spriteBatch;
“SpriteBatch
”允许我们以纹理的形式绘制精灵。精灵是直接绘制到渲染目标上的位图,绕过了变换、光照或效果的管道。仅使用精灵就可以创建相当不错的游戏。
生成的构造函数非常简单。
public GameSkeleton()
{
graphics = new GraphicsDeviceManager(this);
第一步是为该游戏创建“GraphicsDeviceManager
”,接下来我们需要告诉“ContentManager
”它应该在哪里查找内容。
Content.RootDirectory = "Content";
“Content
”属性提供对“ContentManager
”的访问权限,“ContentManager
”是负责从“AnatomyOfAGameContent
”内容项目中的二进制文件加载托管对象的运行时组件。
内容是在设计时生成的,通常是游戏的所有非代码部分;例如位图、模型和音效。通过内容管道将内容添加到项目中,之所以称为内容管道,是因为它是一套在游戏构建时应用于游戏美术和其他数据资产的进程。“RootDirectory
”告诉“ContentManager
”它应该在哪里查找这些资源。
// Frame rate is 30 fps by default for Windows Phone.
TargetElapsedTime = TimeSpan.FromTicks(333333);
“TargetElapsedTime
”指定了固定帧率游戏的帧循环的目标时间间隔。在固定帧率游戏中,“Update
”会根据“TargetElapsedTime
”定期调用,并且在“Update
”完成后,游戏会检查是否到了再次调用“Update
”的时间,然后再调用“Draw
”。在“Draw
”完成后,游戏会处于空闲状态,直到再次调用 Update
。
// Extend battery life under lock.
InactiveSleepTime = TimeSpan.FromSeconds(1);
}
“InactiveSleepTime
”指定了游戏不活跃时进入休眠的时间。
protected override void Initialize()
{
base.Initialize();
}
“Initialize
”是我们应该查询任何必需服务并加载非图形资源的地方。调用基类的“Initialize
”很重要,因为这可以确保对添加到游戏“Components
”集合中的任何游戏组件调用“Initialize
”。“Initialize
”在游戏进入“Update
”/”Draw
”循环之前被调用。
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
}
“LoadContent
”由“Initialize
”调用,并在需要重新加载游戏内容的其他时间调用,例如当“DeviceReset
”事件发生时。
protected override void UnloadContent()
{
}
“UnloadContent
”在需要卸载图形资源时被调用,并且是我们应该卸载任何游戏特定图形资源的地方。
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
{
this.Exit();
}
base.Update(gameTime);
}
“Update
”是所有精彩发生的地方,我们在这里移动事物、检查碰撞,让手机发出声音和震动。简而言之:在这里处理游戏逻辑。
参数“gameTime
”通过三个属性为我们提供了时间信息。
public TimeSpan ElapsedGameTime { get; }
自上次更新以来经过的游戏时间。
public bool IsRunningSlowly { get; }
“IsRunningSlowly
”表示游戏循环是否花费的时间超过了其 TargetElapsedTime
。在这种情况下,我们的游戏应该赶上延迟,这可以提供更流畅的游戏体验。
public TimeSpan TotalGameTime { get; }
TotalGameTime
指定了自游戏开始以来的游戏时间。
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.DarkKhaki);
// TODO: Add your drawing code here
base.Draw(gameTime);
}
}
“Draw
”在需要绘制帧时由 XNA 框架调用。通过调用基类的“Draw
”方法,我们确保可绘制的游戏组件也会被绘制。

我们现在创建了一个不会做太多事情的东西,但至少我们现在对事情的运作方式有了初步的了解。
Farseer Physics XNA WP7
在继续之前,我想介绍 Farseer Physics 引擎,您可以从 http://farseerphysics.codeplex.com/ 下载。Farseer Physics 引擎是一个开源的 .NET 2D 物理引擎,可用于商业项目——这非常好。
本文的解决方案包含原始的、几乎未经修改的 Farseer Physics Engine 3.3.1 for Windows Phone 项目。我唯一做的更改是升级项目到 Windows Phone 软件开发工具包 (SDK) 7.1。顺便说一句,这是通过在项目菜单上点击“Upgrade Windows Phone Project”项实现的。
现在我们有了物理引擎,让我们的游戏做一些有趣的事情就容易多了。
XNAImage – XNA Framework 的图像处理
当您开始玩 XNA 框架和 Farseer Physics 时,很快就会发现能够在运行时创建精灵是很棒的。HarlinnXNA
项目包含一个名为“XNAImage
”的类,它将帮助我们即时创建图像。

这个类允许我们绘制线条、圆形、样条曲线、贝塞尔曲线以及许多其他在渲染游戏形状时很有用的东西——而 Farseer Physics 库非常侧重于形状。我将在下一篇关于 XNA for Windows Mobile 的文章中开始研究该类及其如何与 Farseer Physics 库一起使用。
XNAImage 更新 - 11 月 11 日

XNAImageIntro
项目演示了如何使用 XNAImage
在运行时渲染图像。XNAImage
基于 WriteableBitmapEx 项目,并支持 WriteableBitmapEx
的所有图像处理功能。这意味着我们可以使用该库在运行时创建纹理,然后将生成的图像分配给纹理。
texture = new Texture2D(GraphicsDevice,
rect.Width, rect.Height, false, SurfaceFormat.Color);
textureImage = new XNAImage(rect.Width, rect.Height, Color.CornflowerBlue);
当我们在创建 Texture2D
对象并希望将其与 XNAImage
一起使用时,我们必须指定 SurfaceFormat.Color
格式,以便纹理的像素格式与 XNAImage
的像素格式匹配。
现在我们已经创建了 XNAImage
对象,我们可以开始直接绘制到图像中。
Color color = Color.Green;
textureImage.FillEllipseCentered(480/3, 275, 75, 75, color);
color = Color.Blue;
textureImage.FillEllipseCentered(480*2/3, 275, 75, 75, color);
我们可以创建另一个图像,并用 珀林噪声 填充它。
XNAImage noisyImage = new XNAImage(200, 200);
noisyImage.PerlinNoise(1.2, 0.025, 0.9, 3, 5);
珀林噪声在我们要创建火焰、烟雾和云彩等各种效果时很有用。然后可以像这样将图像 blit 到目标图像。
textureImage.Blit(new Rectangle(140, 400, 200, 100),
noisyImage, new Rectangle(0, 0, 200, 100),BlendMode.Subtractive);
textureImage.Blit(new Rectangle(140, 500, 200, 100),
noisyImage, new Rectangle(0, 100, 200, 100));
第一次 blit 操作使用减法混合混合源图像和目标图像,而第二次只是覆盖目标矩形。完成图像后,我们将其分配给 Texture2D
对象。
texture.Assign(textureImage);
XNAImage
是“正在进行中的工作”,但它提供了许多对游戏 UI 开发非常有用的功能。
Blit
FillRectangle
FillEllipse
FillEllipseCentered
FillPolygon
FillQuad
FillTriangle
FillBeziers
FillCurve
FillCurveClosed
Convolute - 应用图像滤镜
PerlinNoise
DrawLineBresenham
DrawLineDDA
DrawLine
DrawLineAa
DrawPolyline
DrawTriangle
DrawQuad
DrawRectangle
DrawEllipse
DrawEllipseCentered
DrawBezier
DrawBeziers
DrawCurveSegment
DrawCurve
DrawCurveClosed
裁剪
调整大小
旋转
RotateFree
Flip
最终,XNAImage
将使我们能够创建像本文开头那样的图像;如果兴趣足够,它将在此处与 CodeProject 上的开发社区分享。虽然 WriteableBitmapEx
库提供了不错的功能集,但 XNAImage
在拥有合理的 API 之前还有很长的路要走。
Game Studio 4.0 更改了 Color 类型
根据 SurfaceFormat 文档,Texture2D
类使用 32 位 ARGB 像素格式(带 Alpha),当它以 SurfaceFormat.Color
格式创建时,每通道使用 8 位。
事实证明,Microsoft 忘记更新文档了,因为 Game Studio 4.0 将 Color 类型从 BGRA 更改为 RGBA 字节序。大多数游戏都不会注意到此更改,因为我们不仅更新了 Color 结构,还更改了纹理和顶点声明创建代码以匹配。如果您有直接创建 Color 格式纹理的代码,从字节数组而不是强类型 Color[] 设置其内容,您需要交换红色和蓝色通道的顺序。
XNAImage
的内部工作最初假设我们处理的是 ARGB 格式的像素,所以这有点出乎意料——截至 11 月 11 日,这大部分已经修复。
历史
- 2011 年 11 月 8 日 - 初次发布
- 2011 年 11 月 9 日 -
XNAImage
错误警告 - 2011 年 11 月 11 日 -
XNAImage
已更新 - 2011 年 11 月 12 日 - 做了一些更改