尝试XNA

  前面说到Windows Phone 7支持Xna开发,这次想来尝试一下,体验Xna开发的过程。我们做一个简单的Sample,在屏幕的最中间以Segoe UI的16号粗体字显示一行闪烁的字,字的颜色在黑色,红色,蓝色,黄色之间循环变换,如下图:

      
  1.Xna没有内置字体
  前面我们提到了Silverlight的字体,也许你觉得Xna开发和Silverlight一样设置文字显示字体就可以了,但是事实没这么简单。因为Silverlight使用的事基于矢量的TrueType字体,但是Xna中压根就没有这样的概念,因为在xna中一切都是图形,包括字体。如果你想在Xna程序中使用字体,就必须把某个字体的所有字符图形嵌入到程序中。幸运的是使用Xna Game Studio可以轻松完成以上工作(需要考虑版权问题哦,- -)。微软当然考虑到了这点,为了方便开发,内置了如下几种字体:(这里说的内置指嵌入对应字体的字符图形)

  Kootenay      Pescadero             Miramonte          Pericles                 Segoe UI Mono
  Lindsey         Pescadero Bold      Miramonte Bold       Pericles Light      Segoe UI Mono Bold
如果希望使用其他的字体可能需要购买。
  2.创建Xna程序,添加资源 
  在IDE中创建一个Windows Phone Game程序(需要选择.NET Framework 4)
   
创建完成后可以发现Xna程序结构和Silverlight程序有明显的区别就是多出了一个以Content结尾的工程
   
这个工程包含了游戏中需要用到所有的资源,包括字体,图形,音乐。本次的sample中需要添加一个字体,右键这个工程,选择添加项目,添加一个SpriteFont,默认添加的字体是Segoe UI Mono,字体描述文件中各个Xml节点的意义一目了然,手动修改字体属性:Size:16;Style:Bold

SpriteFont描述文件
<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains an xml description of a font, and will be read by the XNA
Framework Content Pipeline. Follow the comments to customize the appearance
of the font in your game, and to change the characters which are available to draw
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
<Asset Type="Graphics:FontDescription">

<!--
Modify this string to change the font that will be imported.
-->
<FontName>Segoe UI Mono</FontName>

<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>16</Size>

<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>

<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>

<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Bold</Style>

<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<!-- <DefaultCharacter>*</DefaultCharacter> -->

<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#126;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
</XnaContent>

其中CharacterRegions节点描述的是十六进制Unicode字符编码范围,默认从0x32到0x126。
现在我们把目光移到真正的游戏工程中来, 最重要的两个文件IDE已经创建,是Program.cs和Game1.cs,前者是程序的入口,我们不需要太关心,我们的重点是Game1.cs,它定义了整个游戏过程。Game1从Microsoft.Xna.Framework.Game继承而来,默认已经创建好了两个对象:graphics和spriteBatch,在我们的smaple中需要添加一些其他的变量:

Game1.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;

namespace XnaHelloWindowsPhone
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;

string text = "Hello, Windows Phone"; //输出文字
int index = 0; //记录颜色索引
SpriteFont spriteFont; //显示字体
Vector2 textPosition; //显示位置
Color textColor; //显示颜色
Color[] colors; //可选显示颜色

public Game1()
{
graphics
= new GraphicsDeviceManager(this);
Content.RootDirectory
= "Content";

// Frame rate is 30 fps by default for Windows Phone.
TargetElapsedTime = TimeSpan.FromTicks(333333);
}

/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here

base.Initialize();
}

/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);

// TODO: use this.Content to load your game content here
spriteFont = Content.Load<SpriteFont>("Segoe16Bold");
Vector2 textSize
= spriteFont.MeasureString(text);
Viewport viewPort
= this.GraphicsDevice.Viewport;
textColor
= Color.Black;
colors
= new Color[] {Color.Black, Color.Red, Color.Blue, Color.Yellow};

textPosition
= new Vector2((viewPort.Width - textSize.X) / 2, (viewPort.Height - textSize.Y) / 2);
}

/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}

/// <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)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();

// TODO: Add your update logic here
textColor = colors[index % 4];

if (index == int.MaxValue)
{
index
= 0;
}

index
++;

base.Update(gameTime);
}

/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.AliceBlue);

// TODO: Add your drawing code here
spriteBatch.Begin();
spriteBatch.DrawString(spriteFont, text, textPosition, textColor);
spriteBatch.End();

base.Draw(gameTime);
}
}
}

在构造函数的最后一行:TargetElapsedTime = TimeSpan.FromTicks(333333);为游戏周期设置了一个用于游戏刷新的时间周期,默认为每秒30帧刷新画面。当Game1实例化后函数Run就会被调用(可以在Program.cs中看到),然后就会开始初始化游戏,第一步就是调用Initialize函数,函数LoadContent会在稍晚的时候调用,用于加载游戏所需要的资源包括图片,音乐,字体等。在本次的sample中,我会加载字体,计算字体显示位置,以及初始化可选颜色,大家可以看到我使用ViewPort来获取游戏屏幕的大小并通过计算特定字体下文字的大小来计算文字显示的位置。到此,游戏初始化的过程已经完成了,真正的游戏将要开始,程序将要进入游戏周期。由于Windows Phone默认刷新频率为每秒30帧,因此两个重要的函数Update和Draw在一秒中内会被调用30次(如果Update或者Draw函数在1/30秒内没有执行完,怎么办?丢帧?),从函数签名上可以看出,Update用于更新画面,Draw用于重绘画面。在本次的Sample中Update中会设置文本显示颜色,Draw函数中会绘制这段文本,到此第一个Xna Sample完成,编译运行。

 

  3.重要的事项
  
由于我们会加入自己的Update和Draw代码,下面这点对游戏的体验非常重要:避免Update和Draw函数中的代码在堆上进行内存分配。由于.Net垃圾回收机制的原因,如果在Update和Draw进行垃圾回收或者开辟内存会影响游戏的流畅感,导致游戏有停顿的现象,也就是游戏会卡。 在Draw函数一般不会出现这种情况,问题大都潜伏在Update函数中,我们应该避免Update和Draw函数中任何代码对类进行操作比如构建对象,类型转换引起的装箱等,即便如此,问题同样会存在,比如在Update中对两个string变量进行拼接,由于字符串驻留机制,会在堆上开辟一块内存来保存字符串常量,因此对字符串的操作可以使用StringBuilder来代替。

  到此Xna编程体验就结束了,感觉和通常的编程区别挺大的,所有的借口函数已经定义好了,只需要加入自己的逻辑处理,不过我搞不明白卫生么要吧游戏资源另外设定一个Project呢?另外,要考虑游戏的流畅程度,对每行代码的要求很高,要避免影响游戏流畅性的代码。

 

  下一次我们将体验Windows Phone的动态布局和横竖显示模式。

转载于:https://www.cnblogs.com/gyycyy/archive/2010/12/05/1897040.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值