现在的位置: 首页 > 综合 > 正文

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十二)制作精美的Mini地图②

2012年12月24日 ⁄ 综合 ⁄ 共 3739字 ⁄ 字号 评论关闭

前面章节中讲解的包括对象头像面板、Mini雷达地图等窗体都是位置固定的,在处理起来方式多样且简单;而RPGSLG、休闲养成等类型的游戏中往往会大量使用到悬浮且可自由拖动的窗体,比如包裹面板、武器装备面板、个人属性面板、技能面板、系统设置面板等等,这就要求我们必须为游戏量身定做一个通用且易用的ChildWindow控件。那么本节我将为大家讲解如何制作一个包含可拖动头部、关闭按钮及内容主体3大部件高自由度的自定义ChildWindow控件,并用它来实现Mini寻路地图。

首先,我们需要确定该ChildWindow的功能需求,从布局上说包含上述3大部分,且这3部分都是可以用任意对象来实现的,这样才能实现高度拓展;从功能上说,ChildWindow可在游戏窗口中任意拖动,且多个ChildWindow实例之间同样存在一个可协调的层次关系,这方面内容大家可以参考我关于ChildWindow另一篇文章;从整体结构上说,ChildWindow即可以与游戏中与对象轻松交互,同时也不能影响到游戏中其它对象的活动。

那么接下来进入实质性设计阶段,此时我们有3条路可以选择:

1)通过底层的继承来实现。例如新建一个BaseWindow.cs类文件,然后让之继承ControlContentControlUserControl等均可,并通过代码添加并布局好各部分控件,同时实现各部分应有的功能事件,最后让this.Content=总的布局控件或其它方式来完成基类的定义。那么其他的控件就可以通过继承此BaseWindow,在拥有所有BaseWindow功能的基础上再拓展出各自控件自身的特定功能。总的来说这是传统的方案,但是在WPF/Silverlight中易用性不强,因为有着xaml这一层东西在;且目前大多数的开发者都不一定具备底层控件开发的技术与经验,实现起来难度较大。

2)通过Silverlight模板控件来实现。国外很多Silverlight开发者都比较喜欢使用此方式进行控件开发。具体步骤:在项目上右键->添加->新建项->Silverlight模板化控件:

新建好后,大家可以看到的项目结构中出现了一个Themes文件夹,且里面包含着一个名为Generic.xaml的模板文件,主体代码如下:

    <Style TargetType="local:QXChildWindow">

        <Setter Property="Template">

            <Setter.Value>

                <ControlTemplate TargetType="local:QXChildWindow">

                    ……模板内容……

                </ControlTemplate>

            </Setter.Value>

        </Setter>

    </Style>

以后如果还有新的模板添加进项目,那么所有模板的xaml部分均会以如上格式追加到此文件中,只是它们绑定的TargetType不同(cs文件不同)罢了:

当我们打开QXChildWindow.cs文件可以看到,此QXChildWindow模板控件继承自Control,且通过this.DefaultStyleKey = typeof(QXChildWindow);这句话来实现与Generic.xaml中的模板界面对接。既然是非partial文件,因此其拓展起来还是很方便的。我也曾尝试使用此方法来实现ChildWindow,功能是有了,但过程很是别扭,例如模板中对中文的支持不好;重载OnApplyTemplate()方法中的base.OnApplyTemplate()在控件加载中并不灵活等等,个人感觉从拓展度及开发难度上说效果并非最理想。

3)通过用户控件来实现。Silverlight中的用户控件大家应该再熟悉不过了,此时肯定会有朋友质疑它是否真的如此万能?连ChildWindow也可以实现吗?其实用户控件本身继承自UserControl,既然是面向对象的,又为何不能呢?下面是我写的QXChildWindow界面部分代码:

<UserControl x:Class="QXGameEngine.Control.QXChildWindow"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" MouseLeftButtonDown="UserControl_MouseLeftButtonDown">

    <Canvas>

        <Canvas x:Name="Head" MouseLeftButtonUp="Head_MouseLeftButtonUp" MouseMove="Head_MouseMove">

            <ContentPresenter x:Name="HeadPresenter" />

            <Rectangle x:Name="CloseButton">

                <ToolTipService.ToolTip>

                    <TextBlock x:Name="Tip" Text="关闭" />

                </ToolTipService.ToolTip>

            </Rectangle>

        </Canvas>

        <Canvas x:Name="Body">

            <ContentPresenter x:Name="BodyPresenter" />

        </Canvas>

    </Canvas>

</UserControl>

整个xaml就是如此简单,但是却蕴涵着高度的灵活性,此话怎讲?不妨先看下面这张结构描述图:

以头部Head为例,它是Canvas类型,因此我们可以将它的Background设置为任意Brush对象,如渐变颜色、图片、乃至视频;并且它内部还包含着一个名为HeadPresenter ContentPresenter,这又是何方神圣?我们可以在后台代码中通过HeadPresenter=object来实现对其完全的重新定义,这意味着HeadPresenter可以是任何东西,比如矩形啦、图片啦、画布啦、甚至新的用户控件,甚至再来个QXChildWindow实例,嘿嘿(当然,这么做是没意义的)。且由于HeadPresenterCanvas画布中,因此对它的布局也是完全自由的。Body部分则是同样的道理,不累述了。接下来定义好对这些对象进行赋值的CLR属性,并通过路由的MouseLeftButtonDownMouseLeftButtonUpMouseMove事件分别实现ChildWindow应该有的功能,最终就完成了这个QXChildWindow控件的制作

如果您到此还不能完全感受到它的强大与灵活?那么接下来我将使用该控件实例出一个mini寻路地图,让大家近距离接触这个牛气烘烘的新家伙。

创建过程是很简单的,只需为游戏窗体注册一个键盘敲下事件,通过设置激发的按钮或按钮组合来显示窗口:

       //键盘按下事件

        private void UserControl_KeyDown(object sender, KeyEventArgs e) {

            //显示寻路地图(组合按住Ctrl+Tab)

            if (e.Key == Key.Tab) {

                if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control) {

                      ……

                }

            }

         }

这里我用的是Ctrl+Tab键,目前Silverlight3.0版本中键盘处理还不算完善,4.0中将实现所有的键位。接下来我们通过赋予一个QXChildWindow实例相应的参数,如头部宽、高、背景图片,身体宽、高、背景图片等等,并将之添加进Root中。到此,一个Mini地图寻路面板就完成了:

//初始化寻路地图

wayfindingWindow = new QXChildWindow() {

   Left = 105,

   Top = 40,

   HeadLeft = 0,

   HeadTop = 0,

   HeadWidth = 604,

   HeadHeight = 37,

   HeadBackground = new ImageBrush() { ImageSource = Super.GetImage("/Image/Plate/WayfindingMapHead.png") },

   BodyLeft = 0,

   BodyTop = 37,

抱歉!评论已关闭.