08 图形特效与文字显示

摘要

使用 XNA Framework 设计游戏程序的时候可以利用 SpriteBatch 类别提供的功能显示游戏的内容供用户检视,SpriteBatch 类别提供了丰富的功能协助游戏程序绘制图画和文字,包括对所输出的图画和文字加入特殊的效果,例如放大/缩小、旋转、设定透明度、水平/垂直翻转、以及图层深度等游戏程序常常需要表现的效果。在这一篇文件中,我们将会为大家介绍利用 SpriteBatch 类别为游戏程序加上特殊效果的多种做法。

认识 SpriteBatch 类别

XNA Framework 支持的 SpriteBatch 类别可以协助游戏程序输出 2 维的图片和文字,并提供批次输出的功能,避免频繁地输出游戏的内容造成闪烁的现象。

[提示]

虽然以 XNA 为基础的 3D 游戏输出 3 维的图形内容时不需要依靠 SpriteBatch 类别提供的功能,但是当 3D 游戏需要提供文字的功能选单供用户选择的时候,还是需要使用到 SpriteBatch 类别提供的文字输出功能。

表 1 所示为 SpriteBatch 类别常用的属性

表 1 :SpriteBatch 类别常用的属性
属性名称 说明
GraphicsDevice 取得游戏程序所使用的 GraphicsDevic 类别的对象的属性。

表 2 所示为 SpriteBatch 类别常用的方法:

表 2 :SpriteBatch 类别常用的方法
方法名称 说明
Begin 宣告批次绘图的动作开始。
Draw 绘制 2 维图案。
DrawString 绘制文字。
End 宣告批次绘图的动作结束,将从呼叫 Begin 方法之后绘制的所有内容输出到游戏窗口,并将 GraphicsDevice 的状态还原到呼叫 Begin 方法之前的状态。

SpriteBatch 类别的功能看似简单,但是负责绘制 2 维图案的 Draw 方法有高达7个不同的多载 (Overload) 版本,负责绘制文字的 DrawString 方法也有多达 6 个不同的多载版本,让游戏程序可以经由传入不同数量的参数,控制方法执行的结果,如果再加计列举型态的参数的内容值选择,就可以组合出各种繁复的变化,满足游戏程序就变更游戏程序内容的需求。

SpriteBatch 类别与图形特效支持

SpriteBatch 类别支持绘制 2 维图案的 Draw 方法一共有以下 7 个不同的多载版本:

SpriteBatch.Draw(texture, destinationRectangle, color)

SpriteBatch.Draw(texture, destinationRectangle, sourceRectangle, color)

SpriteBatch.Draw(texture, destinationRectangle, sourceRectangle, color,

rotation, origin, effects, layerDepth)

SpriteBatch.Draw(texture, position, color)

SpriteBatch.Draw(texture, position, sourceRectangle, color)

SpriteBatch.Draw(texture, position, sourceRectangle, color, rotation,

origin, scale, effects, layerDepth)

SpriteBatch.Draw(texture, position, sourceRectangle, color, rotation,

origin, scale, effects, layerDepth)

其需要用到的参数请参考表3的详细说明:

表 3 :SpriteBatch 类别的 Draw 方法需要使用的参数
参数名称 说明
texture 型态为 Texture2D 类别的参数,负责管理欲绘制的 2 维图案。
destinationRectangle 负责描述欲绘制在游戏窗口上的物体的矩形。
color 负责控制欲绘制的图形的色调的参数,传入 Color.White 表示不改变欲显示的物体的色调。
sourceRectangle 指定欲用来取用来源对象的矩形。
scale 图案放大/缩小的倍数。
rotation 旋转角度。
origin 旋转图形时所依据的圆心。
effects 设定成 SpriteEffects.FlipHorizontally 表示要水平翻转图案,设定成 SpriteEffects.FlipVertically 表示要垂直翻转图案。
layerDepth 图层深度。0 代表前景层,1 代表背景层,可以搭配呼叫 SpriteBatch 类别的 Begin 方法传入的 SpriteSortMode 参数控制是否要对欲绘制的内容依 layerDepth 的内容值排序。
position 指定欲绘制的图案的左上角点坐标。

光是靠 SpriteBatch 类别的 Draw 方法的众多参数,就能够创造繁复的游戏效果,例如透过 color 参数设定图案的色调和透明度,透过 rotation 参数指定旋转图案的角度,利用 origin 参数设定图案旋转的圆心坐标,利用 effects 参数水平翻转或垂直翻转图案,利用 scale 参数指定放大/缩小图案的倍数,或是利用 layerDepth 参数设定图案要显示在那一个图层。

要利用 SpriteBatch 类别的 Draw 方法的各个参数创造繁复的游戏效果,首先请启动 Visual Studio 2010 Express for Windows Phone,并建立 [Windows Phone Game(4.0)] 型态的项目,然后将游戏程序欲显示的图案加入到 Content Pipeline 项目,以便让游戏程序加载显示。

要为欲显示的图案加入各种不同的特殊效果,请先于 Game1 类别中宣告以下的变量,负责管理欲显示的图案,以及图案的显示的位置:

 

Texture2D Mario;									//管理欲顯示的圖案的變數
Vector2 MarioPosition;								//存放圖案顯示的位置的變數
然后将Game1类别的建构函式编辑成以下的样子,负责设定游戏窗口的高度和宽度:

public Game1()
{
    graphics = new GraphicsDeviceManager(this);
    Content.RootDirectory = "Content";
    graphics.PreferredBackBufferHeight = 800;				//設定遊戲視窗的高度為800
    graphics.PreferredBackBufferWidth = 480;				//設定遊戲視窗的寬度為480
    TargetElapsedTime = TimeSpan.FromTicks(333333);
}

设定妥游戏窗口的高度和宽度之后请编辑 Game1 类别的 LoadContent 方法,负责加载游戏程序欲使用的资源,编辑好的 LoadContent 方法如下:

protected override void LoadContent()
{
    spriteBatch = new SpriteBatch(GraphicsDevice);
    Mario = Content.Load<Texture2D>("Mario");	  //從Content Pipeline專案載入欲顯示的圖案
MarioPosition = new Vector2(0, 0);            //設定圖案要顯示在遊戲視窗的最左上角
}

最后我们只要在 Game1 类别的 Draw 方法中呼叫 SpriteBatch 的 Draw 方法,传入适当的参数,就可以显示出各种特殊的效果,例如以下的 Draw 方法便会旋转、放大/缩小、水平/垂直翻转、改变图案色调、以及设定图案的透明度:

protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.CornflowerBlue);
    spriteBatch.Begin();			                      	//宣告批次繪圖動作開始

    spriteBatch.Draw(Mario, MarioPosition, Color.White);	//顯示未加上特殊效果的圖案
    spriteBatch.Draw(Mario, new Vector2(MarioPosition.X + Mario.Width*2, MarioPosition.Y 
+ Mario.Height), null, Color.White, MathHelper.ToRadians(180), new Vector2(0, 0), 1, SpriteEffects.None, 0);						//將圖案旋轉180度
    spriteBatch.Draw(Mario, new Vector2(MarioPosition.X + Mario.Width * 2, 0), null, 
Color.White, 0, new Vector2(0, 0), 1, 
SpriteEffects.FlipHorizontally, 0);						//將圖案水平翻轉

    spriteBatch.Draw(Mario, new Vector2(MarioPosition.X , MarioPosition.Y + Mario.Height), 
Color.Red);								//以紅色的色調顯示圖案
spriteBatch.Draw(Mario, new Vector2(MarioPosition.X + Mario.Width, MarioPosition.Y + 
Mario.Height), Color.Blue);					//以藍色的色調顯示圖案
    spriteBatch.Draw(Mario, new Vector2(MarioPosition.X + Mario.Width * 2, MarioPosition.Y 
+ Mario.Height), Color.Green);					//以綠色的色調顯示圖案

    spriteBatch.Draw(Mario, new Vector2(MarioPosition.X, MarioPosition.Y + 
Mario.Height*2), null, Color.White, 0, new Vector2(0, 0), 1, 
SpriteEffects.None, 0);						//以圖案原始大小顯示圖案
    spriteBatch.Draw(Mario, new Vector2(MarioPosition.X + Mario.Width, MarioPosition.Y + 
Mario.Height * 2), null, Color.White, 0, new Vector2(0, 0), 0.5f, SpriteEffects.None, 0);	//以原圖一半的大小顯示圖案
spriteBatch.Draw(Mario, new Vector2(MarioPosition.X + Mario.Width*1.5f, 
MarioPosition.Y + Mario.Height * 2), null, Color.White, 0, new Vector2(0, 0), 2, SpriteEffects.None, 0);						//以原圖兩倍的大小顯示圖案

    spriteBatch.Draw(Mario, new Vector2(MarioPosition.X, MarioPosition.Y + 
Mario.Height*4), null, new Color(255, 255, 255, 255), 0, new Vector2(0, 0), 1, SpriteEffects.None, 0);						    //以原始透明度顯示圖案
spriteBatch.Draw(Mario, new Vector2(MarioPosition.X + Mario.Width, MarioPosition.Y + 
Mario.Height * 4), null, new Color(255, 255, 255, 170), 0, new Vector2(0, 0), 1, SpriteEffects.None, 0);						 //以約2/3的透明度顯示圖案
spriteBatch.Draw(Mario, new Vector2(MarioPosition.X + Mario.Width*2, MarioPosition.Y 
+ Mario.Height * 4), null, new Color(255, 255, 255, 85), 0, new Vector2(0, 0), 1, SpriteEffects.None, 0);					//以約1/3的透明度顯示圖案

    spriteBatch.End();								    //宣告批次繪圖動作結束
base.Draw(gameTime);
}

做好之后请执行项目,您就会看到如图1的画面,看到传入不同的参数内容给 SpriteBatch 类别的 Draw 方法显示的内容的结果:

图1:传入不同的参数内容控制SpriteBatch类别的Draw方法显示的内容的结果

注:本文所使用的人物图案来源来自:http://www.emutalk.net/showthread.php?t=43273

[说明]

呼叫 SpriteBatch 类别的 Draw 方法执行旋转图案的时候而要传入的旋转角度的单位是弪度量,而不是惯用的度度量。以 XNA 为基础的游戏程序可以利用 MathHelper 类别的 ToRadians 方法指定的度度量角度转换成弪度量,再交给 SpriteBatch 类别的 Draw 方法执行旋转图案的动作。

MathHelper 类别是 XNA Framework 中提供高效能数学运算功能的类别,负责提供游戏执行时需要的数学运算。有关 MathHelper 类别常用的属性可以参考表 4 的说明:

表 4 :MathHelper 类别常用的属性
属性名称 说明
E 代表数学上的指数常数 e (亦称欧拉数 – Euler's Number )。
Log10E 代表以 10 为基底的对数 e 。
Log2E 代表以 2 为基底的对数 e 。
Pi 代表圆周率(pi)。
PiOver2 代表/2。
PiOver4 代表/4。
TwoPi 代表2。

MathHelper 类别常用的方法请参考表 5 的说明:

表 5:MathHelper 类别常用的方法
方法名称 说明
Clamp 限制数值必须介于指定的数值范围。
Distance 计算两个数值之间的距离。
Hermite 执行 Hermite Spline 内插法。
Lerp 于两点之间执行线性内插。
Max 取得两个数值中较大者的内容值。
Min 取得两个数值中较小者的内容值。
SmoothStep 利用 cubic 方程式计算两个数值间的内插值。
ToDegrees 将弪度量转换成度度量。
ToRadians 将度度量转换成弪度量。
WrapAngle 限制角度必须介于π和-π之间。

[提示]

您只要善用 Game1 类别的 Update 方法,动态更新传递给 SpriteBatch 类别的 Draw 方法的参数内容值,就可以很容易地令所开发的游戏程序动态旋转图案、动态放大/缩小图案、或是动态令图案逐渐变成透明/不透明。

SpriteBatch 类别与文字输出支持

SpriteBatch 类别除了能够执行显示图案的功能以下,还能够协助游戏程序显示文字,当游戏程序需要显示菜单供用户选择,或是需要显示游戏的状态(包括分数和游戏的关卡)时,就会需要使用到 SpriteBatch 类别支持显示文字的功能。

游戏程序可以利用 SpriteBatch 类别的 DrawString 方法执行显示文字的动作,和 Draw 方法支持多种多载版本一样,SpriteBatch 类别支持的 DrawString 方法一共有以下 6 个不同的多载版本:

SpriteBatch.DrawString(spriteFont, text, position, color)

SpriteBatch.DrawString(spriteFont, text, position, color, rotation, origin, scale,

effects, layerDepth)

SpriteBatch.DrawString(spriteFont, text, position, color, rotation, origin,

scale, effects, layerDepth)

SpriteBatch.DrawString(spriteFont, text, position, color)

SpriteBatch.DrawString(spriteFont, text, position, color, rotation, origin,

scale, effects, layerDepth)

SpriteBatch.DrawString(spriteFont, text, position, color, rotation, origin,

scale, effects, layerDepth)

其需要用到的参数请参考表6的详细说明:

表 4 :SpriteBatch 类别的 DrawString 方法需要使用的参数
参数名称 说明
spriteFont 型态为 SpriteFont 类别的参数,负责记录欲输出的文字的定义。
text 欲输出的文字,其型态可以是 String 类别或 StringBuilder 类别。
position 指定欲输出的文字的左上角点坐标。
color 负责控制欲输出的文字的色调的参数,传入 Color.White 表示不改变欲显示的文字的色调。
rotation 依据输出的文字的圆心旋转 2 维输出的文字。
origin 旋转文字时所依据的圆心。
scale 文字放大/缩小的倍数。
effects 设定成 SpriteEffects.FlipHorizontally 表示要水平翻转所显示的文字,设定成 SpriteEffects.FlipVertically 表示要垂直翻转所显示的文字。
layerDepth 图层深度。0 代表前景层,1 代表背景层,可以搭配呼叫 SpriteBatch 类别的 Begin 方法传入的 SpriteSortMode 参数控制是否要对欲绘制的内容依 layerDepth 的内容值排序。

[提示]

呼叫 SpriteBatch 类别的 DrawString 方法需要的参数和 Draw 方法需要的参数几乎完全相同,所代表的意义和使用方式也都一样。

了解 SpriteBatch 类别的 DrawString 方法的基本功能之后,接下来我们就要为游戏程序加入显示文字的功能。

要显示文字,请先使用鼠标的右键点中 [Solution Explorer] 窗口中的 Content Pipeline 项目名称,再从出现的菜单选择 [Add | New Item] 功能,屏幕上就会出现如图 2 的画面,要求您选择欲新增的资源项目:

图 2:要求选择欲新增的资源项目的画面

请于中间窗口选择 [Sprite Font] 项目,于 [Name] 字段输入字型定义档案的名称,做好之后按下 [Add] 键,执行新增 SpriteFont 资源到 Content Pipeline 项目的动作,Visual Studio 2010 Express for Windows Phone 就会为 Content Pipeline 项目加入字型定义档案,其内容如下:

 

<?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>14</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>Regular</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> </Start>
        <End>~</End>
      </CharacterRegion>
    </CharacterRegions>
  </Asset>
</XnaContent>

 

您可以利用 <FontName> 卷标指定欲显示的文字所使用的字型,利用 <Size> 卷标指定欲显示的文字的字号,利用 <Style> 卷标设定字型的样式,包括 Bold (粗体)和 Italic (斜体),利用 <CharacterRegion> 卷标指定欲显示的文字范围,包括利用 <Start> 卷标定义欲显示的字符中第一个字符的 Unicode ,利用 <End> 卷标定义欲显示的字符中最后一个字符的 Unicode 。例如以下就是一个 SpriteFont 字型定义文件的范例,指定欲使用大小为 18 的 Courier New 粗体字型,而且开头字符为 a,终止符为 z:

<?xml version="1.0" encoding="utf-8"?>
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
  <Asset Type="Graphics:FontDescription">
    <FontName>Courier New</FontName>
    <Size>18</Size>
    <Spacing>0</Spacing>
    <UseKerning>true</UseKerning>
    <Style>Bold</Style>
    <CharacterRegions>
      <CharacterRegion>
        <Start>a</Start>
        <End>z</End>
      </CharacterRegion>     
  </Asset>
</XnaContent>

[注意]

请注意 SpriteFont 字型定义文件是一个内容大小写视为相异的 XML 文件,编辑字型定义的时候请特别注意大小写不要写错。除此之外,如果游戏程序需要显示汉字字符,因为汉字字符的 Unicode 内容值并不一定会连续,所以我们必须为每一个欲显示的中文字定义一个 <CharacterRegion> 段落,例如以下的字型定义,便会指定游戏程序可以显示 [中文]这两个中文字:

<CharacterRegions>
      <CharacterRegion>
        <Start>中</Start>
        <End>中</End>
      </CharacterRegion>
      <CharacterRegion>
        <Start>文</Start>
        <End>文</End>
      </CharacterRegion>
</CharacterRegions>

定义好游戏程序欲显示的中文字型定义之后,就可以利用 SpriteFont 类别提供的功能管理游戏程序欲显示的字型。SpriteFont 类别常用的属性可以参考表 5 的说明:

表 5:SpriteFont 类别常用的属性
属性名称 说明
Characters 取得 SpriteFont 类别的对象管理的所有字符。
DefaultCharacter 指定默认字符。如果 DefaultCharacter 属性的内容值设定为异于 null 的内容值,则当游戏程序欲显示 SpriteFont 字型定义文件中未定义的字符时,就会自动显示 DefaultCharacter 属性指定的字符。如果 DefaultCharacter 属性的内容值设定为 null,则当游戏程序欲显示 SpriteFont 字型定义文件中未定义的字符时,就会引发例外。

表 6 所示为 SpriteFont 类别常用的方法:

表 6:SpriteFont 类别常用的方法
方法名称 说明
MeasureString 传回 SpriteFont 字型定义文件定义的文字的高度与宽度。当游戏程序欲将文字显示在某个矩形的正中央的时候就需要用到这个方法。

准备好必要的字型定义文件之后,接下来我们就要为游戏程序加入显示文字的功能。

首先请于 Game1 类别加入以下的变量宣告,负责管理欲显示的文字,文字显示的位置,文字旋转的角度,以及旋转的圆心坐标:

SpriteFont GameFont;									//管理欲顯示的文字的變數
Vector2 FontPosition;								//管理文字顯示位置的變數
Vector2 RotateOrigin;						//管理旋轉文字依據的圓心座標的變數
float FontAngle = 0;									//管理文字旋轉角度的變數

然后于 Game1 类别的 LoadContent 方法加入以下的程序代码,负责加载欲显示的文字定义,计算欲显示的文字的大小,位置,以及旋转时的圆心坐标:
Viewport ViewPort = GraphicsDevice.Viewport;					//取得遊戲視窗的大小
GameFont = Content.Load<SpriteFont>("GameFont");	             //載入欲顯示的文字資源
Vector2 FontSize = GameFont.MeasureString("中文");			//計算欲顯示的文字的大小
FontPosition = new Vector2((ViewPort.Width - FontSize.X) / 2, 
(ViewPort.Height - FontSize.Y) / 2);  //設定文字要顯示在遊戲視窗的正中央
RotateOrigin = new Vector2(FontSize.X / 2, FontSize.Y / 2);//設定文字的中心為旋轉的圓心

[注意]

呼叫 Content 对象的 Load 方法加载 Content Pipeline 项目管理的字型资源时所传入的参数名称即扩展名为 .spritefont 的字型定义文件的主文件名,也就是图 2 所示加入字型资源的画面中于 [Name] 字段输入的文件名中的主档名。

加载妥游戏程序欲显示的文字资源之后,请将 Game1 类别的 Update 方法编辑成以下的样子,负责递增文字旋转的角度:

protected override void Update(GameTime gameTime)
{
    // Allows the game to exit
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
        this.Exit();
    if (FontAngle < 360)							//如果旋轉角度尚未到達360度
    {
        FontAngle += 1;									//遞增旋轉角度1度
    }
    // TODO: Add your update logic here
    base.Update(gameTime);
}

最后我们只要在 Game1 类别的 Draw 方法中呼叫 spriteBatch 对象的 End 方法之前加入以下的程序代码,负责显示字型定义文件中指定的中文字,并以文字中心点为圆心旋转所显示的文字
spriteBatch.DrawString(GameFont, "中文", FontPosition+RotateOrigin, Color.White, 
MathHelper.ToRadians(FontAngle), RotateOrigin, 1, SpriteEffects.None, 
0);		//呼叫SpriteBatch類別的DrawString方法顯示並依據指定的角度旋轉文字

做好之后请执行项目,您将会看到游戏程序显示的中文出现在游戏窗口的正中央,并以文字的中心点为圆心进行旋转的情形,如图 3 所示:

图 3:显示并旋转中文字的游戏程序执行的情形

[范例档案下载]

SpriteAndText.zip



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值