绘制选项屏幕
下一个要讲述的用户接口组件是选项屏幕。依赖于游戏的复杂性,它可能由多个选项屏幕组成,通过一个主选项屏幕来访问。在这里玩家可以设定他偏爱的游戏方式或者退出游戏。选项屏幕的需求决定了在屏幕上应用的控件(controls)的复杂性,从从头到尾应用简单的按钮,到使用类似于MFC的对话框。
为选项屏幕建立砖块
为我们的最初的选项屏幕,我们使用一个按钮风格的接口。为了支持这个,我们定义一个小类ImageButton,它保存我们的按钮数据。
为了按钮增加一点炫的效果,我们定义他有三个可能的状态:Off,Hover和On。Off状态有一个基本的图片。Hover状态显示高亮,一旦鼠标指针在按钮上就触发这个状态。这就提示了玩家鼠标点在了按钮上。On状态可以用于能触发开和关的条目(例如一个用于被选择的选择框)(The On state can be used for items that they can toggle on and off(e.g., an image with a checked check box))。我们还需要指定按钮要显示在屏幕的什么地方和按钮被选择时需要调用的方法。
列表2-9中类ImageButton的声明考虑了这些需求。
列表2.9:ImageButton的声明
public delegate void ButtonFunction( ); public class ImageButton : IDisposable { private int m_X = 0 private int m_Y = 0; private Image m_OffImage = null; private Image m_OnImage = null; private Image m_HoverImage = null; private bool m_bOn = false; private bool m_bHoverOn = false; private ButtonFunction m_Function = null; private Rectangle m_Rect; private VertexBuffer m_vb = null; private CustomVertex.TransformedTextured[] data; |
类中的矩行值保存了按钮的尺寸。我们假设了按钮的三个图片的尺寸相同。如果我们错误的以不同尺寸的图片初始了类,就会出现只绘制部分图片的错误,因为我们试图绘制一个比图片大的矩形。
注意:我建议你先制作Off状态按钮的图片,然后以这个图片为基础来创建其他两个状态的图片。
ImageButton类的构造函数比目前我们处理过的其他类都要棘手一点。构造函数需要六个参数:在屏幕上定位的X和Y值,三个图片的文件名,以及当按钮被选择需要调用的函数。代码应该和类SplashScreen类似,我们也创建一个顶点缓冲,其中的数据用来绘制有纹理的矩形按钮(参见列表2-10)。
列表2.10:ImageButton的构造函数
public ImageButton(int nX, int nY, string sOffFilename, string sOnFilename , string sHoverFilename, ButtonFunction pFunc ) { m_X = nX; m_Y = nY; m_OffImage = new Image( sOffFilename ); m_OnImage = new Image( sOnFilename ); m_HoverImage = new Image( sHoverFilename ); m_Rect = m_OffImage.GetRect(); m_Rect.X += m_X; m_Rect.Y += m_Y; m_Function = pFunc; m_vb = new VertexBuffer( typeof(CustomVertex.TransformedTextured), 4, CGameEngine.Device3D, Usage.WriteOnly, CustomVertex.TransformedTextured.Format, Pool.Default ); } |
Render和Dispose方法见列表2-11。Splash和option屏幕的Render方法非常相似。区别之处在设置顶点缓冲的坐标。不是填充屏幕,组成按钮的两个三角形是填充按钮的矩形。Dispose方法简单的为按钮的每个图片调用Dispose方法。
列表2.11:ImageButton的Render和Dispose方法
public void Render() { try { data = new CustomVertex.TransformedTextured[4]; data[0].X = (float)m_Rect.X; data[0].Y = (float)m_Rect.Y; data[0].Tu = data[0].Tv = data[1].X = (float)(m_Rect.X+m_Rect.Width); data[1].Y = (float)m_Rect.Y; data[1].Z = data[1].Tu = data[1].Tv = data[2].X = (float)m_Rect.X; data[2].Y = (float)(m_Rect.Y+m_Rect.Height); data[2].Z = data[2].Tu = data[2].Tv = data[3].X = (float)(m_Rect.X+m_Rect.Width); data[3].Y = (float)(m_Rect.Y+m_Rect.Height); data[3].Z = data[3].Tu = data[3].Tv =
m_vb.SetData(data, 0, 0);
CGameEngine.Device3D.SetStreamSource( 0, m_vb, 0 ); CGameEngine.Device3D.VertexFormat = CustomVertex.TransformedTextured.Format;
// Set the texture. CGameEngine.Device3D.SetTexture(0, GetTexture() );
// Render the face. CGameEngine.Device3D.DrawPrimitives( PrimitiveType.TriangleStrip, 0, 2 ); } catch (DirectXException d3de) { Console.AddLine( "Unable to display imagebutton " ); Console.AddLine( d3de.ErrorString ); } catch ( Exception e ) { Console.AddLine( "Unable to display imagebutton " ); Console.AddLine( e.Message ); } public void Dispose() { m_OffImage.Dispose(); m_OnImage.Dispose(); m_HoverImage.Dispose(); } |