技术开发 频道

XNA Framework Game Studio开发WP游戏

  【IT168技术】在今天的开发领域,能从相同的游戏代码库开发支持多平台运行的游戏很困难,通常,同一游戏项目想要在不同平台上运行时,代码需要重写,这会引起许多头痛的问题,挫折和时间损失。XNA Game Studio正是在这种背景下诞生的,XNA Game Studio是一套来自微软公司的工具,它使游戏开发过程变得更加简单和有趣。XNA Game Studio真正有吸引力的地方在于,它为开发人员提供了一个无缝构建多平台游戏的方法。在这篇文章中,我们将介绍如何使用统一的代码库构建一个简单的XNA Framework游戏,让它可在Windows Phone 7、Xbox和PC上运行。

  开发者需要什么

  如果你还没有这样做过,请先访问http://create.msdn.com/下载Visual Studio 2010和XNA Game Studio 4.0的试用版,然后安装它们。

  我们要构建什么

  我们将要构建一个非常简单的XNA Framework游戏,主要目的是介绍如何将它部署到多个不同的平台,这个游戏说来很简单,就是将一个高尔夫球移动到某个目标位置。在Windows Phone 7上,使用加速计控制高尔夫球,在Xbox上,使用控制器上的游戏杆移动,在PC上,使用键盘上的箭头键移动,但用户将高尔夫球移动到目标位置,游戏就重新开始。怎么样,超级简单吧!

  第1步:构建Windows Phone 7 XNA Framework游戏

  我们先创建一个新的Windows XNA Framework项目,然后再修改为在Windows Phone 7和Xbox上运行的版本。点击“文件”*“新建项目”,在“XNA Framework Game Studio 4.0”下,选择“Windows Phone Game (4.0)”,项目命名为“CrossPlatformXNA FrameworkGame”,如图1所示。

XNA Framework Game Studio开发WP游戏
▲图 1 创建新的Windows Phone游戏项目

  先介绍一点理论的东西

  接下来,我们需要给我们的项目编写代码,首先请允许我简单描述一下XNA Framework是如何工作的,下图展示了XNA Game Studio应用程序的运行流程。

构建WP7 XNA Framework游戏
▲图 2 XNA Game Studio应用程序的运行流程

  代码以进入构造程序开始,然后是初始化变量,加载任何内容到ContentManager,再进入游戏循环,游戏循环将是这里最主要的代码。默认情况下,Windows Phone 7 XNA Framework应用程序以每秒30帧的速度运行,这意味着游戏循环每秒要被调用30次。游戏循环实际上是由两个函数 — Update()和Draw() — 组成的。

  接下来向我们的项目导入一些纹理

  在开始编码之前,让我们先导入一些游戏会使用到的纹理,我已经为高尔夫球和目标创建了纹理,你在你的项目中也可以使用,每个纹理有两个分辨率,因为游戏运行的平台不同,分辨率可能也不同,因此我提供了两个图像,一个是Xbox上的高清晰度分辨率版本,另一个是Windows Phone和PC上的低分辨率版本。

  注:Windows Phone 7和Xbox包括硬件缩放功能,可以根据需要放大或缩小图像。

构建WP7 XNA Framework游戏
▲图 3 高尔夫球和目标对象纹理的高分辨率和低分辨率版本

  将这些图像文件保存到本地计算机,然后转到Visual Studio 2010中的解决方案资源管理器,在CrossPlatformXNA FrameworkGameContent项目上点击右键,选择“添加”*“现有项目”,然后选择你保存在本地计算机上的图像文件。

构建WP7 XNA Framework游戏
▲图 4 添加现有项目(图像文件)

  开始编码

  现在我们粗略地知道了XNA Framework应用程序如何运行,并且创建了一些可用于构建应用程序的纹理,终于可以开始编写程序代码了。

  1、首先将CrossPlatformXNA FrameworkGame项目包含的Game1.cs重命名为“GolfGameMain.cs”;

  2、然后打开GolfGameMain.cs文件,定义下面的变量,它们将用于我们的两个纹理,位置和速度信息:

// Textures
Texture2D ball;
Texture2D target;
// Location information
Vector2 ballPt;
Vector2 targetPt;
// normalized velocity vector
Vector2 ballVelocity;
// Used to multiply on the velocity vector
float velocityMultiplier;

  3、在Initialize()方法内添加下面的代码,设置高尔夫球的速度:

  velocityMultiplier = 13.0f;

  4、自己动手写一个名为ResetGame()的函数,初始化高尔夫球的速度和位置值,函数内容如下,我们指定高尔夫球的初始位置为左上角稍微靠右的位置,目标在右下角稍微靠左的位置,高尔夫球的速度从0开始:

private void ResetGame()
{
    ballVelocity
= Vector2.Zero;
    ballPt
= new Vector2(target.Width, target.Height);
    targetPt
= new Vector2(graphics.GraphicsDevice.Viewport.Width - 2*target.Width, graphics.GraphicsDevice.Viewport.Height - 2*target.Height);
}

  5、向LoadContent()函数添加下面的代码,加载我们导入到内容管理器的纹理,完成后,调用ResetGame()指定对象的位置:

  ball = Content.Load("ball_small");

  target = Content.Load("target_small");

  ResetGame();

  6、现在我们已将内容载入到内容管理器,接下来让我们根据描述的位置绘制加载到屏幕的纹理,修改Draw()函数,修改后内容如下:

protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.White);
            spriteBatch.Begin();
            
// Draw our objects to the screen
            spriteBatch.Draw(target, targetPt, Color.White);
            spriteBatch.Draw(ball, ballPt, Color.White);
            spriteBatch.End();
            base.Draw(gameTime);
        }

  7、至此,我们应该可以运行这个程序,看到高尔夫球和目标绘制到屏幕上,看起来的效果应该和下图差不多:

开始编码
▲图 5 程序运行效果

  8、下一步要为做碰撞检查添加一个函数,当高尔夫球完全包含在目标内时,这个函数开始执行。

private bool CheckForCollision()
{
    Rectangle ballRect
= new Rectangle((int)ballPt.X, (int)ballPt.Y, ball.Width, ball.Height);
    Rectangle targetRect
= new Rectangle((int)targetPt.X, (int)targetPt.Y, target.Width, target.Height);
    return targetRect.Contains(ballRect);
}

  9、有了碰撞检测逻辑后,我们可以给高尔夫球移动到目标的过程也添加上逻辑,将下面的代码添加到Update()函数即可,检测到碰撞后,我们可以通过调用前面创建的函数ResetGame()重置游戏:

KeyboardState kState = Keyboard.GetState(PlayerIndex.One);
Keys[] pressedKeys
= kState.GetPressedKeys();
ballVelocity
= Vector2.Zero;
foreach (Keys k in pressedKeys)
    switch (k)
    {
        
case Keys.Right:
            ballVelocity.X
= velocityMultiplier;
            break;
        
case Keys.Left:
            ballVelocity.X
= -velocityMultiplier;
            break;
        
case Keys.Down:
            ballVelocity.Y
= velocityMultiplier;
            break;
        
case Keys.Up:
            ballVelocity.Y
= -velocityMultiplier;
            break;
    }
ballPt
+= ballVelocity;
if (CheckForCollision())
    ResetGame();

  10、测试一下游戏运行时的状况,现在你应该可以使用键盘上的箭头控制高尔夫球的移动,当高尔夫球移动到目标时,游戏应该被重置。至此,你已经完成了主要的工作,从下一步开始,我们将修改代码,使其支持Windows Phone 7和Xbox平台。

  第2步:修改代码,使其支持Windows Phone 7

  11、为Windows Phone 7创建一个CrossPlatformXNA FrameworkGame项目副本,在项目名称上点击右键,选择“为Windows Phone创建项目副本”,第二个项目应该就这样创建好了,项目名称应该是“Windows Phone 7 copy of CrossPlatformXNA FrameworkGame”。

  12、在“引用”上点击右键,选择“添加引用”,为你的项目添加一个引用,如下图所示,然后选择“Microsoft.Devices.Sensors”,点击“添加”。

修改代码支持Windows Phone 7
▲图 6 添加引用

  13、现在关闭所有打开的文件,选择并打开“Windows Phone 7 copy of Cross PlatformXNA FrameworkGame”项目下的GolfGameMain.cs文件。

  14、在项目顶部添加下面的命名空间,通过宏“#if WINDOWS_PHONE”批量导入命名空间,这样可以告诉编译器忽略“#if…#endif”内的代码,除非它是为Windows Phone 7编译,后面我们会使用“if XBOX… #endif”为Xbox做同样的处理。

// Used for accelerometer data from Windows Phone
#
if WINDOWS_PHONE
using Microsoft.Devices.Sensors;
#endif

  15、添加一个类级变量,增加加速计支持

#if WINDOWS_PHONE
Accelerometer accelerometer;
#endif

  16、在构造器中添加下面的代码,帮助修改设置,处理游戏如何显示,以及游戏运行在什么分辨率下。

#if WINDOWS_PHONE
    
// Hides the battery and signal strength bar
    graphics.IsFullScreen
= true;
#
else
    
// Code to support changing the resolution of the game for the Xbox to handle high def screens
    graphics.IsFullScreen
= false;
    graphics.PreparingDeviceSettings
+= new EventHandler<PreparingDeviceSettingsEventArgs>(graphics_PreparingDeviceSettings);
#endif

  17、修改前面编写的Initialize()函数,初始化加速计,根据平台的不同为高尔夫球设置不同的速度。

#if WINDOWS_PHONE
    
if (accelerometer == null)
    {
        
// Instantiate the accelerometer sensor
        accelerometer
= new Accelerometer();
        accelerometer.ReadingChanged
+= new EventHandler<AccelerometerReadingEventArgs>(accelerometer_ReadingChanged);
        accelerometer.Start();
    }
    velocityMultiplier
= 10.0f;
#elif WINDOWS
    velocityMultiplier
= 13.0f;
#
else
    velocityMultiplier
= 20.0f;
#endif

  18、添加一个函数处理我们在上一步注册的事件,这个函数将处理加速计读数变化,我们基于此设置高尔夫球的速度,这与在Windows版本中处理不同按键事件的代码是等效的。

#if WINDOWS_PHONE
void accelerometer_ReadingChanged(
object sender, AccelerometerReadingEventArgs e)
{
    ballVelocity.X
= -velocityMultiplier*(float)e.Y;
    ballVelocity.Y
= -velocityMultiplier*(float)e.X;
}
#endif

  19、修改LoadContent()函数,使其可以根据平台的不同加载不同的纹理,对Windows Phone和Windows平台,我们将加载低分辨率图像,对于Xbox,我们将加载高分辨率图像。

// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch
= new SpriteBatch(GraphicsDevice);
// Load our game content to the ContentManager
#
if WINDOWS_PHONE || WINDOWS
    ball
= Content.Load<Texture2D>("ball_small");
    target
= Content.Load<Texture2D>("target_small");
#
else
    ball
= Content.Load<Texture2D>("ball");
    target
= Content.Load<Texture2D>("target");
#endif
ResetGame();

  20、修改Update()函数,如果我们是为Windows版本编译的话,我们只能看到键盘输入。

#if WINDOWS
                KeyboardState kState
= Keyboard.GetState(PlayerIndex.One);
                Keys[] pressedKeys
= kState.GetPressedKeys();
                ballVelocity
= Vector2.Zero;
                foreach (Keys k in pressedKeys)
                    switch (k)
                    {
                        
case Keys.Right:
                            ballVelocity.X
= velocityMultiplier;
                            break;
                        
case Keys.Left:
                            ballVelocity.X
= -velocityMultiplier;
                            break;
                        
case Keys.Down:
                            ballVelocity.Y
= velocityMultiplier;
                            break;
                        
case Keys.Up:
                            ballVelocity.Y
= -velocityMultiplier;
                            break;
                    }
#endif

  21、很好,现在在解决方案资源管理器中的“Windows Phone 7 copy of CrossPlatformXNA FrameworkGame”项目上点击右键,运行“调试”*“运行新实例”,这时应该会启动Windows Phone 7模拟器,如下图所示,但遗憾的是,不能在模拟器中测试加速计功能,除非你将应用程序部署到一台真实的Windows Phone 7手机上。

修改代码支持Windows Phone 7
▲图 7 在Windows Phone 7模拟器上运行的效果

  下面我们创建一个Xbox版本

  22、为Xbox创建CrossPlatformXNA FrameworkGame项目的一个副本,在项目名称上点击右键,选择“为Xbox 360创建项目的副本”,第三个项目应该就创建好了,项目名称应该为“Xbox 360 copy of CrossPlatformXNA FrameworkGame”。

  23、最后一次修改构造器,为设置游戏的分辨率添加一个事件处理程序,最终的构造器看起来应该是:

public GolfGame()
{
    graphics
= new GraphicsDeviceManager(this);
    Content.RootDirectory
= "Content";
    
// Frame rate is 30 fps by default for Windows Phone.
    TargetElapsedTime
= TimeSpan.FromTicks(333333);
    #
if WINDOWS_PHONE
        
// Hides the battery and signal strength bar
        graphics.IsFullScreen
= true;
    #
else
        
// Code to support changing the resolution of the game for the Xbox to handle high def screens
        graphics.IsFullScreen
= false;
        graphics.PreparingDeviceSettings
+= new EventHandler<PreparingDeviceSettingsEventArgs>(graphics_PreparingDeviceSettings);
    #endif
}

  24、现在我们必须为我们注册的事件定义函数的定义。

void graphics_PreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
        {
            #
if XBOX
                foreach (Microsoft.Xna.Framework.Graphics.DisplayMode displayMode in GraphicsAdapter.DefaultAdapter.SupportedDisplayModes)
                {
                    
// High def resolution support for Xbox (if available)
                    
if (displayMode.Width == 1920 || displayMode.Width == 1280)
                    {
                        e.GraphicsDeviceInformation.PresentationParameters.BackBufferFormat
= displayMode.Format;
                        e.GraphicsDeviceInformation.PresentationParameters.BackBufferHeight
= displayMode.Height;
                        e.GraphicsDeviceInformation.PresentationParameters.BackBufferWidth
= displayMode.Width;
                    }
                }
            #endif
        }

  25、接下来我们必须修改Update()函数,添加Xbox控制器支持,这个函数的最终版本代码如下:

protected override void Update(GameTime gameTime)
        {
            
// Allows the game to exit
            
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            Vector2 velocity
= Vector2.Zero;
            #
if WINDOWS
                KeyboardState kState
= Keyboard.GetState(PlayerIndex.One);
                Keys[] pressedKeys
= kState.GetPressedKeys();
                ballVelocity
= Vector2.Zero;
                foreach (Keys k in pressedKeys)
                    switch (k)
                    {
                        
case Keys.Right:
                            ballVelocity.X
= velocityMultiplier;
                            break;
                        
case Keys.Left:
                            ballVelocity.X
= -velocityMultiplier;
                            break;
                        
case Keys.Down:
                            ballVelocity.Y
= velocityMultiplier;
                            break;
                        
case Keys.Up:
                            ballVelocity.Y
= -velocityMultiplier;
                            break;
                    }
            #elif XBOX
                    ballVelocity.X
= velocityMultiplier * GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.X;
                    ballVelocity.Y
= -velocityMultiplier * GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.Y;    
            #endif
                ballPt
+= ballVelocity;
            
if (CheckForCollision())
                ResetGame();
            base.Update(gameTime);
        }

  26、就这样,我们编写了一个可以运行在三个平台上的应用程序,是不是很简单呢?

0
相关文章