65.9K
CodeProject 正在变化。 阅读更多。
Home

从头开始用 XNA 创建 3D 太空入侵者游戏

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (26投票s)

2008年7月6日

CPOL

7分钟阅读

viewsIcon

119792

downloadIcon

6158

一系列文章,旨在利用微软的XNA技术从头开始构建一个3D太空侵略者游戏。

引言

刚开始接触游戏编程?想制作自己的游戏?

这是系列文章中的第一篇,将教你如何使用微软的XNA游戏编程框架,从零开始完全构建一个类似3D太空侵略者的游戏。

背景

大约10年前,游戏编程激起了我十几岁的兴趣。我买了一些关于DirectX和C++编程的书,然后一头扎了进去。不幸的是,我很快就发现,从零编程知识直接进入C++和DirectX游戏编程,就像在学会加减法之前就想理解微积分一样困难。

我感到沮丧,于是学习了其他编程语言,并转向了一些更高级的游戏引擎。我发现了一个名为WildTangent WebDriver的网络游戏引擎,它有一个非常简单的“如何制作游戏”教程。它一步一步地教你使用WebDriver游戏引擎创建一个3D太空侵略者游戏。作为一个编程新手,这正是我所需要的。它帮助了我很多,我最终创建了一个增强版C++教程,彻底理解了它,并成为了该游戏引擎的忠实粉丝。

快进到今天,WildTangent WebDriver游戏引擎已经消失(尽管公司仍然存在),但我对学习游戏编程的热情依然存在。

这一系列文章旨在尝试使用微软的XNA编程框架来重现那个教程。我希望捕捉到原始教程的简洁性,并向你展示如何使用XNA游戏编程框架C#编程语言创建一个3D游戏。

话虽如此,我绝对是游戏编程的新手!我对原生DirectX和XNA的经验很少。今天,我是一名业务软件开发人员,而不是游戏开发人员,所以这也是一次学习经历!我希望这些文章能像我从这次经历中学到的那样,对你有所帮助。(XNA专家们,请告诉我我的代码哪里有问题,请批评并告诉我我哪里做错了。)

另外,这是我的第一篇文章。请在评论中告诉我我的表现如何。

谁应该阅读这篇文章?

对制作3D电脑游戏感兴趣的新手游戏程序员!

为了理解这一系列文章,我建议你具备一些C#编程语言的基础知识,但实际上并没有强制要求。

我们将使用微软的XNA游戏编程框架来制作这个游戏,所以即使是C#的专家也会第一次接触这些东西。

你需要什么

概述

在本系列的第一部分,我们将构建基础——在屏幕上绘制图形,加载模型,并使用键盘进行移动。到本文结束时,你还不能玩《太空侵略者》(但你已经具备了可以使用键盘在关卡中移动的基础)。

在下一篇文章中,我们将在此基础上继续,你将很快开始射击外星人。

准备好了吗?让我们开始吧。

代码概述

在这一系列文章中,我们将使用一个我基于XNA构建的简单游戏引擎,名为Arlandria。我们将在3D太空侵略者游戏中使用它。

你可能会问,什么是游戏引擎?游戏引擎是一个抽象层,是底层代码之上的一个层,使得编写游戏更加容易。所以,与其写

// Without game engine abstraction... :-(
computerPlayer.Mesh[0].Effect.World *= Matrix.CreateTranslation(spawnLocation); 

你将获得这段易于阅读的代码

// With game engine... :-)
computerPlayer.Position = spawnLocation; 

其理念是隐藏一些复杂性,让我们能够专注于制作游戏。好吗?我们将使用Arlandria游戏引擎,这样我们就可以直接写 gun.Shoot()alien.Position = earth。然后,我们将用它来制作我们真正的3D太空侵略者游戏。

Arlandria游戏引擎简述

我们的简单游戏引擎很容易理解。它只有四个对象

  • Scene - 这是我们的世界,我们的舞台。包含游戏中的所有对象。
  • Group - 这是一个包含其他对象的容器。可以把它想象成一个看不见的盒子,你可以把其他东西放进去。
  • Model - Group的一种,包含从文件中加载的3D模型。
  • Camera - 正如你所想:观察我们世界的眼睛,并将美丽的图像显示在你的屏幕上。

我编写这些对象是为了隐藏直接处理XNA游戏编程框架的一些复杂部分。我们不会在本文中深入研究这些对象的代码,但欢迎你随意探索并查看它们是如何工作的,它们包含在源代码中。在未来的文章中,我们将讨论直接处理XNA引擎的更复杂细节,以及诸如移动和旋转之类的变换是如何工作的。

3D太空侵略者代码

我们的首要任务是创建我们将在游戏中使用的东西。今天,我们需要我们的世界,我们称之为scene,并且需要相机来查看世界。

// Keep our scene and our camera around. We'll need them later.
Scene scene;
Camera camera;

/// <summary>
/// Creates a new SpaceInvaders3d object.
/// </summary>
public SpaceInvaders3d()
{
   // Before we can create our scene, we'll need
   // some XNA objects to do some house-keeping.
   GraphicsDeviceManager graphics = new GraphicsDeviceManager(this);
   ContentManager contentManager = new ContentManager(base.Services);
 
   // Now that we have those XNA house-keeping objects,
   // we can create our scene!
   scene = new Scene(graphics, contentManager);
   scene.BackColor = Color.CornflowerBlue;
}


/// <summary>
/// Called by XNA when the game's content (models, audio, textures, etc.)
/// is ready to load.
/// 
/// The purpose is to create our camera.
/// </summary>
/// <param name="loadAllContent">Which type of content to load.</param>
protected override void LoadGraphicsContent(bool loadAllContent)
{
    if (loadAllContent)
    {
        // Create a camera a little ways back from the center of the screen.
        camera = new Camera();
        camera.Position = new Vector3(0, 0, 300);
    }
}

好了,我们的世界就有了!如果你现在停止并运行它,你会看到它完全是玉米花蓝色!而且是空的。

SpaceInvadersEmpty.gif

这并不难。XNA的后台管理功能帮助我们管理内容(模型、纹理等)和图形表面(我们正在绘制的屏幕)。现在不用担心它们,我们只需要创建它们,然后scene将从现在开始负责。

好的,到目前为止,我们有了世界,但它相当无聊——我们只有一个空荡荡的蓝色世界!让我们来解决这个问题。我们将加载一个房间的3D模型,有四个角落,墙上挂着一些精美的抽象艺术品。我使用了一个便宜(30美元)的3D建模工具Milkshape3d创建了这个模型,但你可以使用任何导出为.FBX文件格式的工具来创建模型。

一旦你有了.FBX模型文件,就可以通过XNA Game Studio工具将其添加到你的游戏中。只需右键单击你的游戏项目,选择“添加现有项...”,然后选择你的文件。

SpaceInvadersAddingContent.png

现在,我们的3D模型已经在项目中了,可以通过代码加载它。在创建相机后,添加这两行代码

// Create our room. It's got 4 walls with some fancy abstract art on it.
Model room = new Model("Content\\Models\\room");
scene.Children.Add(room);

轻而易举!现在,我们真的有东西了!

SpaceInvadersLevel.png

太棒了!现在,我们有一些漂亮的东西可以看了。但是,这还不是动作丰富的外星人毁灭战。

让我们让玩家在按下键盘按键时可以移动。第一人称射击游戏的标准操作是使用W、A、S、D键进行移动(W=前进,S=后退,A=左,D=右)。让我们现在就来实现它。

在XNA中,你会在一个名为Update的特殊函数中更新你的游戏状态(例如玩家移动)。它看起来像这样

/// <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)
{
    base.Update(gameTime);
}

在这个特殊函数中,让我们检查用户是否按下了W、A、S或D键,并相应地移动相机。在该函数中,在base.Update(gameTime);行之上,添加ProcessKeyPresses();行。

然后,我们将ProcessKeyPresses函数编写如下

///<summary> 
/// Checks the state of the keyboard and moves the camera as necessary. 
/// </summary> 
private void ProcessKeyPresses()
{
    // Standard first-person shooter keys. 
    const Keys moveLeftKey = Keys.A;
    const Keys moveRightKey = Keys.D;
    const Keys moveForwardKey = Keys.W;
    const Keys moveBackwardKey = Keys.S;
 
    KeyboardState keyState = Keyboard.GetState();
    if (keyState.IsKeyDown(moveForwardKey))
    {
        this.camera.Position += Vector3.Forward;
    }
    else if (keyState.IsKeyDown(moveBackwardKey))
    {
        this.camera.Position += Vector3.Backward;
    }
    else if (keyState.IsKeyDown(moveLeftKey))
    {
        this.camera.Position += Vector3.Left;
    }
    else if (keyState.IsKeyDown(moveRightKey))
    {
        this.camera.Position += Vector3.Right;
    }
}

相当简单的代码:我们在这里所做的只是根据按下的按键调整相机的位置。

最终结果?我们可以用键盘在相机周围移动!哇!这让我们能够近距离欣赏挂在墙上的精美艺术品……

SpaceInvadersMoving.png

好的,现在我们已经可以加载3D模型,并使用W、A、S、D键在我们那充满玉米花的世界里移动相机了。事情正在成型!

在第二部分,我们将讨论如何像第一人称射击游戏那样使用鼠标来移动玩家的视角。我们还将装备精良……并充满危险!敬请期待。

致谢

非常感谢Mark Lamprecht、Brent Orford、Ryan Rogers、Todd Zircher以及所有Genesis3d和WildTangent的成员,他们忍受了我新手般的问题,并帮助我开始了我的编程之旅。特别要感谢Mark,他创建了本系列文章所基于的WildTangent教程游戏。

历史

  • 2008年7月7日 - 初始版本。
© . All rights reserved.