将放置

游戏在 Zune Of 程序密钥

Mike Calligaro

内容

C That Is Sharp man,
Anatomy of 游戏
Pixie 灰尘上的子画面
固定资产的名称和颜色键
ya Gotta 移动到播放
框中的子画面
Bing 感叹号吊臂
高级绘图
其余由上到您

我因为他是三个的被播放 Xbox 的儿子已开始显示编程中的兴趣特别编写游戏。此提示我要下载 XNA 游戏 Studio,并深入它自己,您知道,以便我可以教他。我已经总是想要编写自己的游戏有与之无关。确实。

XNA 游戏 Studio 3.0 添加能够为这意味着在 Zune 现在是一个移动的开发平台的 Zune 编写游戏。因此公平,er,游戏的将放置项目。如果您已经是一个 XNA 开发人员,我可能会查看您已了解的一些概念。但如果您是我一样,属于 enthusiastic 有关但非常熟悉游戏开发,程序员阅读。

C That Is Sharp man,

在 Microsoft 我十五年职业大部分,我一直在系统和驱动程序开发人员。我选择和需要的语言已被一个相当 bare bones C++。我很少收到使用 MFC 和 Microsoft.NET Framework 运行库。为止,我无法甚至拼写 STL 得进行的利用。

这是我一天的工作。但我关闭时,我喜欢使用 C# 播放周围。通常,我编写小应用程序为我的 Windows Mobile 的设备和有时我的 PC。C++ 不会将我不存在很多本机的开发人员,但我仍然得到有点 giddy 我编写 C# 中时。您可以获取大量使用非常几行代码。我 swear,C# 是因此更有趣它们应使其 controlled 实体。

在娱乐类别 XNA 游戏 Studio 在 steroids 上是如 C#。通过有团队已经完成了使游戏开发简单的一个惊人的作业。Framework 是简单、 硬盘的内容很大程度上处理的和它们已发布的示例旨在讲授游戏开发在各个方面的大量。

开始 Creators.xna.com。从此处可以下载免费 XNA 游戏 Studio 3.0。如果您已使用 Visual Studio 2008 的各种的认知之一,XNA 游戏 Studio 将与其集成。如果您没有 Visual Studio 2008,不要烦恼。XNA 游戏 Studio 还使用免费 Visual C# Express Edition。(换句话说,尽管我提到 Visual Studio 时,可以替换 Visual C# 速成版如果您使用的内容)。

该 Creators.xna.com 的网站也已充满了信息可以帮助您将。单击查找初学者的参考线示例,页面顶部的教育链接以及-到的。在"初学者的指南到二维游戏"是尤其是好是使用 XNA 游戏 Studio 安装的文档。在某些情况下,安装文档,请拥有并不在网站上的信息。在 Visual Studio,您地通过选择帮助找到该文档 | 内容,并将该筛选器设置为 XNA 游戏 Studio 3.0。

XNA 游戏 Studio,可以编写一个代码库并部署到 Xbox、 PC 和 Zune。所有我此处将适用于所有三个平台。免费下载您需要开发用于 PC 或 Zune,但 Xbox 开发要求成本每年的费用的高级成员身份。

Anatomy of 游戏

一旦您已获得 XNA 游戏安装 Studio 3.0,可以创建一个 Hello World 游戏 Zune 选择文件 | 新建 | 项目。然后选择 Visual C# | XNA 游戏 Studio 3.0 和单击 Zune 游戏 (3.0)。尽管这会生成该程序实际上不会说 Hello World,它不会监视输入、 绘制背景蓝色,并根据退出。

如果您希望一些非常复杂,处于愉快的意外的。大约 20 个行代码将整个游戏的基础结构金额分配超过六个函数。下面是这些函数的说明。

构造函数是只是一个标准,园各种 C# 对象构造函数。将它处理相同像其他任一。

在构造函数完毕之后,将调用 Initialize。它允许您执行进一步初始化,特别是对于涉及图形系统的操作。

LoadContent 初始化后调用,并为您加载您的图像和声音。

UnloadContent 游戏退出上调用,并可以卸载您的内容。但是,因为卸载大多数图像和声音处理为您,您通常不需要执行以下任何操作。

更新可能是游戏开发的最不同于普通应用程序开发的位置。而不是一个消息循环游戏定期轮询其输入,计算如何与其,然后绘制这些计算的结果。更新中的大部分的发生,因此这是将在 Live 大部分代码。

绘制每个更新后调用,并且是在绘制图像。

就是这样。即使程序是非常短,它启动、 绘制屏幕蓝色、 读取输入,命中上一步按钮时退出。什么?您认为游戏开发将很难?不能与 XNA 游戏 Studio。

Pixie 灰尘上的子画面

简单,但退出的蓝色背景不会使吸引人的游戏的。如果您要有一个的游戏,则需要实际的图像。令人欣慰的是,放在屏幕的图片不难。

稍后我将向您展示该的代码,但首先您需要的图像加载到您的项目。在 Visual Studio 中, 您应该称为解决方案资源管理器窗口 (如果未这样做,可以找到它在视图菜单下)。在解决方案资源管理器右键单击内容,然后选择添加 | 现有项。从此处您可以在任何.bmp、.jpg、.png、.tga 或.dds 图像文件指向它。

让我们假设您有名为 Player.jpg 和只是其添加到内容的人员的图片。图 1 显示了代码以在屏幕上显示的图像。

图 1 显示图像

// Add these member variables
Texture2D texture;
Vector2 position;

// Add this line to the constructor
position = new Vector2(100, 100);

// Add this line to LoadContent()
texture = Content.Load<Texture2D>("player");

// And add these lines to Draw();
spriteBatch.Begin();
spriteBatch.Draw(texture, position, Color.White);
// (Draw the rest of your sprites)
spriteBatch.End();

我将介绍这些行之前,让我们讨论术语。 XNA 游戏 Studio 启动作为 Xbox 的开发系统。 在这种情况下,它的所有基于三维图形。 二维游戏 (,因为在 Zune 不具有三维呈现器,您需要执行二维游戏) 是真正的三维游戏 (其中所有内容是真正细。 因此您将看到 sprinkled 在代码周围的三维条款。 对于是实例 sprite 处于普通术语二维游戏中的图像时, Word 纹理来自三维游戏。 如 far 而言 XNA 游戏 Studio,sprite 是与映射到它们的纹理的真正细三维矩形。

该 content.load 函数采用一个资产为名称即默认情况下不带扩展名的文件名。 我加载图像调用 Player.jpg 后, 我传递字符串"播放机"给 content.load。 在 LoadContent 函数中可以找到的已分配一个 SpriteBatch 的行。 所有绘制都是都完成此 SpriteBatch 的。 在绘图函数中您告诉该 SpriteBatch 您将要开始绘制所有 sprite,然后告诉它您已完成。

位置成员变量是向量结构包含 x 和 y 位置绘制 sprite。 下例所我使用像素的位置 (100,100)。 该颜色是可以将添加到您的子画面的淡色。 使用白色保留不变的图像。

因此,获取在屏幕上的一个图像,您只需要加载纹理,并告诉绘制子画面批处理。 第一个映像基本上四行代码,并每个后续的一个将两个的更多。

固定资产的名称和颜色键

希望,此时您要在屏幕上查看您的播放机映像并认为这不那么难。 但也许不完全满意。 如果您不喜欢您的代码需要使用图像的文件名? 更是重要,如果您加载的图片矩形,但播放机不? 您如何可以绘制只是播放机和不背景?

要回答这两个这些问题,需要查看为您加载该图像属性。 请返回到解决方案资源管理器,并右键单击该文件 (在我示例 Player.jpg)。 选择属性。 属性窗格会下面为您提供大量有用的信息解决方案资源管理器。 第一次查看固定资产的名称。 这是传递给 content.load 的名称。 如果需要,使得以外的文件名称,请此处更改它。

现在即可在少 + 名称的左侧,请展开内容的处理器。 您所关注此属性是颜色主要颜色。 其颜色与颜色键匹配的任何像素将是透明的。 这是如何使一个矩形图像并退出在后台清除。 因此,要去掉 sprite 的背景,更改其颜色或更改该颜色键设置,以便它们匹配。 设置默认为红色、 绿色、 蓝色,以及 Alpha 值 255、 0、 255、 255,这是洋红色。

ya Gotta 移动到播放

当然在蓝色背景上的一个子画面不会在游戏中的大接下来。 至少,需要用户能够以某种方式移动的 sprite。 这样做,您需要知道用户执行。 如果在程序中已经探讨更新功能,您可能已经了解如何执行此操作。 默认代码读取输入,并退出,如果按下后退键。 遗憾的是,他们的独占有输入。 让我们来更改一段周围的点允许您使用输入也。

以下是当前看到的内容:

if (GamePad.GetState(PlayerIndex.One).Buttons.Back == 
    ButtonState.Pressed)
    this.Exit();

我建议更改如下所示:

GamePadState input = 
    GamePad.GetState(PlayerIndex.One);
if (input.Buttons.Back == ButtonState.Pressed)
    this.Exit();

现在可以使用输入的变量查看用户输入。请注意输入是一个 GamePadState。在 Zune 输入视为一个 Xbox gamepad 的缺少某些按钮的。图 2 提供了 Zune 的按钮的映射,完整列表。

图 2 Zune 按钮映射
按钮 映射
备份 GamePadState.Buttons.Back
播放/暂停 GamePadState.Buttons.B
DPad 中心 GamePadState.Buttons.A
DPad 边缘 GamePadState.DPad
在 ZunePad 上滑动 GamePadState.Thumbsticks.Left
单击该 ZunePad GamePadState.Buttons.LeftShoulder

好,因此让我们使播放机移动。图 3 中的代码包括 DPad 和 ZunePad 输入,因此它可用于任何 Zune。(原始 Zunes 未有 ZunePad 功能)。

图 3 支持移动

// add these lines to Update()
const int c_speedScalar = 100;
Vector2 speed = Vector2.Zero;

speed.X = input.ThumbSticks.Left.X * c_speedScalar;
speed.Y = input.ThumbSticks.Left.Y * c_speedScalar * -1;

if (input.DPad.Left == ButtonState.Pressed)
    speed.X -= c_speedScalar;
else if (input.DPad.Right == ButtonState.Pressed)
    speed.Y += c_speedScalar;

if (input.DPad.Up == ButtonState.Pressed)
    speed.Y -= c_speedScalar;
else if (input.DPad.Down == ButtonState.Pressed)
    speed.Y += c_speedScalar;

position += speed * (float)gameTime.ElapsedGameTime.TotalSeconds;

请记住该绘图例程在绘制在位置成员变量指定的位置播放机。 因此,移动 sprite,您需要为是更新的位置。

非常有趣的部分是最后一行更改位置的位置。 Xbox 有比在的 Zune 更强的图形功能,因此更频繁地调用其更新例程。 换句话说,它具有更高版本的 framerate。 这意味着您需要将独立于该 framerate 的移动。 要完成此,使用输入计算一个的速度不位置。 然后转换为一个位置速度乘以自上次调用更新经过的时间量。

框中的子画面

任何人都可以移动。 技巧知道何时停止。

如果游戏是有趣,则需要知道与另一个子画面的冲突时。 对此的复杂的游戏开发人员术语有冲突检测,最简单的方法执行 XNA 游戏 Studio 中的冲突检测使用名为一个 BoundingBox 对象。 基本,您环绕对象的不可见的框,然后查看是否任何这些框相交相互。

除了当前游戏在小于令人兴奋,最大问题是 sprite 可以移动出了屏幕。 让我们解决的。 只要 sprite 点击边缘,我们将使跳回到 (100,100) 的位置。

首先,您需要一个边界框屏幕:

// Add this member variable
BoundingBox bbScreen;

// Add these lines to Initialize() 
Vector3 min = new Vector3(0, 0, 0);
Vector3 max = new Vector3(graphics.GraphicsDevice.Viewport.Width,
    graphics.GraphicsDevice.Viewport.Height, 0);
bbScreen = new BoundingBox(min, max);

有是一个的神奇功能此处,但这并不非常复杂神奇功能。 Hello World 框架提供成员变量名为包含宽度和高度游戏的屏幕的图形。 您可以设置屏幕的边界框左上角于在左上角和右下边界框在屏幕右下角。 BoundingBoxes 要求三维矢量,因此将 Z 坐标设置为 0。

现在让我们创建该的 sprite 的框如下:

// Add these lines to Update() after 
// the position has been calculated.
Vector3 min = 
    new Vector3((int)position.X, (int)position.Y, 0);
Vector3 max = 
    new Vector3((int)position.X + texture.Width - 1,
    (int)position.Y + texture.Height - 1, 0);
BoundingBox bb = new BoundingBox(min, max);

最终,让我们看到 sprite 是否完全包含在屏幕。 如果不是,它必须点击边缘。 添加这些行正下方以前添加的:

ContainmentType ct = bbScreen.Contains(bb);
if (ct != ContainmentType.Contains)
    position = new Vector2(100, 100);

现在 sprite 将跳回到 (100,100) 时,它点击屏幕边缘。 当然,应该可能做更智能,像停止或飞行向其他事情。

屏幕的边 colliding 与有点不同 colliding 与另一个对象。 正常情况是您在屏幕中,但您是外部的其他对象。 因此,以检查冲突边到屏幕的要查看屏幕的框是否包含您。 但是,如果要查找与另一对象冲突,您想查看是否与您与相交的对象框。 为此,BoundingBox 对象都有一个 Intersects 成员函数。 与相交返回当两个框相交的 bool。 如果要检查两个 sprite 是否遇到相互,请使用 Intersects。

Bing 感叹号吊臂

您现在离开编写您自己的游戏的一种技术。 您可以绘制图像,将它们移以响应用户输入和行为上运行到对方。 由于这是游戏,您可能需要结束巨大的分解 sprite 冲突。 您已经知道了如何绘制在的分解但不是真正满足除非太 rattle 播放机的扬声器。 幸运的是,播放声音更为比绘制子画面更简单的。

首先,您需要将声音添加到项目。 此过程是类似于添加图像的。 转到解决方案资源管理器右键单击内容,并选择添加 | 现有项。 从这里,您可以选择.wav、.wma、.mp 3 或.xap 文件。 此外,这种在图像文件如果您希望不同的资产名称与该文件名称您可以更改其属性中。

现在让我们来播放该声音。 此代码假设您加载该文件是 explode.wav:

// Add this member variable
SoundEffect sndBoom;

// Add these lines to LoadContent()
ContentManager contentManager = 
    new ContentManager(Services, "Content");
sndBoom = 
    contentManager.Load<SoundEffect>("explode");

// Add these lines to Update()
if (input.Buttons.B == ButtonState.Pressed)
    sndBoom.Play();

contentManager.load 调用是类似于用于加载子画面的纹理的功能。 然后,正如您看到,您希望该的声音只播放。 请注意,编写,此代码将尝试播放新的声音每个帧按下 B 按钮时。 根据声音的长度,这会导致过多份播放它,游戏引发异常。 您应该通过一次播放按钮按每防止出现的。 若要执行此操作,经典方法是存储输入的以前的状态和操作仅当状态更改。

高级绘图

您现在已获得您需要构建您自己的游戏的基本工具。 我建议您需要一些时间播放使用这些工具,并获取熟悉它们。 当您准备的更多时,您可以阅读此部分简要介绍高级的想法。 为这些函数的帮助文档将提供所有需要了解使用它们。

首先,让我们谈论 Z 顺序。 为代码当前代表,如果两个 sprite 重叠的绘制的上一次将最终在最前面。 这种获得认可。 更好方法是为每个 sprite 提供一个指出在其中它应绘制的顺序的变量。 为此,您需要使用更复杂的版本 spriteBatch.begin 和 spriteBatch.Draw,像下面这样:

spriteBatch.Begin(
    SpriteBlendMode.AlphaBlend, 
    SpriteSortMode.BackToFront, 
    SaveStateMode.None);
spriteBatch.Draw(texture, position, 
    null, Color.White, 0, Vector2.Zero, 
    1.0F, SpriteEffects.None, zOrder);

花费一些时间 SpriteBatch 文档,并尝试。 这些函数是有点复杂,但它们也非常强大。 对于是实例如果要更改您的子画面的大小,可以使用而不是向量矩形的位置。 不同纹理的大小的矩形界限是否 XNA 游戏 Studio 将缩放其为您自动。 如果您的纹理具有多个图像要之间循环,可以传递一个源矩形,它指定绘制纹理的哪一部分。

如果希望半透明子画面,更改将传递给绘制该颜色的 alpha 值:

Color trans = new Color(
    Color.White.R, Color.White.G, 
    Color.White.B, 128);

通过 trans 而不是 color.white,绘制和 sprite 会半半透明效果。

最后,下面是可用于旋转为横向模式从纵向屏幕一些便利代码:

// Add this member variable
Matrix matTransform;

// Add these lines to the constructor
matTransform = Matrix.Identity;
matTransform *= 
    Matrix.CreateRotationZ(MathHelper.ToRadians(90));
matTransform *= 
    Matrix.CreateTranslation(240, 0, 0);

// In Draw() change spriteBatch.Begin to this
spriteBatch.Begin(SpriteBlendMode.AlphaBlend, 
    SpriteSortMode.BackToFront, SaveStateMode.None, 
    matTransform);

其余由上到您

完整代码示例将显示在 图 4 中,,并它应获取您移动。 如果您运行 aground,则 Creators.xna.com Web 站点已满的示例,显示如何执行每像素边界框到物理学模型的各种神秘的游戏开发内容,。

图 4 A 简单 Zune 游戏

public class Game1 : Microsoft.Xna.Framework.Game {
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    Matrix matTransform;
    Texture2D texture;
    SoundEffect sndBoom;
    BoundingBox bbScreen;
    Vector2 position;

    public Game1() {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
        position = new Vector2(100, 100);
        matTransform = Matrix.Identity;
        // Uncomment these lines to do Landscape Mode
        //matTransform *= Matrix.CreateRotationZ(          MathHelper. ToRadians(90));
        //matTransform *= Matrix.CreateTranslation(240, 0, 0);
    }

    protected override void Initialize() {
        Vector3 min = new Vector3(0, 0, 0);
        Vector3 max = 
            new Vector3(
            graphics.GraphicsDevice.Viewport.Width, 
            graphics.GraphicsDevice.Viewport.Height, 0);
        bbScreen = new BoundingBox(min, max);
        base.Initialize();
    }

    protected override void LoadContent() {
        spriteBatch = new SpriteBatch(GraphicsDevice);
        texture = Content.Load<Texture2D>("player");
        ContentManager contentManager = 
            new ContentManager(Services, @"Content\Audio");
        sndBoom = contentManager.Load<SoundEffect>("explode");
    }

    protected override void UnloadContent() {
    }

    protected override void Update(GameTime gameTime) {
        GamePadState input = GamePad.GetState(PlayerIndex.One);
        if (input.Buttons.Back == ButtonState.Pressed)
            this.Exit();

        if (input.Buttons.B == ButtonState.Pressed)
            sndBoom.Play();

        const int c_speedScalar = 100;
        Vector2 speed = Vector2.Zero;

        speed.X = input.ThumbSticks.Left.X * c_speedScalar;
        speed.Y = input.ThumbSticks.Left.Y * c_speedScalar * -1;

        if (input.DPad.Left == ButtonState.Pressed)
            speed.X -= c_speedScalar;
        else if (input.DPad.Right == ButtonState.Pressed)
            speed.X += c_speedScalar;

        if (input.DPad.Up == ButtonState.Pressed)
            speed.Y -= c_speedScalar;
        else if (input.DPad.Down == ButtonState.Pressed)
            speed.Y += c_speedScalar;

        position += speed * (float)gameTime.ElapsedGameTime.TotalSeconds;

        Vector3 min = new Vector3((int)position.X, (int)position.Y, 0);
        Vector3 max = new Vector3((int)position.X + 
            texture.Width - 1, (int)position.Y + texture.Height - 1, 0);
        BoundingBox bb = new BoundingBox(min, max);

        ContainmentType ct = bbScreen.Contains(bb);
        if (ct != ContainmentType.Contains)
            position = new Vector2(100, 100);

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime) {
        GraphicsDevice.Clear(Color.CornflowerBlue);
        spriteBatch.Begin(SpriteBlendMode.AlphaBlend, 
            SpriteSortMode.BackToFront, SaveStateMode.None, matTransform);
        spriteBatch.Draw(texture, position, null, Color.White, 
            0, Vector2.Zero, 1.0F, SpriteEffects.None, 0.5F);
        spriteBatch.End();

        base.Draw(gameTime);
    }
}

我希望您在 C# 为尽可能中找到了 XNA 游戏开发有趣与我。也许您编写的内容将成为在游戏中的大接下来...如果我的儿子不更改它。快乐的编码。

将您的问题和提出的意见发送至goplaces@Microsoft.com.

Mike Calligaro 是 Windows Mobile 团队博客可以看到在一个高级开发导致与 Windows Mobile 团队在 Microsoft 和参与者blogs.msdn.com/windowsmobile.